Indicators

Indicators are text decorators that can accept mouse clicks and mouse releases, similar to hotspots, but they have many more styling and property options. In fact, the creator of (Q)Scintilla himself encourages the use of indicators instead of hotspots. We’ll find out why very soon.

Defining a hotspot (memory refresh)

Before we’ll consider how an indicator is created, let’s first look back at how hotspots were created. Remember the following figure:
 

 
Our lexer holds three styles: myStyle_0, myStyle_1 and myStyle_2. These are all QsciStyle-objects with their own properties. As you’ve learned in the Syntax highlighting chapter, you can use the setStyling(nr_of_chars, style_nr) function to apply a certain style on some text in the editor.
Now imagine you want myStyle_1 to be a hotspot style. Well, you know from the hotspots chapter how to turn a normal-style into a hotspot-style. All text belonging to that style automatically turns into hotspots.

Defining an indicator

It’s time to introduce indicators. As you can see on the figure below, they are conceptually totally different from hotspots.
 

 
To define an indicator, use the following function:

self.__editor.indicatorDefine(indicator_type, indicator_number)

The indicator_type parameter determines how the indicated text will look like. You can choose one of the following:

  • QsciScintilla.PlainIndicator              
  • QsciScintilla.SquiggleIndicator           
  • QsciScintilla.TTIndicator                 
  • QsciScintilla.DiagonalIndicator           
  • QsciScintilla.StrikeIndicator             
  • QsciScintilla.HiddenIndicator             
  • QsciScintilla.BoxIndicator                
  • QsciScintilla.RoundBoxIndicator           
  • QsciScintilla.StraightBoxIndicator        
  • QsciScintilla.FullBoxIndicator            
  • QsciScintilla.DashesIndicator             
  • QsciScintilla.DotsIndicator               
  • QsciScintilla.SquiggleLowIndicator        
  • QsciScintilla.DotBoxIndicator             
  • QsciScintilla.SquigglePixmapIndicator     
  • QsciScintilla.ThickCompositionIndicator   
  • QsciScintilla.ThinCompositionIndicator    
  • QsciScintilla.TextColorIndicator          
  • QsciScintilla.TriangleIndicator           
  • QsciScintilla.TriangleCharacterIndicator  

The indicator_number parameter determines the ID number of the defined indicator. The editor keeps a list of maximal 32 defined indicators.
 

Architectural difference hotspot vs indicator

First of all – unlike hotspot-styles – indicators are not part of the Lexer. In fact, the editor himself – not the Lexer – keeps a list of all the defined indicators. Each indicator is (probably) a QsciIndicator-object. This object has many attributes, like:

  • type/style
  • foreground color
  • hover foreground color
  • hover type/style

I would need to dive into the underlying C++ code to be sure about the term QsciIndicator-object, but the given model in the figure above is okay for all practical purposes.
By the way, no more 32 QsciIndicator-objects can exist for one editor.
 

Relationship to QsciStyle-objects hotspot vs indicator

As you can clearly see on the figure, indicators are in no way tied to QsciStyle-objects. They operate totally independent. And that’s important. Imagine the following example:

The hyperlink https://qscintilla.com is clickable text. At the same time, it belongs to a comment – so it is styled in the comment-style. How would you make this text ‘clickable’ using the hotspot mechanism? You could define the comment-style as a hotspot, but that would make all comments clickable! Not very useful. But if you apply an indicator on that piece of text, it gets clickable independently from the rest of the comment. In fact, it still belongs to the comment-style and at the same time, it belongs also to the given indicator-style.
 

Terminology

Just like “hotspot”, the term “indicator” leaves room for two interpretations. The following definition attempts to clarify:

Indicator
The term indicator is ambiguous. It can refer to an indicator-style, which is (probably) a QsciIndicator-object. Think of this object as the text marker.
The term can also refer to a piece of indicator-text, which is some text formatted in the indicator-style. Think of this as the marked text. Such text is clickable.

 

