diff options
-rw-r--r-- | doc/ScintillaDoc.html | 270 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 7 | ||||
-rw-r--r-- | include/Scintilla.h | 15 | ||||
-rw-r--r-- | include/Scintilla.iface | 21 | ||||
-rw-r--r-- | src/EditView.cxx | 238 | ||||
-rw-r--r-- | src/Editor.cxx | 60 | ||||
-rw-r--r-- | src/ViewStyle.cxx | 42 | ||||
-rw-r--r-- | src/ViewStyle.h | 21 |
8 files changed, 464 insertions, 210 deletions
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 41cac0d2b..7e120c44c 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -51,7 +51,9 @@ table.standard td { padding: 1px 5px 1px 5px; } - + tr.section { + border-top:1px solid #808080; + } .S0 { color: #808080; } @@ -99,6 +101,12 @@ .deprecated { text-decoration: line-through red; } + A.discouraged { + text-decoration: line-through #FFB000; + } + .discouraged { + text-decoration: line-through #FFB000; + } .parameter { font-style:italic; } @@ -364,7 +372,7 @@ </tr> <tr> - <td>○ <a class="toc" href="#CaretAndSelectionStyles">Caret, selection, and hotspot styles</a></td> + <td>○ <a class="toc" href="#CaretAndSelectionStyles">Selection, caret, and hotspot styles</a></td> <td>○ <a class="toc" href="#CharacterRepresentations">Character representations</a></td> @@ -1713,12 +1721,15 @@ struct Sci_TextToFind { <a class="message" href="#SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE">SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE → position</a><br /> <br /> - <a class="message" href="#SCI_SETADDITIONALSELALPHA">SCI_SETADDITIONALSELALPHA(alpha alpha)</a><br /> - <a class="message" href="#SCI_GETADDITIONALSELALPHA">SCI_GETADDITIONALSELALPHA → int</a><br /> - <a class="message" href="#SCI_SETADDITIONALSELFORE">SCI_SETADDITIONALSELFORE(colour fore)</a><br /> - <a class="message" href="#SCI_SETADDITIONALSELBACK">SCI_SETADDITIONALSELBACK(colour back)</a><br /> - <a class="message" href="#SCI_SETADDITIONALCARETFORE">SCI_SETADDITIONALCARETFORE(colour fore)</a><br /> - <a class="message" href="#SCI_GETADDITIONALCARETFORE">SCI_GETADDITIONALCARETFORE → colour</a><br /> + <a class="element" href="#SC_ELEMENT_SELECTION_ADDITIONAL_TEXT">SC_ELEMENT_SELECTION_ADDITIONAL_TEXT : colouralpha</a><br /> + <a class="element" href="#SC_ELEMENT_SELECTION_ADDITIONAL_BACK">SC_ELEMENT_SELECTION_ADDITIONAL_BACK : colouralpha</a><br /> + <a class="discouraged message" href="#SCI_SETADDITIONALSELALPHA">SCI_SETADDITIONALSELALPHA(alpha alpha)</a><br /> + <a class="discouraged message" href="#SCI_GETADDITIONALSELALPHA">SCI_GETADDITIONALSELALPHA → int</a><br /> + <a class="discouraged message" href="#SCI_SETADDITIONALSELFORE">SCI_SETADDITIONALSELFORE(colour fore)</a><br /> + <a class="discouraged message" href="#SCI_SETADDITIONALSELBACK">SCI_SETADDITIONALSELBACK(colour back)</a><br /> + <a class="element" href="#SC_ELEMENT_CARET_ADDITIONAL">SC_ELEMENT_CARET_ADDITIONAL : colouralpha</a><br /> + <a class="discouraged message" href="#SCI_SETADDITIONALCARETFORE">SCI_SETADDITIONALCARETFORE(colour fore)</a><br /> + <a class="discouraged message" href="#SCI_GETADDITIONALCARETFORE">SCI_GETADDITIONALCARETFORE → colour</a><br /> <a class="message" href="#SCI_SETADDITIONALCARETSBLINK">SCI_SETADDITIONALCARETSBLINK(bool additionalCaretsBlink)</a><br /> <a class="message" href="#SCI_GETADDITIONALCARETSBLINK">SCI_GETADDITIONALCARETSBLINK → bool</a><br /> <a class="message" href="#SCI_SETADDITIONALCARETSVISIBLE">SCI_SETADDITIONALCARETSVISIBLE(bool additionalCaretsVisible)</a><br /> @@ -1871,15 +1882,22 @@ struct Sci_TextToFind { After setting the rectangular selection, this is broken down into multiple selections, one for each line.</p> <p> + <b id="SC_ELEMENT_SELECTION_ADDITIONAL_TEXT">SC_ELEMENT_SELECTION_ADDITIONAL_TEXT : colouralpha</b><br /> + <b id="SC_ELEMENT_SELECTION_ADDITIONAL_BACK">SC_ELEMENT_SELECTION_ADDITIONAL_BACK : colouralpha</b><br /> <b id="SCI_SETADDITIONALSELALPHA">SCI_SETADDITIONALSELALPHA(<a class="jump" href="#alpha">alpha</a> alpha)</b><br /> <b id="SCI_GETADDITIONALSELALPHA">SCI_GETADDITIONALSELALPHA → int</b><br /> <b id="SCI_SETADDITIONALSELFORE">SCI_SETADDITIONALSELFORE(<a class="jump" href="#colour">colour</a> fore)</b><br /> <b id="SCI_SETADDITIONALSELBACK">SCI_SETADDITIONALSELBACK(<a class="jump" href="#colour">colour</a> back)</b><br /> Modify the appearance of additional selections so that they can be differentiated from the main selection which has its appearance set with + <a class="element" href="#SC_ELEMENT_SELECTION_TEXT"><code>SC_ELEMENT_SELECTION_TEXT</code></a>, + <a class="element" href="#SC_ELEMENT_SELECTION_BACK"><code>SC_ELEMENT_SELECTION_BACK</code></a>, <a class="message" href="#SCI_SETSELALPHA"><code>SCI_SETSELALPHA</code></a>, <a class="message" href="#SCI_GETSELALPHA"><code>SCI_GETSELALPHA</code></a>, <a class="message" href="#SCI_SETSELFORE"><code>SCI_SETSELFORE</code></a>, and <a class="message" href="#SCI_SETSELBACK"><code>SCI_SETSELBACK</code></a>. + The element APIs are preferred and the following messages discouraged. + The additional selection background is drawn on the layer defined for all selection backgrounds by + <a class="message" href="#SCI_SETSELECTIONLAYER"><code>SCI_SETSELECTIONLAYER</code></a>. <code>SCI_SETADDITIONALSELFORE</code> and <code>SCI_SETADDITIONALSELBACK</code> calls have no effect until <a class="message" href="#SCI_SETSELFORE"><code>SCI_SETSELFORE</code></a> @@ -1888,12 +1906,15 @@ struct Sci_TextToFind { <a class="message" href="#SCI_SETSELFORE"><code>SCI_SETSELFORE</code></a>, and <a class="message" href="#SCI_SETSELBACK"><code>SCI_SETSELBACK</code></a> will overwrite the values set by <code>SCI_SETADDITIONALSEL*</code> functions.</p> + <p> + <b id="SC_ELEMENT_CARET_ADDITIONAL">SC_ELEMENT_CARET_ADDITIONAL : colouralpha</b><br /> <b id="SCI_SETADDITIONALCARETFORE">SCI_SETADDITIONALCARETFORE(<a class="jump" href="#colour">colour</a> fore)</b><br /> <b id="SCI_GETADDITIONALCARETFORE">SCI_GETADDITIONALCARETFORE → colour</b><br /> <b id="SCI_SETADDITIONALCARETSBLINK">SCI_SETADDITIONALCARETSBLINK(bool additionalCaretsBlink)</b><br /> <b id="SCI_GETADDITIONALCARETSBLINK">SCI_GETADDITIONALCARETSBLINK → bool</b><br /> Modify the appearance of additional carets so that they can be differentiated from the main caret which has its appearance set with + <a class="element" href="#SC_ELEMENT_CARET"><code>SC_ELEMENT_CARET</code></a>, <a class="message" href="#SCI_SETCARETFORE"><code>SCI_SETCARETFORE</code></a>, <a class="message" href="#SCI_GETCARETFORE"><code>SCI_GETCARETFORE</code></a>, <a class="message" href="#SCI_SETCARETPERIOD"><code>SCI_SETCARETPERIOD</code></a>, and @@ -2451,7 +2472,7 @@ struct Sci_TextToFind { <b id="SCI_GETMOUSEWHEELCAPTURES">SCI_GETMOUSEWHEELCAPTURES → bool</b><br /> On Windows, Scintilla captures all <code>WM_MOUSEWHEEL</code> messages if it has the focus, even if the mouse pointer is nowhere near the Scintilla editor window. This - behavior can be changed with <code>SCI_SETMOUSEWHEELCAPTURES(0)</code> so that + behaviour can be changed with <code>SCI_SETMOUSEWHEELCAPTURES(0)</code> so that Scintilla passes the <code>WM_MOUSEWHEEL</code> messages to its parent window. Scintilla will still react to the mouse wheel if the mouse pointer is over the editor window.</p> @@ -3269,7 +3290,7 @@ struct Sci_TextToFind { </tr> </thead> <tbody valign="top"> - <tr> + <tr class="section"> <th align="left"><code>SC_ELEMENT_LIST</code></th> <td>0</td> <td>Opaque</td> @@ -3297,6 +3318,83 @@ struct Sci_TextToFind { <td>Win32</td> <td>Background colour of selected item in autocompletion lists</td> </tr> + <tr class="section"> + <th align="left"><code>SC_ELEMENT_SELECTION_TEXT</code></th> + <td>10</td> + <td>Translucent</td> + <td>All</td> + <td>Text colour of main selection</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_BACK</code></th> + <td>11</td> + <td>Translucent</td> + <td>All</td> + <td>Background colour of main selection</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_ADDITIONAL_TEXT</code></th> + <td>12</td> + <td>Translucent</td> + <td>All</td> + <td>Text colour of additional selections</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_ADDITIONAL_BACK</code></th> + <td>13</td> + <td>Translucent</td> + <td>All</td> + <td>Background colour of additional selections</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_SECONDARY_TEXT</code></th> + <td>14</td> + <td>Translucent</td> + <td>All</td> + <td>Text colour of selections when another window contains the primary selection</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_SECONDARY_BACK</code></th> + <td>15</td> + <td>Translucent</td> + <td>All</td> + <td>Background colour of selections when another window contains the primary selection</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_NO_FOCUS_TEXT</code></th> + <td>16</td> + <td>Translucent</td> + <td>All</td> + <td>Text colour of selections when another window has focus</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_SELECTION_NO_FOCUS_BACK</code></th> + <td>17</td> + <td>Translucent</td> + <td>All</td> + <td>Background colour of selections when another window has focus</td> + </tr> + <tr class="section"> + <th align="left"><code>SC_ELEMENT_CARET</code></th> + <td>40</td> + <td>Translucent</td> + <td>All</td> + <td>Colour of caret for main selection</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_CARET_ADDITIONAL</code></th> + <td>41</td> + <td>Translucent</td> + <td>All</td> + <td>Colour of caret for additional selections</td> + </tr> + <tr> + <th align="left"><code>SC_ELEMENT_CARET_SECONDARY</code></th> + <td>42</td> + <td>Translucent</td> + <td>All</td> + <td>Colour of carets when another window has focus</td> + </tr> </tbody> </table> @@ -3309,22 +3407,40 @@ struct Sci_TextToFind { The default value is US English "en-us". </p> - <h2 id="CaretAndSelectionStyles">Caret, selection, and hotspot styles</h2> + <h2 id="CaretAndSelectionStyles">Selection, caret, and hotspot styles</h2> - <p>The selection is shown by changing the foreground and/or background colours. If one of these - is not set then that attribute is not changed for the selection. The default is to show the - selection by changing the background to light grey and leaving the foreground the same as when + <p>The selection is shown by changing the text and/or background colours. + If the selected text colour is not set then that attribute is not changed for the selection. + The default is to show the + selection by changing the background and leaving the foreground the same as when it was not selected. When there is no selection, the current insertion point is marked by the text caret. This is a vertical line that is normally blinking on and off to attract the users attention.</p> - <code><a class="message" href="#SCI_SETSELFORE">SCI_SETSELFORE(bool useSetting, colour fore)</a><br /> - <a class="message" href="#SCI_SETSELBACK">SCI_SETSELBACK(bool useSetting, colour back)</a><br /> - <a class="message" href="#SCI_SETSELALPHA">SCI_SETSELALPHA(alpha alpha)</a><br /> - <a class="message" href="#SCI_GETSELALPHA">SCI_GETSELALPHA → int</a><br /> + <p>On most platforms, a default grey selection background is used but, on macOS, the system-defined + selection background is used. The application can call APIs to change the colours used.</p> + <code> + <a class="element" href="#SC_ELEMENT_SELECTION_TEXT">SC_ELEMENT_SELECTION_TEXT : colouralpha</a><br /> + <a class="discouraged message" href="#SCI_SETSELFORE">SCI_SETSELFORE(bool useSetting, colour fore)</a><br /> + <a class="element" href="#SC_ELEMENT_SELECTION_BACK">SC_ELEMENT_SELECTION_BACK : colouralpha</a><br /> + <a class="discouraged message" href="#SCI_SETSELBACK">SCI_SETSELBACK(bool useSetting, colour back)</a><br /> + <a class="message" href="#SCI_SETSELECTIONLAYER">SCI_SETSELECTIONLAYER(int layer)</a><br /> + <a class="message" href="#SCI_GETSELECTIONLAYER">SCI_GETSELECTIONLAYER → int</a><br /> + <a class="discouraged message" href="#SCI_SETSELALPHA">SCI_SETSELALPHA(alpha alpha)</a><br /> + <a class="discouraged message" href="#SCI_GETSELALPHA">SCI_GETSELALPHA → int</a><br /> <a class="message" href="#SCI_SETSELEOLFILLED">SCI_SETSELEOLFILLED(bool filled)</a><br /> <a class="message" href="#SCI_GETSELEOLFILLED">SCI_GETSELEOLFILLED → bool</a><br /> - <a class="message" href="#SCI_SETCARETFORE">SCI_SETCARETFORE(colour fore)</a><br /> - <a class="message" href="#SCI_GETCARETFORE">SCI_GETCARETFORE → colour</a><br /> + <br /> + <a class="element" href="#SC_ELEMENT_CARET">SC_ELEMENT_CARET : colouralpha</a><br /> + <a class="discouraged message" href="#SCI_SETCARETFORE">SCI_SETCARETFORE(colour fore)</a><br /> + <a class="discouraged message" href="#SCI_GETCARETFORE">SCI_GETCARETFORE → colour</a><br /> + <br /> + <a class="element" href="#SC_ELEMENT_SELECTION_SECONDARY_TEXT">SC_ELEMENT_SELECTION_SECONDARY_TEXT : colouralpha</a><br /> + <a class="element" href="#SC_ELEMENT_SELECTION_SECONDARY_BACK">SC_ELEMENT_SELECTION_SECONDARY_BACK : colouralpha</a><br /> + <a class="element" href="#SC_ELEMENT_CARET_SECONDARY">SC_ELEMENT_CARET_SECONDARY : colouralpha</a><br /> + <br /> + <a class="element" href="#SC_ELEMENT_SELECTION_NO_FOCUS_TEXT">SC_ELEMENT_SELECTION_NO_FOCUS_TEXT : colouralpha</a><br /> + <a class="element" href="#SC_ELEMENT_SELECTION_NO_FOCUS_BACK">SC_ELEMENT_SELECTION_NO_FOCUS_BACK : colouralpha</a><br /> + <br /> <a class="message" href="#SCI_SETCARETLINEVISIBLE">SCI_SETCARETLINEVISIBLE(bool show)</a><br /> <a class="message" href="#SCI_GETCARETLINEVISIBLE">SCI_GETCARETLINEVISIBLE → bool</a><br /> <a class="message" href="#SCI_SETCARETLINEBACK">SCI_SETCARETLINEBACK(colour back)</a><br /> @@ -3335,12 +3451,17 @@ struct Sci_TextToFind { <a class="message" href="#SCI_GETCARETLINEFRAME">SCI_GETCARETLINEFRAME → int</a><br /> <a class="message" href="#SCI_SETCARETLINEVISIBLEALWAYS">SCI_SETCARETLINEVISIBLEALWAYS(bool alwaysVisible)</a><br /> <a class="message" href="#SCI_GETCARETLINEVISIBLEALWAYS">SCI_GETCARETLINEVISIBLEALWAYS → bool</a><br /> + <br /> <a class="message" href="#SCI_SETCARETPERIOD">SCI_SETCARETPERIOD(int periodMilliseconds)</a><br /> <a class="message" href="#SCI_GETCARETPERIOD">SCI_GETCARETPERIOD → int</a><br /> <a class="message" href="#SCI_SETCARETSTYLE">SCI_SETCARETSTYLE(int caretStyle)</a><br /> <a class="message" href="#SCI_GETCARETSTYLE">SCI_GETCARETSTYLE → int</a><br /> <a class="message" href="#SCI_SETCARETWIDTH">SCI_SETCARETWIDTH(int pixelWidth)</a><br /> <a class="message" href="#SCI_GETCARETWIDTH">SCI_GETCARETWIDTH → int</a><br /> + <a class="message" href="#SCI_SETCARETSTICKY">SCI_SETCARETSTICKY(int useCaretStickyBehaviour)</a><br /> + <a class="message" href="#SCI_GETCARETSTICKY">SCI_GETCARETSTICKY → int</a><br /> + <a class="message" href="#SCI_TOGGLECARETSTICKY">SCI_TOGGLECARETSTICKY</a><br /> + <br /> <a class="message" href="#SCI_SETHOTSPOTACTIVEFORE">SCI_SETHOTSPOTACTIVEFORE(bool useSetting, colour fore)</a><br /> <a class="message" href="#SCI_GETHOTSPOTACTIVEFORE">SCI_GETHOTSPOTACTIVEFORE → colour</a><br /> <a class="message" href="#SCI_SETHOTSPOTACTIVEBACK">SCI_SETHOTSPOTACTIVEBACK(bool useSetting, colour back)</a><br /> @@ -3349,31 +3470,87 @@ struct Sci_TextToFind { <a class="message" href="#SCI_GETHOTSPOTACTIVEUNDERLINE">SCI_GETHOTSPOTACTIVEUNDERLINE → bool</a><br /> <a class="message" href="#SCI_SETHOTSPOTSINGLELINE">SCI_SETHOTSPOTSINGLELINE(bool singleLine)</a><br /> <a class="message" href="#SCI_GETHOTSPOTSINGLELINE">SCI_GETHOTSPOTSINGLELINE → bool</a><br /> - <a class="message" href="#SCI_SETCARETSTICKY">SCI_SETCARETSTICKY(int useCaretStickyBehaviour)</a><br /> - <a class="message" href="#SCI_GETCARETSTICKY">SCI_GETCARETSTICKY → int</a><br /> - <a class="message" href="#SCI_TOGGLECARETSTICKY">SCI_TOGGLECARETSTICKY</a><br /> </code> - <p><b id="SCI_SETSELFORE">SCI_SETSELFORE(bool useSetting, <a class="jump" href="#colour">colour</a> fore)</b><br /> + <p> + <b id="SC_ELEMENT_SELECTION_TEXT">SC_ELEMENT_SELECTION_TEXT : colouralpha</b><br /> + <b id="SCI_SETSELFORE">SCI_SETSELFORE(bool useSetting, <a class="jump" href="#colour">colour</a> fore)</b><br /> + <b id="SC_ELEMENT_SELECTION_BACK">SC_ELEMENT_SELECTION_BACK : colouralpha</b><br /> <b id="SCI_SETSELBACK">SCI_SETSELBACK(bool useSetting, <a class="jump" href="#colour">colour</a> back)</b><br /> - You can choose to override the default selection colouring with these two messages. The colour + You can choose to override the default selection colouring with these elements and messages. + The <a href="#ElementColours">element APIs</a> are now preferred as they handle translucency + layering and + cooperation with defaults better. + With the messages, the colour you provide is used if you set <code class="parameter">useSetting</code> to <code>true</code>. If it is set to <code>false</code>, the default styled colouring is used and the <code class="parameter">fore</code> or <code class="parameter">back</code> argument has no effect.</p> + + <p><b id="SCI_SETSELECTIONLAYER">SCI_SETSELECTIONLAYER(int layer)</b><br /> + <b id="SCI_GETSELECTIONLAYER">SCI_GETSELECTIONLAYER → int</b><br /> + The selection background can be drawn translucently over the text + or opaquely on the base layer. + The <code class="parameter">layer</code> argument can be one of:</p> + + <table class="standard" summary="Layer"> + <tbody valign="top"> + <tr> + <th align="left"><code>SC_LAYER_BASE</code></th> + + <td>0</td> + + <td>Draw the selection background opaquely on the base layer</td> + </tr> + + <tr> + <th align="left"><code>SC_LAYER_OVER_TEXT</code></th> + + <td>10</td> + + <td>Draw the selection background translucently over the text</td> + </tr> + + </tbody> + </table> + <p><b id="SCI_SETSELALPHA">SCI_SETSELALPHA(<a class="jump" href="#alpha">alpha</a> alpha)</b><br /> <b id="SCI_GETSELALPHA">SCI_GETSELALPHA → int</b><br /> - The selection can be drawn translucently in the selection background colour by - setting an alpha value.</p> + These APIs are now discouraged and should be replaced with + a combination of setting the layer with SCI_SETSELECTIONLAYER and + setting translucency through the SC_ELEMENT_SELECTION_BACK element.</p> <p><b id="SCI_SETSELEOLFILLED">SCI_SETSELEOLFILLED(bool filled)</b><br /> <b id="SCI_GETSELEOLFILLED">SCI_GETSELEOLFILLED → bool</b><br /> The selection can be drawn up to the right hand border by setting this property.</p> - <p><b id="SCI_SETCARETFORE">SCI_SETCARETFORE(<a class="jump" href="#colour">colour</a> fore)</b><br /> + <p> + <b id="SC_ELEMENT_CARET">SC_ELEMENT_CARET : colouralpha</b><br /> + <b id="SCI_SETCARETFORE">SCI_SETCARETFORE(<a class="jump" href="#colour">colour</a> fore)</b><br /> <b id="SCI_GETCARETFORE">SCI_GETCARETFORE → colour</b><br /> - The colour of the caret can be set with <code>SCI_SETCARETFORE</code> and retrieved with - <code>SCI_GETCARETFORE</code>.</p> + The colour of the caret can be set with + <a class="message" href="#SCI_SETELEMENTCOLOUR"><code>SCI_SETELEMENTCOLOUR(SC_ELEMENT_CARET)</code></a> or + <code>SCI_SETCARETFORE</code> and retrieved with + <a class="message" href="#SCI_GETELEMENTCOLOUR"><code>SCI_GETELEMENTCOLOUR(SC_ELEMENT_CARET)</code></a> or + <code>SCI_GETCARETFORE</code>. + The element APIs are preferred and allow setting the translucency of carets.</p> + + <p> + <b id="SC_ELEMENT_SELECTION_SECONDARY_TEXT">SC_ELEMENT_SELECTION_SECONDARY_TEXT : colouralpha</b><br /> + <b id="SC_ELEMENT_SELECTION_SECONDARY_BACK">SC_ELEMENT_SELECTION_SECONDARY_TEXT : colouralpha</b><br /> + <b id="SC_ELEMENT_CARET_SECONDARY">SC_ELEMENT_CARET_SECONDARY : colouralpha</b><br /> + On Unix systems running with the X window system or Wayland there is a 'primary selection' which is the text most recently + selected in any application and which can be pasted by a middle button click. + When working with a selection, it is commonly the primary selection so Scintilla draws the primary selection with the main and additional + colours defined earlier. When another application takes over the primary selection, these <code>_SECONDARY</code> colours are used. + They are commonly defined as grey to highlight that it is the selection in the other application that is now available as primary. + </p> + + <p> + <b id="SC_ELEMENT_SELECTION_NO_FOCUS_TEXT">SC_ELEMENT_SELECTION_NO_FOCUS_TEXT : colouralpha</b><br /> + <b id="SC_ELEMENT_SELECTION_NO_FOCUS_BACK">SC_ELEMENT_SELECTION_NO_FOCUS_BACK : colouralpha</b><br /> + When a window no longer has the keyboard focus, it is customary to make its selection less noticeable by colouring it grey. + These elements define the colours to be used for selections without focus. + </p> <p><b id="SCI_SETCARETLINEVISIBLE">SCI_SETCARETLINEVISIBLE(bool show)</b><br /> <b id="SCI_GETCARETLINEVISIBLE">SCI_GETCARETLINEVISIBLE → bool</b><br /> @@ -3467,19 +3644,6 @@ struct Sci_TextToFind { This setting only affects the width of the cursor when the cursor style is set to line caret mode, it does not affect the width for a block caret.</p> - <p><b id="SCI_SETHOTSPOTACTIVEFORE">SCI_SETHOTSPOTACTIVEFORE(bool useSetting, <a class="jump" href="#colour">colour</a> fore)</b><br /> - <b id="SCI_GETHOTSPOTACTIVEFORE">SCI_GETHOTSPOTACTIVEFORE → colour</b><br /> - <b id="SCI_SETHOTSPOTACTIVEBACK">SCI_SETHOTSPOTACTIVEBACK(bool useSetting, - <a class="jump" href="#colour">colour</a> back)</b><br /> - <b id="SCI_GETHOTSPOTACTIVEBACK">SCI_GETHOTSPOTACTIVEBACK → colour</b><br /> - <b id="SCI_SETHOTSPOTACTIVEUNDERLINE">SCI_SETHOTSPOTACTIVEUNDERLINE(bool underline)</b><br /> - <b id="SCI_GETHOTSPOTACTIVEUNDERLINE">SCI_GETHOTSPOTACTIVEUNDERLINE → bool</b><br /> - <b id="SCI_SETHOTSPOTSINGLELINE">SCI_SETHOTSPOTSINGLELINE(bool singleLine)</b><br /> - <b id="SCI_GETHOTSPOTSINGLELINE">SCI_GETHOTSPOTSINGLELINE → bool</b><br /> - While the cursor hovers over text in a style with the hotspot attribute set, - the default colouring can be modified and an underline drawn with these settings. - Single line mode stops a hotspot from wrapping onto next line.</p> - <p><b id="SCI_SETCARETSTICKY">SCI_SETCARETSTICKY(int useCaretStickyBehaviour)</b><br /> <b id="SCI_GETCARETSTICKY">SCI_GETCARETSTICKY → int</b><br /> <b id="SCI_TOGGLECARETSTICKY">SCI_TOGGLECARETSTICKY</b><br /> @@ -3500,6 +3664,19 @@ struct Sci_TextToFind { <p><code>SCI_TOGGLECARETSTICKY</code> switches from <code>SC_CARETSTICKY_ON</code> and <code>SC_CARETSTICKY_WHITESPACE</code> to <code>SC_CARETSTICKY_OFF</code> and from <code>SC_CARETSTICKY_OFF</code> to <code>SC_CARETSTICKY_ON</code>.</p> + <p><b id="SCI_SETHOTSPOTACTIVEFORE">SCI_SETHOTSPOTACTIVEFORE(bool useSetting, <a class="jump" href="#colour">colour</a> fore)</b><br /> + <b id="SCI_GETHOTSPOTACTIVEFORE">SCI_GETHOTSPOTACTIVEFORE → colour</b><br /> + <b id="SCI_SETHOTSPOTACTIVEBACK">SCI_SETHOTSPOTACTIVEBACK(bool useSetting, + <a class="jump" href="#colour">colour</a> back)</b><br /> + <b id="SCI_GETHOTSPOTACTIVEBACK">SCI_GETHOTSPOTACTIVEBACK → colour</b><br /> + <b id="SCI_SETHOTSPOTACTIVEUNDERLINE">SCI_SETHOTSPOTACTIVEUNDERLINE(bool underline)</b><br /> + <b id="SCI_GETHOTSPOTACTIVEUNDERLINE">SCI_GETHOTSPOTACTIVEUNDERLINE → bool</b><br /> + <b id="SCI_SETHOTSPOTSINGLELINE">SCI_SETHOTSPOTSINGLELINE(bool singleLine)</b><br /> + <b id="SCI_GETHOTSPOTSINGLELINE">SCI_GETHOTSPOTSINGLELINE → bool</b><br /> + While the cursor hovers over text in a style with the hotspot attribute set, + the default colouring can be modified and an underline drawn with these settings. + Single line mode stops a hotspot from wrapping onto next line.</p> + <h2 id="CharacterRepresentations">Character representations</h2> <p>Some characters, such as control characters and invalid bytes, do not have a visual glyph or use a glyph that is hard to distinguish.</p> @@ -8877,7 +9054,7 @@ for line = lineStart to lineEnd do SCI_ENSUREVISIBLE(line) next provisional status. To avoid using provisional messages compile with the symbol <code>SCI_DISABLE_PROVISIONAL</code> defined.</p> - <h2 id="DeprecatedMessages">Deprecated messages and notifications</h2> + <h2 id="DeprecatedMessages">Deprecated and discouraged messages and notifications</h2> <p>The following messages are currently supported to emulate existing Windows controls, but they will be removed in future versions of Scintilla. If you use these messages you should @@ -8964,6 +9141,11 @@ EM_FORMATRANGE Any use of these symbols should be removed and replaced with <a href="#Indicators">standard indicators</a>. <code>SCI_GETSTYLEBITS</code> and <code>SCI_GETSTYLEBITSNEEDED</code> always return 8, indicating that 8 bits are used for styling and there are 256 styles.</p> + + <p>Discouraged APIs are a step before deprecation. A new preferred API has been implemented that new code should use + but the old API is unlikely to be removed. + Discouraged APIs are marked with a <span class="discouraged">orange strikethrough</span> and their documentation mentions the preferred API. + </p> <h2 id="EditMessagesNeverSupportedByScintilla">Edit messages never supported by Scintilla</h2> <pre> diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 67dd2133d..bf43a17b6 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -579,6 +579,13 @@ Released 23 April 2021. </li> <li> + Change the way that selections and carets are drawn to use the element APIs. + The selection background colour may default to use platform APIs to discover global + or user settings and may change in response to those settings changing. + The SCI_SETSELECTIONLAYER method defines whether the selection background is drawn + translucently over text or opaquely underneath other drawing. + </li> + <li> Make idle actions wrapping and background styling smoother by measuring per-byte instead of per-line and allowing just one line to be processed in a time slice. diff --git a/include/Scintilla.h b/include/Scintilla.h index 3f16dffc5..1a352ae85 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -273,6 +273,17 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_ELEMENT_LIST_BACK 1 #define SC_ELEMENT_LIST_SELECTED 2 #define SC_ELEMENT_LIST_SELECTED_BACK 3 +#define SC_ELEMENT_SELECTION_TEXT 10 +#define SC_ELEMENT_SELECTION_BACK 11 +#define SC_ELEMENT_SELECTION_ADDITIONAL_TEXT 12 +#define SC_ELEMENT_SELECTION_ADDITIONAL_BACK 13 +#define SC_ELEMENT_SELECTION_SECONDARY_TEXT 14 +#define SC_ELEMENT_SELECTION_SECONDARY_BACK 15 +#define SC_ELEMENT_SELECTION_NO_FOCUS_TEXT 16 +#define SC_ELEMENT_SELECTION_NO_FOCUS_BACK 17 +#define SC_ELEMENT_CARET 40 +#define SC_ELEMENT_CARET_ADDITIONAL 41 +#define SC_ELEMENT_CARET_SECONDARY 42 #define SCI_SETELEMENTCOLOUR 2753 #define SCI_GETELEMENTCOLOUR 2754 #define SCI_RESETELEMENTCOLOUR 2755 @@ -284,6 +295,10 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_SETSELALPHA 2478 #define SCI_GETSELEOLFILLED 2479 #define SCI_SETSELEOLFILLED 2480 +#define SC_LAYER_BASE 0 +#define SC_LAYER_OVER_TEXT 10 +#define SCI_GETSELECTIONLAYER 2762 +#define SCI_SETSELECTIONLAYER 2763 #define SCI_SETCARETFORE 2069 #define SCI_ASSIGNCMDKEY 2070 #define SCI_CLEARCMDKEY 2071 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index faf846dc8..ac5a72346 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -676,6 +676,17 @@ val SC_ELEMENT_LIST=0 val SC_ELEMENT_LIST_BACK=1 val SC_ELEMENT_LIST_SELECTED=2 val SC_ELEMENT_LIST_SELECTED_BACK=3 +val SC_ELEMENT_SELECTION_TEXT=10 +val SC_ELEMENT_SELECTION_BACK=11 +val SC_ELEMENT_SELECTION_ADDITIONAL_TEXT=12 +val SC_ELEMENT_SELECTION_ADDITIONAL_BACK=13 +val SC_ELEMENT_SELECTION_SECONDARY_TEXT=14 +val SC_ELEMENT_SELECTION_SECONDARY_BACK=15 +val SC_ELEMENT_SELECTION_NO_FOCUS_TEXT=16 +val SC_ELEMENT_SELECTION_NO_FOCUS_BACK=17 +val SC_ELEMENT_CARET=40 +val SC_ELEMENT_CARET_ADDITIONAL=41 +val SC_ELEMENT_CARET_SECONDARY=42 # Set the colour of an element. Translucency (alpha) may or may not be significant # and this may depend on the platform. The alpha byte should commonly be 0xff for opaque. @@ -712,6 +723,16 @@ get bool GetSelEOLFilled=2479(,) # Set the selection to have its end of line filled or not. set void SetSelEOLFilled=2480(bool filled,) +enu Layer=SC_LAYER_ +val SC_LAYER_BASE=0 +val SC_LAYER_OVER_TEXT=10 + +# Get the layer for drawing selections +get Layer GetSelectionLayer=2762(,) + +# Set the layer for drawing selections: either opaquely on base layer or translucently over text +set void SetSelectionLayer=2763(Layer layer,) + # Set the foreground colour of the caret. set void SetCaretFore=2069(colour fore,) diff --git a/src/EditView.cxx b/src/EditView.cxx index 2d32c8997..5549e73db 100644 --- a/src/EditView.cxx +++ b/src/EditView.cxx @@ -826,42 +826,46 @@ namespace { constexpr ColourAlpha bugColour = ColourAlpha(0xff, 0, 0xff, 0xf0); -ColourAlpha SelectionBackground(const EditModel &model, const ViewStyle &vsDraw, InSelection inSelection) noexcept { +// Selection background colours are always defined, the value_or is to show if bug + +ColourAlpha SelectionBackground(const EditModel &model, const ViewStyle &vsDraw, InSelection inSelection) { if (inSelection == InSelection::inNone) return bugColour; // Not selected is a bug - if (!vsDraw.selection.colours.back) - return bugColour; // Not set -> bug - + int element = SC_ELEMENT_SELECTION_BACK; + if (inSelection == InSelection::inAdditional) + element = SC_ELEMENT_SELECTION_ADDITIONAL_BACK; if (!model.primarySelection) - return vsDraw.selection.background2; // Secondary selection - - if (inSelection == InSelection::inMain) - return *vsDraw.selection.colours.back; // Main selection - - return vsDraw.selection.additionalBackground; // Additional selection + element = SC_ELEMENT_SELECTION_SECONDARY_BACK; + if (!model.hasFocus && vsDraw.ElementColour(SC_ELEMENT_SELECTION_NO_FOCUS_BACK)) + element = SC_ELEMENT_SELECTION_NO_FOCUS_BACK; + return vsDraw.ElementColour(element).value_or(bugColour); } -std::optional<ColourAlpha> SelectionForeground(const ViewStyle &vsDraw, InSelection inSelection) noexcept { +std::optional<ColourAlpha> SelectionForeground(const EditModel &model, const ViewStyle &vsDraw, InSelection inSelection) { if (inSelection == InSelection::inNone) return {}; - if (inSelection == InSelection::inMain) - return vsDraw.selection.colours.fore; - if (!vsDraw.selection.colours.fore) // Main not set means don't use additional either - return {}; - return vsDraw.selection.additionalForeground; + int element = SC_ELEMENT_SELECTION_TEXT; + if (inSelection == InSelection::inAdditional) + element = SC_ELEMENT_SELECTION_ADDITIONAL_TEXT; + if (!model.primarySelection) // Secondary selection + element = SC_ELEMENT_SELECTION_SECONDARY_TEXT; + if (!model.hasFocus) { + if (vsDraw.ElementColour(SC_ELEMENT_SELECTION_NO_FOCUS_TEXT)) { + element = SC_ELEMENT_SELECTION_NO_FOCUS_TEXT; + } else { + return {}; + } + } + return vsDraw.ElementColour(element); } } static ColourAlpha TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - std::optional<ColourAlpha> background, InSelection inSelection, bool inHotspot, int styleMain, Sci::Position i) noexcept { - if (inSelection && vsDraw.selection.colours.back) { - if ((inSelection == InSelection::inMain) && (vsDraw.selection.alpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(model, vsDraw, inSelection); - } else if ((inSelection == InSelection::inAdditional) && (vsDraw.selection.additionalAlpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(model, vsDraw, inSelection); - } + std::optional<ColourAlpha> background, InSelection inSelection, bool inHotspot, int styleMain, Sci::Position i) { + if (inSelection && (vsDraw.selection.layer == Layer::base)) { + return SelectionBackground(model, vsDraw, inSelection).Opaque(); } if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll->edgeColumn) && @@ -968,34 +972,30 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle rcSegment.right = xEol + xStart + virtualSpace; const ColourAlpha backgroundFill = background.value_or(vsDraw.styles[ll->styles[ll->numCharsInLine]].back); surface->FillRectangleAligned(rcSegment, backgroundFill); - if (!hideSelection && ((vsDraw.selection.alpha == SC_ALPHA_NOALPHA) || (vsDraw.selection.additionalAlpha == SC_ALPHA_NOALPHA))) { + if (!hideSelection && (vsDraw.selection.layer == Layer::base)) { const SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)))); for (size_t r = 0; r<model.sel.Count(); r++) { - const int alpha = (r == model.sel.Main()) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; - if (alpha == SC_ALPHA_NOALPHA) { - const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); - if (!portion.Empty()) { - const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; - rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; - rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; - surface->FillRectangleAligned(rcSegment, Fill(SelectionBackground(model, vsDraw, model.sel.RangeType(r)))); - } + const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + surface->FillRectangleAligned(rcSegment, Fill( + SelectionBackground(model, vsDraw, model.sel.RangeType(r)).Opaque())); } } } } InSelection eolInSelection = InSelection::inNone; - int alpha = SC_ALPHA_NOALPHA; if (!hideSelection && lastSubLine) { eolInSelection = model.LineEndInSelection(line); - alpha = (eolInSelection == InSelection::inMain) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; } const ColourAlpha selectionBack = SelectionBackground(model, vsDraw, eolInSelection); @@ -1024,11 +1024,11 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle ctrlChar = hexits; } } - const std::optional<ColourAlpha> selectionFore = SelectionForeground(vsDraw, eolInSelection); + const std::optional<ColourAlpha> selectionFore = SelectionForeground(model, vsDraw, eolInSelection); const ColourAlpha textFore = selectionFore.value_or(vsDraw.styles[styleMain].fore); - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1)) { - if (alpha == SC_ALPHA_NOALPHA) { - surface->FillRectangleAligned(rcSegment, Fill(selectionBack)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1)) { + if (vsDraw.selection.layer == Layer::base) { + surface->FillRectangleAligned(rcSegment, Fill(selectionBack.Opaque())); } else { surface->FillRectangleAligned(rcSegment, Fill(textBack)); } @@ -1036,8 +1036,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle surface->FillRectangleAligned(rcSegment, Fill(textBack)); } DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == PhasesDraw::one); - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcSegment, ColourAlpha(selectionBack, alpha)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcSegment, selectionBack); } } } @@ -1046,8 +1046,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcSegment, Fill(selectionBack)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::base)) { + surface->FillRectangleAligned(rcSegment, Fill(selectionBack.Opaque())); } else { if (background) { surface->FillRectangleAligned(rcSegment, Fill(*background)); @@ -1058,8 +1058,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle } else { surface->FillRectangleAligned(rcSegment, Fill(vsDraw.styles[STYLE_DEFAULT].back)); } - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcSegment, ColourAlpha(selectionBack, alpha)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcSegment, selectionBack); } } @@ -1227,10 +1227,8 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con const int widthFoldDisplayText = static_cast<int>(surface->WidthText(fontText, foldDisplayText)); InSelection eolInSelection = InSelection::inNone; - int alpha = SC_ALPHA_NOALPHA; if (!hideSelection) { eolInSelection = model.LineEndInSelection(line); - alpha = (eolInSelection == InSelection::inMain) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; } const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; @@ -1240,7 +1238,7 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthFoldDisplayText); const std::optional<ColourAlpha> background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); - const std::optional<ColourAlpha> selectionFore = SelectionForeground(vsDraw, eolInSelection); + const std::optional<ColourAlpha> selectionFore = SelectionForeground(model, vsDraw, eolInSelection); const ColourAlpha textFore = selectionFore.value_or(vsDraw.styles[STYLE_FOLDDISPLAYTEXT].fore); const ColourAlpha textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, STYLE_FOLDDISPLAYTEXT, -1); @@ -1286,8 +1284,8 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con } if (FlagSet(phase, DrawPhase::selectionTranslucent)) { - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && alpha != SC_ALPHA_NOALPHA) { - surface->FillRectangleAligned(rcSegment, ColourAlpha(SelectionBackground(model, vsDraw, eolInSelection), alpha)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcSegment, SelectionBackground(model, vsDraw, eolInSelection)); } } } @@ -1644,8 +1642,11 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt rcCaret.left = std::round(xposCaret - caretWidthOffset); rcCaret.right = rcCaret.left + vsDraw.caret.width; } - const ColourAlpha caretColour = mainCaret ? vsDraw.caret.colour : vsDraw.caret.additionalColour; - assert(caretColour.IsOpaque()); + int elementCaret = mainCaret ? SC_ELEMENT_CARET : SC_ELEMENT_CARET_ADDITIONAL; + if (!model.primarySelection) + elementCaret = SC_ELEMENT_CARET_SECONDARY; + const ColourAlpha caretColour = *vsDraw.ElementColour(elementCaret); + //assert(caretColour.IsOpaque()); if (drawBlockCaret) { DrawBlockCaret(surface, model, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); } else { @@ -1808,7 +1809,7 @@ static void DrawMarkUnderline(Surface *surface, const EditModel &model, const Vi static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart, int tabWidthMinimumPixels) { - if ((vsDraw.selection.alpha != SC_ALPHA_NOALPHA) || (vsDraw.selection.additionalAlpha != SC_ALPHA_NOALPHA)) { + if (vsDraw.selection.layer == Layer::over) { const Sci::Position posLineStart = model.pdoc->LineStart(line); const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; // For each selection draw @@ -1820,51 +1821,48 @@ static void DrawTranslucentSelection(Surface *surface, const EditModel &model, c const SelectionPosition posEnd(posLineStart + lineRange.end, virtualSpaces); const SelectionSegment virtualSpaceRange(posStart, posEnd); for (size_t r = 0; r < model.sel.Count(); r++) { - const int alpha = (r == model.sel.Main()) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; - if (alpha != SC_ALPHA_NOALPHA) { - const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); - if (!portion.Empty()) { - const ColourAlpha selectionBack = ColourAlpha( - SelectionBackground(model, vsDraw, model.sel.RangeType(r)), alpha); - const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - if (model.BidirectionalEnabled()) { - const int selectionStart = static_cast<int>(portion.start.Position() - posLineStart - lineRange.start); - const int selectionEnd = static_cast<int>(portion.end.Position() - posLineStart - lineRange.start); - - const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels); - std::unique_ptr<IScreenLineLayout> slLayout = surface->Layout(&screenLine); - - const std::vector<Interval> intervals = slLayout->FindRangeIntervals(selectionStart, selectionEnd); - for (const Interval &interval : intervals) { - const XYPOSITION rcRight = interval.right + xStart; - const XYPOSITION rcLeft = interval.left + xStart; - const PRectangle rcSelection(rcLeft, rcLine.top, rcRight, rcLine.bottom); - surface->FillRectangleAligned(rcSelection, selectionBack); - } + const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const ColourAlpha selectionBack = SelectionBackground( + model, vsDraw, model.sel.RangeType(r)); + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + if (model.BidirectionalEnabled()) { + const int selectionStart = static_cast<int>(portion.start.Position() - posLineStart - lineRange.start); + const int selectionEnd = static_cast<int>(portion.end.Position() - posLineStart - lineRange.start); + + const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels); + std::unique_ptr<IScreenLineLayout> slLayout = surface->Layout(&screenLine); + + const std::vector<Interval> intervals = slLayout->FindRangeIntervals(selectionStart, selectionEnd); + for (const Interval &interval : intervals) { + const XYPOSITION rcRight = interval.right + xStart; + const XYPOSITION rcLeft = interval.left + xStart; + const PRectangle rcSelection(rcLeft, rcLine.top, rcRight, rcLine.bottom); + surface->FillRectangleAligned(rcSelection, selectionBack); + } - if (portion.end.VirtualSpace()) { - const XYPOSITION xStartVirtual = ll->positions[lineRange.end] - - static_cast<XYPOSITION>(subLineStart) + xStart; - PRectangle rcSegment = rcLine; - rcSegment.left = xStartVirtual + portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStartVirtual + portion.end.VirtualSpace() * spaceWidth; - surface->FillRectangleAligned(rcSegment, selectionBack); - } - } else { + if (portion.end.VirtualSpace()) { + const XYPOSITION xStartVirtual = ll->positions[lineRange.end] - + static_cast<XYPOSITION>(subLineStart) + xStart; PRectangle rcSegment = rcLine; - rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart) + portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart) + portion.end.VirtualSpace() * spaceWidth; - if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { - if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) - rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here - } - rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; - rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; - if (rcSegment.right > rcLine.left) - surface->FillRectangleAligned(rcSegment, selectionBack); + rcSegment.left = xStartVirtual + portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStartVirtual + portion.end.VirtualSpace() * spaceWidth; + surface->FillRectangleAligned(rcSegment, selectionBack); } + } else { + PRectangle rcSegment = rcLine; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart) + portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart) + portion.end.VirtualSpace() * spaceWidth; + if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { + if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) + rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here + } + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + if (rcSegment.right > rcLine.left) + surface->FillRectangleAligned(rcSegment, selectionBack); } } } @@ -1972,7 +1970,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } } const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); - const std::optional<ColourAlpha> selectionFore = SelectionForeground(vsDraw, inSelection); + const std::optional<ColourAlpha> selectionFore = SelectionForeground(model, vsDraw, inSelection); if (selectionFore) { textFore = *selectionFore; } @@ -2461,28 +2459,26 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan void EditView::FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcArea, int subLine) const { InSelection eolInSelection = InSelection::inNone; - int alpha = SC_ALPHA_NOALPHA; - if ((!hideSelection) && (subLine == (ll->lines - 1))) { - eolInSelection = model.LineEndInSelection(line); - alpha = (eolInSelection == InSelection::inMain) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; - } + if ((!hideSelection) && (subLine == (ll->lines - 1))) { + eolInSelection = model.LineEndInSelection(line); + } - const std::optional<ColourAlpha> background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); + const std::optional<ColourAlpha> background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); - if (eolInSelection && vsDraw.selection.eolFilled && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcArea, Fill(SelectionBackground(model, vsDraw, eolInSelection))); + if (eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::base)) { + surface->FillRectangleAligned(rcArea, Fill(SelectionBackground(model, vsDraw, eolInSelection).Opaque())); + } else { + if (background) { + surface->FillRectangleAligned(rcArea, Fill(*background)); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[ll->styles[ll->numCharsInLine]].back)); } else { - if (background) { - surface->FillRectangleAligned(rcArea, Fill(*background)); - } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { - surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[ll->styles[ll->numCharsInLine]].back)); - } else { - surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[STYLE_DEFAULT].back)); - } - if (eolInSelection && vsDraw.selection.eolFilled && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcArea, ColourAlpha(SelectionBackground(model, vsDraw, eolInSelection), alpha)); - } + surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[STYLE_DEFAULT].back)); } + if (eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcArea, SelectionBackground(model, vsDraw, eolInSelection)); + } + } } // Space (3 space characters) between line numbers and text when printing. @@ -2526,10 +2522,8 @@ Sci::Position EditView::FormatRange(bool draw, const Sci_RangeToFormat *pfr, Sur // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT vsPrint.viewIndentationGuides = IndentView::none; // Don't show the selection when printing - vsPrint.selection.colours.back.reset(); - vsPrint.selection.colours.fore.reset(); - vsPrint.selection.alpha = SC_ALPHA_NOALPHA; - vsPrint.selection.additionalAlpha = SC_ALPHA_NOALPHA; + vsPrint.elementColours.clear(); + vsPrint.elementBaseColours.clear(); vsPrint.whitespaceColours.back.reset(); vsPrint.whitespaceColours.fore.reset(); vsPrint.caretLine.show = false; diff --git a/src/Editor.cxx b/src/Editor.cxx index 477173c6b..e6a31f11a 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -7417,25 +7417,38 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return LinesOnScreen(); case SCI_SETSELFORE: - vs.selection.colours.fore = OptionalColour(wParam, lParam); - vs.selection.additionalForeground = ColourAlpha::FromRGB(static_cast<int>(lParam)); + vs.elementColours[SC_ELEMENT_SELECTION_TEXT] = OptionalColour(wParam, lParam); + vs.elementColours[SC_ELEMENT_SELECTION_ADDITIONAL_TEXT] = OptionalColour(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_SETSELBACK: - vs.selection.colours.back = OptionalColour(wParam, lParam); - vs.selection.additionalBackground = ColourAlpha::FromRGB(static_cast<int>(lParam)); + if (wParam) { + vs.SetElementRGB(SC_ELEMENT_SELECTION_BACK, static_cast<int>(lParam)); + vs.SetElementRGB(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(lParam)); + } else { + vs.ResetElement(SC_ELEMENT_SELECTION_BACK); + vs.ResetElement(SC_ELEMENT_SELECTION_ADDITIONAL_BACK); + } InvalidateStyleRedraw(); break; - case SCI_SETSELALPHA: - vs.selection.alpha = static_cast<int>(wParam); - vs.selection.additionalAlpha = static_cast<int>(wParam); - InvalidateStyleRedraw(); + case SCI_SETSELALPHA: { + Layer layerNew = (wParam == SC_ALPHA_NOALPHA) ? Layer::base : Layer::over; + if (vs.selection.layer != layerNew) { + vs.selection.layer = layerNew; + UpdateBaseElements(); + } + vs.SetElementAlpha(SC_ELEMENT_SELECTION_BACK, static_cast<int>(wParam)); + vs.SetElementAlpha(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(wParam)); + InvalidateStyleRedraw(); + } break; case SCI_GETSELALPHA: - return vs.selection.alpha; + if (vs.selection.layer == Layer::base) + return SC_ALPHA_NOALPHA; + return vs.ElementColour(SC_ELEMENT_SELECTION_BACK)->GetAlpha(); case SCI_GETSELEOLFILLED: return vs.selection.eolFilled; @@ -7455,13 +7468,24 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { InvalidateStyleRedraw(); break; + case SCI_SETSELECTIONLAYER: + if (vs.selection.layer != static_cast<Layer>(wParam)) { + vs.selection.layer = static_cast<Layer>(wParam); + UpdateBaseElements(); + InvalidateStyleRedraw(); + } + break; + + case SCI_GETSELECTIONLAYER: + return static_cast<sptr_t>(vs.selection.layer); + case SCI_SETCARETFORE: - vs.caret.colour = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.elementColours[SC_ELEMENT_CARET] = ColourAlpha::FromRGB(static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_GETCARETFORE: - return vs.caret.colour.OpaqueRGB(); + return vs.ElementColour(SC_ELEMENT_CARET)->OpaqueRGB(); case SCI_SETCARETSTYLE: if (wParam <= (CARETSTYLE_BLOCK | CARETSTYLE_OVERSTRIKE_BLOCK | CARETSTYLE_BLOCK_AFTER)) @@ -8418,30 +8442,32 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return virtualSpaceOptions; case SCI_SETADDITIONALSELFORE: - vs.selection.additionalForeground = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.elementColours[SC_ELEMENT_SELECTION_ADDITIONAL_TEXT] = ColourAlpha::FromRGB(static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELBACK: - vs.selection.additionalBackground = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.SetElementRGB(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELALPHA: - vs.selection.additionalAlpha = static_cast<int>(wParam); + vs.SetElementAlpha(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALSELALPHA: - return vs.selection.additionalAlpha; + if (vs.selection.layer == Layer::base) + return SC_ALPHA_NOALPHA; + return vs.ElementColour(SC_ELEMENT_SELECTION_ADDITIONAL_BACK)->GetAlpha(); case SCI_SETADDITIONALCARETFORE: - vs.caret.additionalColour = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.elementColours[SC_ELEMENT_CARET_ADDITIONAL] = ColourAlpha::FromRGB(static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALCARETFORE: - return vs.caret.additionalColour.OpaqueRGB(); + return vs.ElementColour(SC_ELEMENT_CARET_ADDITIONAL)->OpaqueRGB(); case SCI_ROTATESELECTION: sel.RotateMain(); diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx index 16701983e..ed08ad6ce 100644 --- a/src/ViewStyle.cxx +++ b/src/ViewStyle.cxx @@ -196,13 +196,17 @@ void ViewStyle::Init(size_t stylesSize_) { spaceWidth = 8; tabWidth = spaceWidth * 8; - selection.colours.fore.reset(); - selection.colours.back = ColourAlpha(0xc0, 0xc0, 0xc0); - selection.additionalForeground = ColourAlpha(0xff, 0, 0); - selection.additionalBackground = ColourAlpha(0xd7, 0xd7, 0xd7); - selection.background2 = ColourAlpha(0xb0, 0xb0, 0xb0); - selection.alpha = SC_ALPHA_NOALPHA; - selection.additionalAlpha = SC_ALPHA_NOALPHA; + // Default is for no selection foregrounds + elementColours.erase(SC_ELEMENT_SELECTION_TEXT); + elementColours.erase(SC_ELEMENT_SELECTION_ADDITIONAL_TEXT); + elementColours.erase(SC_ELEMENT_SELECTION_SECONDARY_TEXT); + elementColours.erase(SC_ELEMENT_SELECTION_NO_FOCUS_TEXT); + // Shades of grey for selection backgrounds + elementBaseColours[SC_ELEMENT_SELECTION_BACK] = ColourAlpha(0xc0, 0xc0, 0xc0, 0xff); + elementBaseColours[SC_ELEMENT_SELECTION_ADDITIONAL_BACK] = ColourAlpha(0xd7, 0xd7, 0xd7, 0xff); + elementBaseColours[SC_ELEMENT_SELECTION_SECONDARY_BACK] = ColourAlpha(0xb0, 0xb0, 0xb0, 0xff); + elementBaseColours[SC_ELEMENT_SELECTION_NO_FOCUS_BACK] = ColourAlpha(0x80, 0x80, 0x80, 0x3f); + selection.layer = Layer::base; selection.eolFilled = false; foldmarginColour.reset(); @@ -217,8 +221,9 @@ void ViewStyle::Init(size_t stylesSize_) { styles[STYLE_LINENUMBER].fore = ColourAlpha(0, 0, 0); styles[STYLE_LINENUMBER].back = Platform::Chrome(); - caret.colour = ColourAlpha(0, 0, 0); - caret.additionalColour = ColourAlpha(0x7f, 0x7f, 0x7f); + elementBaseColours[SC_ELEMENT_CARET] = ColourAlpha(0, 0, 0); + elementBaseColours[SC_ELEMENT_CARET_ADDITIONAL] = ColourAlpha(0x7f, 0x7f, 0x7f); + elementBaseColours[SC_ELEMENT_CARET_SECONDARY] = ColourAlpha(0, 0, 0, 0x40); caret.style = CARETSTYLE_LINE; caret.width = 1; @@ -483,12 +488,15 @@ std::optional<ColourAlpha> ViewStyle::Background(int marksOfLine, bool caretActi } bool ViewStyle::SelectionBackgroundDrawn() const noexcept { - return selection.colours.back && - ((selection.alpha == SC_ALPHA_NOALPHA) || (selection.additionalAlpha == SC_ALPHA_NOALPHA)); + return selection.layer == Layer::base; } bool ViewStyle::SelectionTextDrawn() const { - return selection.colours.fore.has_value(); + return + ElementIsSet(SC_ELEMENT_SELECTION_TEXT) || + ElementIsSet(SC_ELEMENT_SELECTION_ADDITIONAL_TEXT) || + ElementIsSet(SC_ELEMENT_SELECTION_SECONDARY_TEXT) || + ElementIsSet(SC_ELEMENT_SELECTION_NO_FOCUS_TEXT); } bool ViewStyle::WhitespaceBackgroundDrawn() const noexcept { @@ -540,6 +548,16 @@ void ViewStyle::ResetElement(int element) { elementColours.erase(element); } +void ViewStyle::SetElementRGB(int element, int rgb) { + const ColourAlpha current = ElementColour(element).value_or(ColourAlpha(0, 0, 0, 0)); + elementColours[element] = ColourAlpha(ColourAlpha(rgb), current.GetAlpha()); +} + +void ViewStyle::SetElementAlpha(int element, int alpha) { + const ColourAlpha current = ElementColour(element).value_or(ColourAlpha(0, 0, 0, 0)); + elementColours[element] = ColourAlpha(current, std::min(alpha, 0xff)); +} + bool ViewStyle::ElementIsSet(int element) const { ElementMap::const_iterator search = elementColours.find(element); if (search != elementColours.end()) { diff --git a/src/ViewStyle.h b/src/ViewStyle.h index a9fe58131..6aab53f64 100644 --- a/src/ViewStyle.h +++ b/src/ViewStyle.h @@ -63,18 +63,11 @@ struct ForeBackColours { std::optional<ColourAlpha> back; }; +enum class Layer { base=0, over=10 }; + struct SelectionAppearance { - // Colours of main selection - ForeBackColours colours; - // Colours of additional (non-main) selections - ColourAlpha additionalForeground; - ColourAlpha additionalBackground; - // Background colour on X when not primary selection - ColourAlpha background2; - // Translucency. SC_ALPHA_NOALPHA: draw selection background beneath text - int alpha; - // Translucency of additional selections - int additionalAlpha; + // Whether to draw on base layer or over text + Layer layer; // Draw selection past line end characters up to right border bool eolFilled; }; @@ -93,10 +86,6 @@ struct CaretLineAppearance { }; struct CaretAppearance { - // Colour of caret - ColourAlpha colour; - // Colour of additional (non-main) carets - ColourAlpha additionalColour; // Line, block, over-strike bar ... int style; // Width in pixels @@ -245,6 +234,8 @@ public: std::optional<ColourAlpha> ElementColour(int element) const; bool ElementAllowsTranslucent(int element) const; void ResetElement(int element); + void SetElementRGB(int element, int rgb); + void SetElementAlpha(int element, int alpha); bool ElementIsSet(int element) const; bool SetElementBase(int element, ColourAlpha colour); |