wxWidgets / wxStyledTextCtrl - Highlight all occurrences when doubleclicking

767 views Asked by At

I am using wxWidgets 3.0.2 in a static unicode build on Windows 10. I am using a wxStyledTextCtrl, which is a near 1-to-1 mapping of Scintilla.

I am looking for functionality similar to Notepad++ where upon double-clicking on something in the editor, all occurrences of that item get highlighted. It is hard to find good examples that really demonstrate styling. I've looked at wxWidgets documentation, Scintilla documentation, Notepad++ source and Code::Blocks source (the latter two use Scintilla as their text editors) and still haven't had much luck.

I've tried many different variations of the following code and it never quite works right. Either nothing is highlighted or the whole document is highlighted. I know I'm missing something, but I can't figure out what.

//textarea is a wxStyledTextCtrl*
textarea->StyleSetBackground(styleHightlightAllSelected, wxColor(80, 255, 80));

wxString selectedText = textarea->GetSelectedText();
int selSize  = selectedText.size();
int selStart = textarea->GetSelectionStart();

int pos    = 0;
int curr   = 0;
int maxPos = textarea->GetLastPosition();
while(pos != -1){
    pos = textarea->FindText(curr, maxPos, selectedText);
    if(pos == selStart){ //skip the actual highlighted item
        curr = pos + selSize;
    } else if(pos != -1){
        textarea->StartStyling(pos, 0x1F);
        textarea->SetStyling(selSize, styleHightlightAllSelected);
        curr = pos + selSize;
    }
}

The search part of the loop does successfully find the selected text; it's just that the styling doesn't seem to take hold.

So my questions that I couldn't really find answers to are:

  1. styleHightlightAllSelected is an int set to 100. When I had it as 0, the whole document turned green when doubleclicking. I see that styles 32-39 are predefined. Are there other styles that are predefined-but-not-really-documented; meaning, is 100 ok?
  2. Do I have to set the entire style up, or can I just set the background color as I do above?
  3. Is it enough to do StartStyling() and SetStyling() when I find an occurrence and be done with it, or is there more?
  4. StartStyling() in wxWidgets has a mask argument, but the Scintilla counterpart does not. I can't clearly determine what I should set this to. It seems to be 31 (00011111) to preserve the 5 existing styling/lexer bits? Essentially, I'm not sure what to set this to if all I want to do is modify the background color of each occurrence.
  5. My program will regularly deal with files that are dozens or more megabytes in size, so should I just be highlighting occurrences that are visible, and adjust as necessary when srolling/jumping? At the moment it searches and (fails to) set styling on each occurrence, and it takes about a second on a 50MB file. I've observed that on the same file loaded in Notepad++, it happens instantly, so I'm assuming it does it on a visible basis?
1

There are 1 answers

0
User51610 On BEST ANSWER

I ended up asking about this on the github issues page for the Notepad++ project, and the correct way to do this is to not use styles, but rather use indicators instead. So my code above changes to this:

int maxPos = textarea->GetLastPosition();

textarea->IndicatorClearRange(0, maxPos);
textarea->IndicatorSetStyle(styleHightlightAllSelected, wxSTC_INDIC_ROUNDBOX);
textarea->IndicatorSetAlpha(styleHightlightAllSelected, 100);
textarea->IndicatorSetUnder(styleHightlightAllSelected, true);
textarea->IndicatorSetForeground(styleHightlightAllSelected, wxColor(0, 255, 0));

wxString selectedText = textarea->GetSelectedText();
int selSize  = selectedText.size();
int selStart = textarea->GetSelectionStart();

int pos    = 0;
int curr   = 0;
vector<int> selectionList;
while((pos = textarea->FindText(curr, maxPos, selectedText)) != -1){
    selectionList.push_back(pos);
    curr = pos + selSize;
}

textarea->SetIndicatorCurrent(styleHightlightAllSelected);
for(unsigned int i = 0; i < selectionList.size(); i++){
    if(selectionList[i] != selStart){
        textarea->IndicatorFillRange(selectionList[i], selSize);
    }
}

This doesn't factor in, however, only highlighting the visible range and only highlighting new occurrences as they scroll into view (I will add this later), so for files that are dozens of megabytes in size, it will take 2-3 seconds for the highlighting to finish.