Applying an indicator-style on text old-fashioned way

Applying a hotspot-style on text was easy. You just define a certain style (QsciStyle-object) to be a hotspot, and all text belonging to that style automatically turns into hotspots.
Since indicators operate independently from existing styles, you’ll have to apply an indicator-style manually onto some text. In QScintilla, we use the term “filling” or “drawing” an indicator-style over text. Use the following functions:

# Tell the editor which indicator-style to use
# (pass it the indicator-style ID number)
self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, indicator_number)

# Assign a value to the text
self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORVALUE, value)

# Now apply the indicator-style on the chosen text
self.__editor.SendScintilla(QsciScintilla.SCI_INDICATORFILLRANGE, start_pos, nr_of_chars)

The first function simply tells the editor which indicator-style you want to use. Think of it as a command to pick up a certain text marker. The second function assigns a value to the text you’re going to indicate. This will be useful when the user clicks the indicated text (more on that later). The third function actually indicates the text. The parameter start_pos is the start position relative to the very beginning of the editor’s text. So you should start counting from the first character all the way up to the character where you want to start indicating. The next parameter nr_of_chars refers to the number of characters you want to indicate.
Honestly, counting characters from the very beginning of your editor’s text is quite … clumsy. Luckily, QScintilla provides a way to get that start position easily:

start_pos = self.__editor.positionFromLineIndex(line, col)

As first parameter line you should pass the line number of the start position. Be careful, you have to start counting from 0, so subtract -1 from the line numbers shown in the left margin. The second parameter col refers to the column of the start position. The first character on any line is in column 0, the second character in column 1, etc…

To clear the indicator, use the following functions:

# Tell the editor which indicator-style to clear
# (pass it the indicator-style ID number)
self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, indicator_number)

# Now clear the indicator-style from the chosen text
self.__editor.SendScintilla(QsciScintilla.SCI_INDICATORCLEARRANGE, start_pos, nr_of_chars)

Applying an indicator-style on text new way

The previous paragraph showed how to apply an indicator using three consecutive SendScintilla commands. QScintilla offers a new and simple way to do it without even touching the low-level API:

self.__editor.fillIndicatorRange(line_from, col_from, line_to, col_to, indicator_nr)

The function to clear the indicator is very similar:

self.__editor.clearIndicatorRange(line_from, col_from, line_to, col_to, indicator_nr)

But there is a serious downside to using these newer (and simpler) functions. When applying an indicator, you can store a value that can be retrieved when the indicator-text is clicked. Unfortunately, you have to use the old-fashioned SendScintilla commands from the previous paragraph for that. The new syntaxis doesn’t (yet) provide this feature.

 

Indicator look and feel

You can define several properties that impact the way your indicators look.

Type / Style
When defining a new indicator, you have to determine its type:

  • QsciScintilla.PlainIndicator              
  • QsciScintilla.SquiggleIndicator           
  • ..

We already covered that in the paragraph Defining an indicator. There is no need to repeat the whole table here.

 
Hover Type / Style
You can change the style when a mouse cursor is over the indicated text:

self.__editor.setIndicatorHoverStyle(indicator_type, indicator_nr)

 
Foreground color
This function selects the indicator’s foreground color, which is the color that is displayed when
there is no mouse cursor over the indicator.

self.__editor.setIndicatorForegroundColor(indicator_color, indicator_nr)

 
Hover foreground color
This function selects the indicator’s hover foreground color, which is the color that is displayed when
there is a mouse cursor over the indicator.

self.__editor.setIndicatorHoverForegroundColor(indicator_color, indicator_nr)

 
Draw under style
This function selects whether the indicator is painted under or above the text:

self.__editor.setIndicatorDrawUnder(draw_under, indicator_nr)

The parameter draw_under can be either True or False.

 

Catching mouseclicks

We didn’t cover yet the most important: making text ‘clickable’ with indicators. Thats something for the next page..