// This module implements the "official" high-level API of the TQt port of // Scintilla. It is modelled on TQTextEdit - a method of the same name should // behave in the same way. // // Copyright (c) 2006 // Riverbank Computing Limited // // This file is part of TQScintilla. // // This copy of TQScintilla is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2, or (at your option) any // later version. // // TQScintilla is supplied in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. // // You should have received a copy of the GNU General Public License along with // TQScintilla; see the file LICENSE. If not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include #include "qextscintilla.h" #include "qextscintillalexer.h" #include "qextscintillaapis.h" #include "qextscintillacommandset.h" // Make sure these match the values in Scintilla.h. We don't #include that // file because it just causes more clashes. #define KEYWORDSET_MAX 8 #define MARKER_MAX 31 // The default fold margin width. static const int defaultFoldMarginWidth = 14; // The default set of characters that make up a word. static const char *defaultWordChars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // The ctor. QextScintilla::QextScintilla(TQWidget *parent,const char *name,WFlags f) : QextScintillaBase(parent,name,f), allocatedMarkers(0), oldPos(-1), selText(FALSE), fold(NoFoldStyle), autoInd(FALSE), braceMode(NoBraceMatch), acSource(AcsDocument), acThresh(-1), acStart(""), acAPIs(0), ctAPIs(0), maxCallTips(-1), showSingle(FALSE), modified(FALSE), explicit_fillups(FALSE), fillups_enabled(FALSE), saved_fillups("") { connect(this,TQT_SIGNAL(SCN_MODIFYATTEMPTRO()), TQT_SIGNAL(modificationAttempted())); connect(this,TQT_SIGNAL(SCN_MODIFIED(int,int,const char *,int,int,int,int,int)), TQT_SLOT(handleModified(int,int,const char *,int,int,int,int,int))); connect(this,TQT_SIGNAL(SCN_CALLTIPCLICK(int)), TQT_SLOT(handleCallTipClick(int))); connect(this,TQT_SIGNAL(SCN_CHARADDED(int)), TQT_SLOT(handleCharAdded(int))); connect(this,TQT_SIGNAL(SCN_MARGINCLICK(int,int,int)), TQT_SLOT(handleMarginClick(int,int,int))); connect(this,TQT_SIGNAL(SCN_SAVEPOINTREACHED()), TQT_SLOT(handleSavePointReached())); connect(this,TQT_SIGNAL(SCN_SAVEPOINTLEFT()), TQT_SLOT(handleSavePointLeft())); connect(this,TQT_SIGNAL(SCN_UPDATEUI()), TQT_SLOT(handleUpdateUI())); connect(this,TQT_SIGNAL(TQSCN_SELCHANGED(bool)), TQT_SLOT(handleSelectionChanged(bool))); connect(this,TQT_SIGNAL(SCN_USERLISTSELECTION(const char *,int)), TQT_SLOT(handleUserListSelection(const char *,int))); // Set the default font. setFont(TQApplication::font()); // Set the default fore and background colours. TQColorGroup cg = TQApplication::palette().active(); setColor(cg.text()); setPaper(cg.base()); #if defined(Q_OS_WIN) setEolMode(EolWindows); #elif defined(Q_OS_MAC) setEolMode(EolMac); #else setEolMode(EolUnix); #endif // Capturing the mouse seems to cause problems on multi-head systems. // TQt should do the right thing anyway. SendScintilla(SCI_SETMOUSEDOWNCAPTURES,0UL); SendScintilla(SCI_SETPROPERTY,"fold","1"); setMatchedBraceForegroundColor(blue); setUnmatchedBraceForegroundColor(red); setLexer(); // Set the visible policy. These are the same as SciTE's defaults // which, presumably, are sensible. SendScintilla(SCI_SETVISIBLEPOLICY,VISIBLE_STRICT|VISIBLE_SLOP,4); // Create the standard command set. stdCmds = new QextScintillaCommandSet(this); doc.display(this,0); } // The dtor. QextScintilla::~QextScintilla() { doc.undisplay(this); delete stdCmds; } // Return the current text colour. TQColor QextScintilla::color() const { return nl_text_colour; } // Set the text colour. void QextScintilla::setColor(const TQColor &c) { if (lex.isNull()) { // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. SendScintilla(SCI_STYLESETFORE, 0, c); nl_text_colour = c; } } // Return the current paper colour. TQColor QextScintilla::paper() const { return nl_paper_colour; } // Set the paper colour. void QextScintilla::setPaper(const TQColor &c) { if (lex.isNull()) { // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. We still have to set the // default style as well for the background without any text. SendScintilla(SCI_STYLESETBACK, 0, c); SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, c); nl_paper_colour = c; } } // Set the default font. void QextScintilla::setFont(const TQFont &f) { if (lex.isNull()) { // Assume style 0 applies to everything so that we don't need to use // SCI_STYLECLEARALL which clears everything. setStylesFont(f, 0); nl_font = f; } } // Enable/disable auto-indent. void QextScintilla::setAutoIndent(bool autoindent) { autoInd = autoindent; } // Set the brace matching mode. void QextScintilla::setBraceMatching(BraceMatch bm) { braceMode = bm; } // Handle the addition of a character. void QextScintilla::handleCharAdded(int ch) { // Ignore if there is a selection. long pos = SendScintilla(SCI_GETSELECTIONSTART); if (pos != SendScintilla(SCI_GETSELECTIONEND) || pos == 0) return; // If auto-completion is already active then see if this character is a // start character. If it is then create a new list which will be a // subset of the current one. The case where it isn't a start // character seem to be handled correctly elsewhere. if (isListActive()) { if (isAutoCStartChar(ch)) { cancelList(); startAutoCompletion(acSource, FALSE, FALSE); } return; } // Handle call tips. if (strchr("(),", ch) != NULL) callTip(); // Handle auto-indentation. if (autoInd) if (lex.isNull() || (lex -> autoIndentStyle() & AiMaintain)) maintainIndentation(ch,pos); else autoIndentation(ch,pos); // See if we might want to start auto-completion. if (!isCallTipActive()) if (isAutoCStartChar(ch)) startAutoCompletion(acSource, FALSE, FALSE); else if (acThresh >= 1 && isWordChar(ch)) startAutoCompletion(acSource, TRUE, FALSE); } // See if a call tip is active. bool QextScintilla::isCallTipActive() { return SendScintilla(SCI_CALLTIPACTIVE); } // Handle a possible change to any current call tip. void QextScintilla::callTip() { if (!ctAPIs) return; long pos = SendScintilla(SCI_GETCURRENTPOS); long linenr = SendScintilla(SCI_LINEFROMPOSITION,pos); long linelen = SendScintilla(SCI_LINELENGTH,linenr); char *lbuf = new char[linelen + 1]; int loff = SendScintilla(SCI_GETCURLINE,linelen + 1,lbuf); int commas = 0, start = -1; // Move backwards through the line looking for the start of the current // call tip and working out which argument it is. while (loff > 0) { char ch = lbuf[--loff]; if (ch == ',') ++commas; else if (ch == ')') { int depth = 1; // Ignore everything back to the start of the // corresponding parenthesis. while (loff > 0) { ch = lbuf[--loff]; if (ch == ')') ++depth; else if (ch == '(' && --depth == 0) break; } } else if (ch == '(' && loff > 0) { if (isWordChar(lbuf[loff - 1])) { // The parenthesis is preceded by a word so // find the start of that word. lbuf[loff--] = '\0'; while (loff >= 0) { if (!isWordChar(lbuf[loff]) && !isAutoCStartChar(lbuf[loff])) break; --loff; } start = loff + 1; break; } // We are between parentheses that do not correspond to // a call tip, so reset the argument count. commas = 0; } } // Cancel any existing call tip. SendScintilla(SCI_CALLTIPCANCEL); // Done if there is no new call tip to set. if (start < 0) { delete []lbuf; return; } TQString ct = ctAPIs -> callTips(&lbuf[start],maxCallTips,commas); delete []lbuf; if (ct.isEmpty()) return; ctpos = SendScintilla(SCI_POSITIONFROMLINE,linenr) + start; SendScintilla(SCI_CALLTIPSHOW,ctpos,ct.latin1()); // Done if there is more than one line in the call tip or there isn't a // down arrow at the start. if (ct[0] == '\002' || ct.find('\n') >= 0) return; // Highlight the current argument. int astart; if (commas == 0) astart = ct.find('('); else { astart = -1; do astart = ct.find(',',astart + 1); while (astart >= 0 && --commas > 0); } int len = ct.length(); if (astart < 0 || ++astart == len) return; // The end is at the next comma or unmatched closing parenthesis. int aend, depth = 0; for (aend = astart; aend < len; ++aend) { TQChar ch = ct.at(aend); if (ch == ',' && depth == 0) break; else if (ch == '(') ++depth; else if (ch == ')') { if (depth == 0) break; --depth; } } if (astart != aend) SendScintilla(SCI_CALLTIPSETHLT,astart,aend); } // Handle a call tip click. void QextScintilla::handleCallTipClick(int dir) { if (!ctAPIs) return; TQString ct = ctAPIs -> callTipsNextPrev(dir); if (ct.isNull()) return; SendScintilla(SCI_CALLTIPSHOW,ctpos,ct.latin1()); } // Possibly start auto-completion. void QextScintilla::startAutoCompletion(AutoCompletionSource acs, bool checkThresh, bool single) { // Get the current line. long len = SendScintilla(SCI_GETCURLINE) + 1; char *line = new char[len]; int wend = SendScintilla(SCI_GETCURLINE, len, line); // Find the start of the auto-completion text. int wstart = wend; bool numeric = true; while (wstart > 0) { char ch = line[wstart - 1]; // Don't auto-complete numbers. if (ch < '0' || ch > '9') numeric = false; if (!isWordChar(ch) && !isAutoCStartChar(ch)) break; --wstart; } int wlen = wend - wstart; if (numeric || wlen == 0 || (checkThresh && wlen < acThresh)) return; // Isolate the auto-completion text. char *word = &line[wstart]; line[wend] = '\0'; // Generate the string representing the valid words to select from. TQStringList wlist; bool cs = !SendScintilla(SCI_AUTOCGETIGNORECASE); if (acs == AcsAll || acs == AcsDocument) { SendScintilla(SCI_SETSEARCHFLAGS,SCFIND_WORDSTART | (cs ? SCFIND_MATCHCASE : 0)); long pos = 0; long dlen = SendScintilla(SCI_GETLENGTH); long caret = SendScintilla(SCI_GETCURRENTPOS); TQString root(word); for (;;) { long fstart; SendScintilla(SCI_SETTARGETSTART,pos); SendScintilla(SCI_SETTARGETEND,dlen); if ((fstart = SendScintilla(SCI_SEARCHINTARGET,wlen,word)) < 0) break; // Move past the root part. pos = fstart + wlen; // Skip if this is the word we are auto-completing. if (pos == caret) continue; // Get the rest of this word. TQString w(root); while (pos < dlen) { char ch = SendScintilla(SCI_GETCHARAT,pos); if (!isWordChar(ch)) break; w += ch; ++pos; } // Add the word if it isn't already there. if (wlist.findIndex(w) < 0) wlist.append(w); } } if ((acs == AcsAll || acs == AcsAPIs) && acAPIs) acAPIs->autoCompletionList(word, cs, wlist); delete []line; if (wlist.isEmpty()) return; wlist.sort(); const char sep = '\x03'; SendScintilla(SCI_AUTOCSETCHOOSESINGLE,single); SendScintilla(SCI_AUTOCSETSEPARATOR, sep); SendScintilla(SCI_AUTOCSHOW, wlen, wlist.join(TQChar(sep)).latin1()); } // Check if a character is an auto-completion start character. bool QextScintilla::isAutoCStartChar(char ch) const { const char *start_chars = 0; if (!lex.isNull()) start_chars = lex->autoCompletionStartCharacters(); if (!start_chars) start_chars = acStart; return (strchr(start_chars, ch) != NULL); } // Maintain the indentation of the previous line. void QextScintilla::maintainIndentation(char ch,long pos) { if (ch != '\r' && ch != '\n') return; int curr_line = SendScintilla(SCI_LINEFROMPOSITION,pos); // Get the indentation of the preceding non-zero length line. int ind = 0; for (int line = curr_line - 1; line >= 0; --line) { if (SendScintilla(SCI_GETLINEENDPOSITION,line) > SendScintilla(SCI_POSITIONFROMLINE,line)) { ind = indentation(line); break; } } if (ind > 0) autoIndentLine(pos,curr_line,ind); } // Implement auto-indentation. void QextScintilla::autoIndentation(char ch,long pos) { int curr_line = SendScintilla(SCI_LINEFROMPOSITION,pos); int ind_width = indentationWidth(); long curr_line_start = SendScintilla(SCI_POSITIONFROMLINE,curr_line); const char *block_start = lex -> blockStart(); bool start_single = (block_start && strlen(block_start) == 1); const char *block_end = lex -> blockEnd(); bool end_single = (block_end && strlen(block_end) == 1); if (end_single && block_end[0] == ch) { if ((lex -> autoIndentStyle() & AiClosing) && rangeIsWhitespace(curr_line_start,pos - 1)) autoIndentLine(pos,curr_line,blockIndent(curr_line - 1) - indentationWidth()); } else if (start_single && block_start[0] == ch) { // De-indent if we have already indented because the previous // line was a start of block keyword. if ((lex->autoIndentStyle() & AiOpening) && curr_line > 0 && getIndentState(curr_line - 1) == isKeywordStart && rangeIsWhitespace(curr_line_start, pos - 1)) autoIndentLine(pos,curr_line,blockIndent(curr_line - 1) - indentationWidth()); } else if (ch == '\r' || ch == '\n') autoIndentLine(pos,curr_line,blockIndent(curr_line - 1)); } // Set the indentation for a line. void QextScintilla::autoIndentLine(long pos,int line,int indent) { if (indent < 0) return; long pos_before = SendScintilla(SCI_GETLINEINDENTPOSITION,line); SendScintilla(SCI_SETLINEINDENTATION,line,indent); long pos_after = SendScintilla(SCI_GETLINEINDENTPOSITION,line); long new_pos = -1; if (pos_after > pos_before) new_pos = pos + (pos_after - pos_before); else if (pos_after < pos_before && pos >= pos_after) if (pos >= pos_before) new_pos = pos + (pos_after - pos_before); else new_pos = pos_after; if (new_pos >= 0) SendScintilla(SCI_SETSEL,new_pos,new_pos); } // Return the indentation of the block defined by the given line (or something // significant before). int QextScintilla::blockIndent(int line) { if (line < 0) return 0; // Handle the trvial case. if (!lex -> blockStartKeyword() && !lex -> blockStart() && !lex -> blockEnd()) return indentation(line); int line_limit = line - lex -> blockLookback(); if (line_limit < 0) line_limit = 0; for (int l = line; l >= line_limit; --l) { IndentState istate = getIndentState(l); if (istate != isNone) { int ind_width = indentationWidth(); int ind = indentation(l); if (istate == isBlockStart) { if (lex -> autoIndentStyle() & AiOpening) ind += ind_width; } else if (istate == isBlockEnd) { if (!(lex -> autoIndentStyle() & AiClosing)) ind -= ind_width; if (ind < 0) ind = 0; } else if (line == l) ind += ind_width; return ind; } } return indentation(line); } // Return TRUE if all characters starting at spos up to, but not including // epos, are spaces or tabs. bool QextScintilla::rangeIsWhitespace(long spos,long epos) { while (spos < epos) { char ch = SendScintilla(SCI_GETCHARAT,spos); if (ch != ' ' && ch != '\t') return FALSE; ++spos; } return TRUE; } // Returns the indentation state of a line. QextScintilla::IndentState QextScintilla::getIndentState(int line) { IndentState istate; // Get the styled text. long spos = SendScintilla(SCI_POSITIONFROMLINE,line); long epos = SendScintilla(SCI_POSITIONFROMLINE,line + 1); char *text = new char[(epos - spos + 1) * 2]; SendScintilla(SCI_GETSTYLEDTEXT,spos,epos,text); int style, bstart_off, bend_off; // Block start/end takes precedence over keywords. const char *bstart_words = lex->blockStart(&style); bstart_off = findStyledWord(text, style, bstart_words); const char *bend_words = lex->blockEnd(&style); bend_off = findStyledWord(text, style, bend_words); // If there is a block start but no block end characters then ignore it // unless the block start is the last significant thing on the line, // ie. assume Python-like blocking. if (bstart_off >= 0 && !bend_words) for (int i = bstart_off * 2; text[i] != '\0'; i += 2) if (!TQChar(text[i]).isSpace()) return isNone; if (bstart_off > bend_off) istate = isBlockStart; else if (bend_off > bstart_off) istate = isBlockEnd; else { const char *words = lex->blockStartKeyword(&style); istate = (findStyledWord(text,style,words) >= 0) ? isKeywordStart : isNone; } delete[] text; return istate; } // text is a pointer to some styled text (ie. a character byte followed by a // style byte). style is a style number. words is a space separated list of // words. Returns the position in the text immediately after the last one of // the words with the style. The reason we are after the last, and not the // first, occurance is that we are looking for words that start and end a block // where the latest one is the most significant. int QextScintilla::findStyledWord(const char *text,int style,const char *words) { if (!words) return -1; // Find the range of text with the style we are looking for. const char *stext; for (stext = text; stext[1] != style; stext += 2) if (stext[0] == '\0') return -1; // Move to the last character. const char *etext = stext; while (etext[2] != '\0') etext += 2; // Backtrack until we find the style. There will be one. while (etext[1] != style) etext -= 2; // Look for each word in turn. while (words[0] != '\0') { // Find the end of the word. const char *eword = words; while (eword[1] != ' ' && eword[1] != '\0') ++eword; // Now search the text backwards. const char *wp = eword; for (const char *tp = etext; tp >= stext; tp -= 2) { if (tp[0] != wp[0] || tp[1] != style) { // Reset the search. wp = eword; continue; } // See if all the word has matched. if (wp-- == words) return ((tp - text) / 2) + (eword - words) + 1; } // Move to the start of the next word if there is one. words = eword + 1; if (words[0] == ' ') ++words; } return -1; } // Return TRUE if the code page is UTF8. bool QextScintilla::isUtf8() { return (SendScintilla(SCI_GETCODEPAGE) == SC_CP_UTF8); } // Set the code page. void QextScintilla::setUtf8(bool cp) { SendScintilla(SCI_SETCODEPAGE,(cp ? SC_CP_UTF8 : 0)); } // Return the end-of-line mode. QextScintilla::EolMode QextScintilla::eolMode() { return (EolMode)SendScintilla(SCI_GETEOLMODE); } // Set the end-of-line mode. void QextScintilla::setEolMode(EolMode mode) { SendScintilla(SCI_SETEOLMODE,mode); } // Convert the end-of-lines to a particular mode. void QextScintilla::convertEols(EolMode mode) { SendScintilla(SCI_CONVERTEOLS,mode); } // Return the edge colour. TQColor QextScintilla::edgeColor() { long res = SendScintilla(SCI_GETEDGECOLOUR); return TQColor((int)res, ((int)(res >> 8)) & 0x00ff, ((int)(res >> 16)) & 0x00ff); } // Set the edge colour. void QextScintilla::setEdgeColor(const TQColor &col) { SendScintilla(SCI_SETEDGECOLOUR,col); } // Return the edge column. int QextScintilla::edgeColumn() { return SendScintilla(SCI_GETEDGECOLUMN); } // Set the edge column. void QextScintilla::setEdgeColumn(int colnr) { SendScintilla(SCI_SETEDGECOLUMN,colnr); } // Return the edge mode. QextScintilla::EdgeMode QextScintilla::edgeMode() { return (EdgeMode)SendScintilla(SCI_GETEDGEMODE); } // Set the edge mode. void QextScintilla::setEdgeMode(EdgeMode mode) { SendScintilla(SCI_SETEDGEMODE,mode); } // Return the end-of-line visibility. bool QextScintilla::eolVisibility() { return SendScintilla(SCI_GETVIEWEOL); } // Set the end-of-line visibility. void QextScintilla::setEolVisibility(bool visible) { SendScintilla(SCI_SETVIEWEOL,visible); } // Return the whitespace visibility. QextScintilla::WhitespaceVisibility QextScintilla::whitespaceVisibility() { return (WhitespaceVisibility)SendScintilla(SCI_GETVIEWWS); } // Set the whitespace visibility. void QextScintilla::setWhitespaceVisibility(WhitespaceVisibility mode) { SendScintilla(SCI_SETVIEWWS,mode); } // Return the line wrap mode. QextScintilla::WrapMode QextScintilla::wrapMode() { return (WrapMode)SendScintilla(SCI_GETWRAPMODE); } // Set the line wrap mode. void QextScintilla::setWrapMode(WrapMode mode) { SendScintilla(SCI_SETLAYOUTCACHE, (mode == WrapNone ? SC_CACHE_CARET : SC_CACHE_DOCUMENT)); SendScintilla(SCI_SETWRAPMODE, mode); } // Set the line wrap visual flags. void QextScintilla::setWrapVisualFlags(WrapVisualFlag eflag, WrapVisualFlag sflag, int sindent) { int flags = SC_WRAPVISUALFLAG_NONE; int loc = SC_WRAPVISUALFLAGLOC_DEFAULT; if (eflag == WrapFlagByText) { flags |= SC_WRAPVISUALFLAG_END; loc |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT; } else if (eflag == WrapFlagByBorder) flags |= SC_WRAPVISUALFLAG_END; if (sflag == WrapFlagByText) { flags |= SC_WRAPVISUALFLAG_START; loc |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT; } else if (sflag == WrapFlagByBorder) flags |= SC_WRAPVISUALFLAG_START; SendScintilla(SCI_SETWRAPVISUALFLAGS, flags); SendScintilla(SCI_SETWRAPVISUALFLAGSLOCATION, loc); SendScintilla(SCI_SETWRAPSTARTINDENT, sindent); } // Set the folding style. void QextScintilla::setFolding(FoldStyle folding) { fold = folding; if (folding == NoFoldStyle) { SendScintilla(SCI_SETMARGINWIDTHN,2,0L); return; } int mask = SendScintilla(SCI_GETMODEVENTMASK); SendScintilla(SCI_SETMODEVENTMASK,mask | SC_MOD_CHANGEFOLD); SendScintilla(SCI_SETFOLDFLAGS,SC_FOLDFLAG_LINEAFTER_CONTRACTED); SendScintilla(SCI_SETMARGINTYPEN,2,(long)SC_MARGIN_SYMBOL); SendScintilla(SCI_SETMARGINMASKN,2,SC_MASK_FOLDERS); SendScintilla(SCI_SETMARGINSENSITIVEN,2,1); // Set the marker symbols to use. switch (folding) { case PlainFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_MINUS); setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_PLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB); setFoldMarker(SC_MARKNUM_FOLDERTAIL); setFoldMarker(SC_MARKNUM_FOLDEREND); setFoldMarker(SC_MARKNUM_FOLDEROPENMID); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); break; case CircledFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_CIRCLEMINUS); setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_CIRCLEPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB); setFoldMarker(SC_MARKNUM_FOLDERTAIL); setFoldMarker(SC_MARKNUM_FOLDEREND); setFoldMarker(SC_MARKNUM_FOLDEROPENMID); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); break; case BoxedFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_BOXMINUS); setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_BOXPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB); setFoldMarker(SC_MARKNUM_FOLDERTAIL); setFoldMarker(SC_MARKNUM_FOLDEREND); setFoldMarker(SC_MARKNUM_FOLDEROPENMID); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); break; case CircledTreeFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_CIRCLEMINUS); setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_CIRCLEPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB,SC_MARK_VLINE); setFoldMarker(SC_MARKNUM_FOLDERTAIL,SC_MARK_LCORNERCURVE); setFoldMarker(SC_MARKNUM_FOLDEREND,SC_MARK_CIRCLEPLUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDEROPENMID,SC_MARK_CIRCLEMINUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL,SC_MARK_TCORNERCURVE); break; case BoxedTreeFoldStyle: setFoldMarker(SC_MARKNUM_FOLDEROPEN,SC_MARK_BOXMINUS); setFoldMarker(SC_MARKNUM_FOLDER,SC_MARK_BOXPLUS); setFoldMarker(SC_MARKNUM_FOLDERSUB,SC_MARK_VLINE); setFoldMarker(SC_MARKNUM_FOLDERTAIL,SC_MARK_LCORNER); setFoldMarker(SC_MARKNUM_FOLDEREND,SC_MARK_BOXPLUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDEROPENMID,SC_MARK_BOXMINUSCONNECTED); setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL,SC_MARK_TCORNER); break; } SendScintilla(SCI_SETMARGINWIDTHN,2,defaultFoldMarginWidth); } // Set up a folder marker. void QextScintilla::setFoldMarker(int marknr,int mark) { SendScintilla(SCI_MARKERDEFINE,marknr,mark); if (mark != SC_MARK_EMPTY) { SendScintilla(SCI_MARKERSETFORE,marknr,white); SendScintilla(SCI_MARKERSETBACK,marknr,black); } } // Handle a click in the fold margin. This is mostly taken from SciTE. void QextScintilla::foldClick(int lineClick,int bstate) { if ((bstate & ShiftButton) && (bstate & ControlButton)) { foldAll(); return; } int levelClick = SendScintilla(SCI_GETFOLDLEVEL,lineClick); if (levelClick & SC_FOLDLEVELHEADERFLAG) { if (bstate & ShiftButton) { // Ensure all children are visible. SendScintilla(SCI_SETFOLDEXPANDED,lineClick,1); foldExpand(lineClick,TRUE,TRUE,100,levelClick); } else if (bstate & ControlButton) { if (SendScintilla(SCI_GETFOLDEXPANDED,lineClick)) { // Contract this line and all its children. SendScintilla(SCI_SETFOLDEXPANDED,lineClick,0L); foldExpand(lineClick,FALSE,TRUE,0,levelClick); } else { // Expand this line and all its children. SendScintilla(SCI_SETFOLDEXPANDED,lineClick,1); foldExpand(lineClick,TRUE,TRUE,100,levelClick); } } else { // Toggle this line. SendScintilla(SCI_TOGGLEFOLD,lineClick); } } } // Do the hard work of hiding and showing lines. This is mostly taken from // SciTE. void QextScintilla::foldExpand(int &line,bool doExpand,bool force, int visLevels,int level) { int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD,line,level & SC_FOLDLEVELNUMBERMASK); line++; while (line <= lineMaxSubord) { if (force) { if (visLevels > 0) SendScintilla(SCI_SHOWLINES,line,line); else SendScintilla(SCI_HIDELINES,line,line); } else if (doExpand) SendScintilla(SCI_SHOWLINES,line,line); int levelLine = level; if (levelLine == -1) levelLine = SendScintilla(SCI_GETFOLDLEVEL,line); if (levelLine & SC_FOLDLEVELHEADERFLAG) { if (force) { if (visLevels > 1) SendScintilla(SCI_SETFOLDEXPANDED,line,1); else SendScintilla(SCI_SETFOLDEXPANDED,line,0L); foldExpand(line,doExpand,force,visLevels - 1); } else if (doExpand) { if (!SendScintilla(SCI_GETFOLDEXPANDED,line)) SendScintilla(SCI_SETFOLDEXPANDED,line,1); foldExpand(line,TRUE,force,visLevels - 1); } else foldExpand(line,FALSE,force,visLevels - 1); } else line++; } } // Fully expand (if there is any line currently folded) all text. Otherwise, // fold all text. This is mostly taken from SciTE. void QextScintilla::foldAll(bool children) { recolor(); int maxLine = SendScintilla(SCI_GETLINECOUNT); bool expanding = TRUE; for (int lineSeek = 0; lineSeek < maxLine; lineSeek++) { if (SendScintilla(SCI_GETFOLDLEVEL,lineSeek) & SC_FOLDLEVELHEADERFLAG) { expanding = !SendScintilla(SCI_GETFOLDEXPANDED,lineSeek); break; } } for (int line = 0; line < maxLine; line++) { int level = SendScintilla(SCI_GETFOLDLEVEL,line); if (!(level & SC_FOLDLEVELHEADERFLAG)) continue; if (children || (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK))) { if (expanding) { SendScintilla(SCI_SETFOLDEXPANDED,line,1); foldExpand(line,TRUE,FALSE,0,level); line--; } else { int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD,line,-1); SendScintilla(SCI_SETFOLDEXPANDED,line,0L); if (lineMaxSubord > line) SendScintilla(SCI_HIDELINES,line + 1,lineMaxSubord); } } } } // Handle a fold change. This is mostly taken from SciTE. void QextScintilla::foldChanged(int line,int levelNow,int levelPrev) { if (levelNow & SC_FOLDLEVELHEADERFLAG) { if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) SendScintilla(SCI_SETFOLDEXPANDED,line,1); } else if (levelPrev & SC_FOLDLEVELHEADERFLAG) { if (!SendScintilla(SCI_GETFOLDEXPANDED,line)) { // Removing the fold from one that has been contracted // so should expand. Otherwise lines are left // invisible with no way to make them visible. foldExpand(line,TRUE,FALSE,0,levelPrev); } } } // Toggle the fold for a line if it contains a fold marker. void QextScintilla::foldLine(int line) { SendScintilla(SCI_TOGGLEFOLD,line); } // Handle the SCN_MODIFIED notification. void QextScintilla::handleModified(int pos,int mtype,const char *text,int len, int added,int line,int foldNow,int foldPrev) { if (mtype & SC_MOD_CHANGEFOLD) { if (fold) foldChanged(line,foldNow,foldPrev); } else if (mtype & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) emit textChanged(); } // Zoom in a number of points. void QextScintilla::zoomIn(int range) { zoomTo(SendScintilla(SCI_GETZOOM) + range); } // Zoom in a single point. void QextScintilla::zoomIn() { SendScintilla(SCI_ZOOMIN); } // Zoom out a number of points. void QextScintilla::zoomOut(int range) { zoomTo(SendScintilla(SCI_GETZOOM) - range); } // Zoom out a single point. void QextScintilla::zoomOut() { SendScintilla(SCI_ZOOMOUT); } // Set the zoom to a number of points. void QextScintilla::zoomTo(int size) { if (size < -10) size = -10; else if (size > 20) size = 20; SendScintilla(SCI_SETZOOM,size); } // Find the first occurrence of a string. bool QextScintilla::findFirst(const TQString &expr,bool re,bool cs,bool wo, bool wrap,bool forward,int line,int index, bool show) { findState.inProgress = FALSE; if (expr.isEmpty()) return FALSE; findState.expr = expr; findState.wrap = wrap; findState.forward = forward; findState.flags = (cs ? SCFIND_MATCHCASE : 0) | (wo ? SCFIND_WHOLEWORD : 0) | (re ? SCFIND_REGEXP : 0); if (line < 0 || index < 0) findState.startpos = SendScintilla(SCI_GETCURRENTPOS); else findState.startpos = posFromLineIndex(line,index); if (forward) findState.endpos = SendScintilla(SCI_GETLENGTH); else findState.endpos = 0; findState.show = show; return doFind(); } // Find the next occurrence of a string. bool QextScintilla::findNext() { if (!findState.inProgress) return FALSE; return doFind(); } // Do the hard work of findFirst() and findNext(). bool QextScintilla::doFind() { SendScintilla(SCI_SETSEARCHFLAGS,findState.flags); long pos = simpleFind(); // See if it was found. If not and wraparound is wanted, try again. if (pos == -1 && findState.wrap) { if (findState.forward) { findState.startpos = 0; findState.endpos = SendScintilla(SCI_GETLENGTH); } else { findState.startpos = SendScintilla(SCI_GETLENGTH); findState.endpos = 0; } pos = simpleFind(); } if (pos == -1) { findState.inProgress = FALSE; return FALSE; } // It was found. long targstart = SendScintilla(SCI_GETTARGETSTART); long targend = SendScintilla(SCI_GETTARGETEND); // Ensure the text found is visible if required. if (findState.show) { int startLine = SendScintilla(SCI_LINEFROMPOSITION,targstart); int endLine = SendScintilla(SCI_LINEFROMPOSITION,targend); for (int i = startLine; i <= endLine; ++i) SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY,i); } // Now set the selection. SendScintilla(SCI_SETSEL,targstart,targend); // Finally adjust the start position so that we don't find the same one // again. if (findState.forward) findState.startpos = targend; else if ((findState.startpos = targstart - 1) < 0) findState.startpos = 0; findState.inProgress = TRUE; return TRUE; } // Do a simple find between the start and end positions. long QextScintilla::simpleFind() { if (findState.startpos == findState.endpos) return -1; SendScintilla(SCI_SETTARGETSTART,findState.startpos); SendScintilla(SCI_SETTARGETEND,findState.endpos); long pos; if (isUtf8()) { TQCString s = findState.expr.utf8(); pos = SendScintilla(SCI_SEARCHINTARGET,s.length(),s.data()); } else { const char *s = findState.expr.latin1(); pos = SendScintilla(SCI_SEARCHINTARGET,strlen(s),s); } return pos; } // Replace the text found with the previous findFirst() or findNext(). void QextScintilla::replace(const TQString &replaceStr) { if (!findState.inProgress) return; long start = SendScintilla(SCI_GETSELECTIONSTART); SendScintilla(SCI_TARGETFROMSELECTION); long len; int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET; if (isUtf8()) len = SendScintilla(cmd,-1,replaceStr.utf8().data()); else len = SendScintilla(cmd,-1,replaceStr.latin1()); // Reset the selection. SendScintilla(SCI_SETSELECTIONSTART,start); SendScintilla(SCI_SETSELECTIONEND,start + len); if (findState.forward) findState.startpos = start + len; } // Query the modified state. bool QextScintilla::isModified() { // We don't use SCI_GETMODIFY as it seems to be buggy in Scintilla // v1.61. return modified; } // Set the modified state. void QextScintilla::setModified(bool m) { if (!m) SendScintilla(SCI_SETSAVEPOINT); } // Handle the SCN_MARGINCLICK notification. void QextScintilla::handleMarginClick(int pos,int modifiers,int margin) { int state = 0; if (modifiers & SCMOD_SHIFT) state |= ShiftButton; if (modifiers & SCMOD_CTRL) state |= ControlButton; if (modifiers & SCMOD_ALT) state |= AltButton; int line = SendScintilla(SCI_LINEFROMPOSITION,pos); if (fold && margin == 2) foldClick(line,state); else emit marginClicked(margin,line,(ButtonState)state); } // Handle the SCN_SAVEPOINTREACHED notification. void QextScintilla::handleSavePointReached() { if (modified) { modified = FALSE; emit modificationChanged(FALSE); } } // Handle the SCN_SAVEPOINTLEFT notification. void QextScintilla::handleSavePointLeft() { if (!modified) { modified = TRUE; emit modificationChanged(TRUE); } } // Handle the TQSCN_SELCHANGED signal. void QextScintilla::handleSelectionChanged(bool yes) { selText = yes; emit copyAvailable(yes); emit selectionChanged(); } // Get the current selection. void QextScintilla::getSelection(int *lineFrom,int *indexFrom, int *lineTo,int *indexTo) { if (selText) { lineIndexFromPos(SendScintilla(SCI_GETSELECTIONSTART), lineFrom,indexFrom); lineIndexFromPos(SendScintilla(SCI_GETSELECTIONEND), lineTo,indexTo); } else *lineFrom = *indexFrom = *lineTo = *indexTo = -1; } // Sets the current selection. void QextScintilla::setSelection(int lineFrom,int indexFrom, int lineTo,int indexTo) { SendScintilla(SCI_SETSELECTIONSTART,posFromLineIndex(lineFrom,indexFrom)); SendScintilla(SCI_SETSELECTIONEND,posFromLineIndex(lineTo,indexTo)); } // Set the background colour of selected text. void QextScintilla::setSelectionBackgroundColor(const TQColor &col) { SendScintilla(SCI_SETSELBACK,1,col); int alpha = tqAlpha(col.rgb()); if (alpha < 255) SendScintilla(SCI_SETSELALPHA, alpha); } // Set the foreground colour of selected text. void QextScintilla::setSelectionForegroundColor(const TQColor &col) { SendScintilla(SCI_SETSELFORE,1,col); } // Reset the background colour of selected text to the default. void QextScintilla::resetSelectionBackgroundColor() { SendScintilla(SCI_SETSELALPHA, SC_ALPHA_NOALPHA); SendScintilla(SCI_SETSELBACK,0UL); } // Reset the foreground colour of selected text to the default. void QextScintilla::resetSelectionForegroundColor() { SendScintilla(SCI_SETSELFORE,0UL); } // Set the width of the caret. void QextScintilla::setCaretWidth(int width) { SendScintilla(SCI_SETCARETWIDTH,width); } // Set the foreground colour of the caret. void QextScintilla::setCaretForegroundColor(const TQColor &col) { SendScintilla(SCI_SETCARETFORE,col); } // Set the background colour of the line containing the caret. void QextScintilla::setCaretLineBackgroundColor(const TQColor &col) { SendScintilla(SCI_SETCARETLINEBACK,col); int alpha = tqAlpha(col.rgb()); if (alpha < 255) SendScintilla(SCI_SETCARETLINEBACKALPHA, alpha); } // Set the state of the background colour of the line containing the caret. void QextScintilla::setCaretLineVisible(bool enable) { SendScintilla(SCI_SETCARETLINEVISIBLE,enable); } // Query the read-only state. bool QextScintilla::isReadOnly() { return SendScintilla(SCI_GETREADONLY); } // Set the read-only state. void QextScintilla::setReadOnly(bool ro) { SendScintilla(SCI_SETREADONLY,ro); } // Append the given text. void QextScintilla::append(const TQString &text) { bool ro = ensureRW(); if (isUtf8()) { TQCString s = text.utf8(); SendScintilla(SCI_APPENDTEXT,s.length(),s.data()); } else { const char *s = text.latin1(); SendScintilla(SCI_APPENDTEXT,strlen(s),s); } SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Insert the given text at the current position. void QextScintilla::insert(const TQString &text) { bool ro = ensureRW(); SendScintilla(SCI_BEGINUNDOACTION); if (isUtf8()) SendScintilla(SCI_INSERTTEXT,-1,text.utf8().data()); else SendScintilla(SCI_INSERTTEXT,-1,text.latin1()); SendScintilla(SCI_ENDUNDOACTION); setReadOnly(ro); } // Insert the given text at the given position. void QextScintilla::insertAt(const TQString &text,int line,int index) { bool ro = ensureRW(); long position = posFromLineIndex(line,index); SendScintilla(SCI_BEGINUNDOACTION); if (isUtf8()) SendScintilla(SCI_INSERTTEXT,position,text.utf8().data()); else SendScintilla(SCI_INSERTTEXT,position,text.latin1()); SendScintilla(SCI_ENDUNDOACTION); setReadOnly(ro); } // Begin a sequence of undoable actions. void QextScintilla::beginUndoAction() { SendScintilla(SCI_BEGINUNDOACTION); } // End a sequence of undoable actions. void QextScintilla::endUndoAction() { SendScintilla(SCI_ENDUNDOACTION); } // Redo a sequence of actions. void QextScintilla::redo() { SendScintilla(SCI_REDO); } // Undo a sequence of actions. void QextScintilla::undo() { SendScintilla(SCI_UNDO); } // See if there is something to redo. bool QextScintilla::isRedoAvailable() { return SendScintilla(SCI_CANREDO); } // See if there is something to undo. bool QextScintilla::isUndoAvailable() { return SendScintilla(SCI_CANUNDO); } // Return the number of lines. int QextScintilla::lines() { return SendScintilla(SCI_GETLINECOUNT); } // Return the line at a position. int QextScintilla::lineAt(const TQPoint &pos) { long chpos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE,pos.x(),pos.y()); if (chpos < 0) return -1; return SendScintilla(SCI_LINEFROMPOSITION,chpos); } // Return the length of a line. int QextScintilla::lineLength(int line) { if (line < 0 || line >= SendScintilla(SCI_GETLINECOUNT)) return -1; return SendScintilla(SCI_LINELENGTH,line); } // Return the length of the current text. int QextScintilla::length() { return SendScintilla(SCI_GETTEXTLENGTH); } // Remove any selected text. void QextScintilla::removeSelectedText() { SendScintilla(SCI_REPLACESEL,""); } // Return the current selected text. TQString QextScintilla::selectedText() { if (!selText) return TQString(); // Scintilla doesn't tell us the length of the selected text so we use // the length of the whole document. char *buf = new char[length() + 1]; SendScintilla(SCI_GETSELTEXT,buf); TQString qs = convertText(buf); delete[] buf; return qs; } // Return the current text. TQString QextScintilla::text() { int buflen = length() + 1; char *buf = new char[buflen]; SendScintilla(SCI_GETTEXT,buflen,buf); TQString qs = convertText(buf); delete[] buf; return qs; } // Return the text of a line. TQString QextScintilla::text(int line) { int line_len = lineLength(line); if (line_len < 1) return TQString(); char *buf = new char[line_len + 1]; SendScintilla(SCI_GETLINE,line,buf); buf[line_len] = '\0'; TQString qs = convertText(buf); delete[] buf; return qs; } // Set the given text. void QextScintilla::setText(const TQString &text) { bool ro = ensureRW(); if (isUtf8()) SendScintilla(SCI_SETTEXT,text.utf8().data()); else SendScintilla(SCI_SETTEXT,text.latin1()); SendScintilla(SCI_EMPTYUNDOBUFFER); setReadOnly(ro); } // Get the cursor position void QextScintilla::getCursorPosition(int *line,int *index) { long pos = SendScintilla(SCI_GETCURRENTPOS); long lin = SendScintilla(SCI_LINEFROMPOSITION,pos); long linpos = SendScintilla(SCI_POSITIONFROMLINE,lin); *line = lin; *index = pos - linpos; } // Set the cursor position void QextScintilla::setCursorPosition(int line,int index) { SendScintilla(SCI_GOTOPOS,posFromLineIndex(line,index)); } // Ensure the cursor is visible. void QextScintilla::ensureCursorVisible() { SendScintilla(SCI_SCROLLCARET); } // Ensure a line is visible. void QextScintilla::ensureLineVisible(int line) { SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY,line); } // Copy text to the clipboard. void QextScintilla::copy() { SendScintilla(SCI_COPY); } // Cut text to the clipboard. void QextScintilla::cut() { SendScintilla(SCI_CUT); } // Paste text from the clipboard. void QextScintilla::paste() { SendScintilla(SCI_PASTE); } // Select all text, or deselect any selected text. void QextScintilla::selectAll(bool select) { if (selText) SendScintilla(SCI_SETANCHOR,SendScintilla(SCI_GETCURRENTPOS)); else SendScintilla(SCI_SELECTALL); } // Delete all text. void QextScintilla::clear() { bool ro = ensureRW(); SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_CLEARALL); SendScintilla(SCI_ENDUNDOACTION); setReadOnly(ro); } // Return the indentation of a line. int QextScintilla::indentation(int line) { return SendScintilla(SCI_GETLINEINDENTATION,line); } // Set the indentation of a line. void QextScintilla::setIndentation(int line,int indentation) { SendScintilla(SCI_BEGINUNDOACTION); SendScintilla(SCI_SETLINEINDENTATION,line,indentation); SendScintilla(SCI_ENDUNDOACTION); } // Indent a line. void QextScintilla::indent(int line) { setIndentation(line,indentation(line) + indentWidth()); } // Unindent a line. void QextScintilla::unindent(int line) { int newIndent = indentation(line) - indentWidth(); if (newIndent < 0) newIndent = 0; setIndentation(line,newIndent); } // Return the indentation of the current line. int QextScintilla::currentIndent() { return indentation(SendScintilla(SCI_LINEFROMPOSITION,SendScintilla(SCI_GETCURRENTPOS))); } // Return the current indentation width. int QextScintilla::indentWidth() { int w = indentationWidth(); if (w == 0) w = tabWidth(); return w; } // Return the state of indentation guides. bool QextScintilla::indentationGuides() { return SendScintilla(SCI_GETINDENTATIONGUIDES); } // Enable and disable indentation guides. void QextScintilla::setIndentationGuides(bool enable) { SendScintilla(SCI_SETINDENTATIONGUIDES,enable); } // Set the background colour of indentation guides. void QextScintilla::setIndentationGuidesBackgroundColor(const TQColor &col) { SendScintilla(SCI_STYLESETBACK,STYLE_INDENTGUIDE,col); } // Set the foreground colour of indentation guides. void QextScintilla::setIndentationGuidesForegroundColor(const TQColor &col) { SendScintilla(SCI_STYLESETFORE,STYLE_INDENTGUIDE,col); } // Return the indentation width. int QextScintilla::indentationWidth() { return SendScintilla(SCI_GETINDENT); } // Set the indentation width. void QextScintilla::setIndentationWidth(int width) { SendScintilla(SCI_SETINDENT,width); } // Return the tab width. int QextScintilla::tabWidth() { return SendScintilla(SCI_GETTABWIDTH); } // Set the tab width. void QextScintilla::setTabWidth(int width) { SendScintilla(SCI_SETTABWIDTH,width); } // Return the effect of the backspace key. bool QextScintilla::backspaceUnindents() { return SendScintilla(SCI_GETBACKSPACEUNINDENTS); } // Set the effect of the backspace key. void QextScintilla::setBackspaceUnindents(bool unindents) { SendScintilla(SCI_SETBACKSPACEUNINDENTS,unindents); } // Return the effect of the tab key. bool QextScintilla::tabIndents() { return SendScintilla(SCI_GETTABINDENTS); } // Set the effect of the tab key. void QextScintilla::setTabIndents(bool indents) { SendScintilla(SCI_SETTABINDENTS,indents); } // Return the indentation use of tabs. bool QextScintilla::indentationsUseTabs() { return SendScintilla(SCI_GETUSETABS); } // Set the indentation use of tabs. void QextScintilla::setIndentationsUseTabs(bool tabs) { SendScintilla(SCI_SETUSETABS,tabs); } // Return the state of line numbers in a margin. bool QextScintilla::marginLineNumbers(int margin) { return SendScintilla(SCI_GETMARGINTYPEN,margin); } // Enable and disable line numbers in a margin. void QextScintilla::setMarginLineNumbers(int margin,bool lnrs) { SendScintilla(SCI_SETMARGINTYPEN,margin,lnrs ? SC_MARGIN_NUMBER : 0); } // Return the marker mask of a margin. int QextScintilla::marginMarkerMask(int margin) { return SendScintilla(SCI_GETMARGINMASKN,margin); } // Set the marker mask of a margin. void QextScintilla::setMarginMarkerMask(int margin,int mask) { SendScintilla(SCI_SETMARGINMASKN,margin,mask); } // Return the state of a margin's sensitivity. bool QextScintilla::marginSensitivity(int margin) { return SendScintilla(SCI_GETMARGINSENSITIVEN,margin); } // Enable and disable a margin's sensitivity. void QextScintilla::setMarginSensitivity(int margin,bool sens) { SendScintilla(SCI_SETMARGINSENSITIVEN,margin,sens); } // Return the width of a margin. int QextScintilla::marginWidth(int margin) { return SendScintilla(SCI_GETMARGINWIDTHN,margin); } // Set the width of a margin. void QextScintilla::setMarginWidth(int margin,int width) { SendScintilla(SCI_SETMARGINWIDTHN,margin,width); } // Set the width of a margin to the width of some text. void QextScintilla::setMarginWidth(int margin,const TQString &s) { int width; if (isUtf8()) width = SendScintilla(SCI_TEXTWIDTH,STYLE_LINENUMBER,s.utf8().data()); else width = SendScintilla(SCI_TEXTWIDTH,STYLE_LINENUMBER,s.latin1()); setMarginWidth(margin,width); } // Set the background colour of all margins. void QextScintilla::setMarginsBackgroundColor(const TQColor &col) { handleStylePaperChange(col,STYLE_LINENUMBER); } // Set the foreground colour of all margins. void QextScintilla::setMarginsForegroundColor(const TQColor &col) { handleStyleColorChange(col,STYLE_LINENUMBER); } // Set the font of all margins. void QextScintilla::setMarginsFont(const TQFont &f) { setStylesFont(f,STYLE_LINENUMBER); } // Define a marker based on a symbol. int QextScintilla::markerDefine(MarkerSymbol sym,int mnr) { checkMarker(mnr); if (mnr >= 0) SendScintilla(SCI_MARKERDEFINE,mnr,static_cast(sym)); return mnr; } // Define a marker based on a character. int QextScintilla::markerDefine(char ch,int mnr) { checkMarker(mnr); if (mnr >= 0) SendScintilla(SCI_MARKERDEFINE,mnr,static_cast(SC_MARK_CHARACTER) + ch); return mnr; } // Define a marker based on a TQPixmap. int QextScintilla::markerDefine(const TQPixmap *pm,int mnr) { checkMarker(mnr); if (mnr >= 0) SendScintilla(SCI_MARKERDEFINEPIXMAP,mnr,pm); return mnr; } // Add a marker to a line. int QextScintilla::markerAdd(int linenr,int mnr) { if (mnr < 0 || mnr > MARKER_MAX || (allocatedMarkers & (1 << mnr)) == 0) return -1; return SendScintilla(SCI_MARKERADD,linenr,mnr); } // Get the marker mask for a line. unsigned QextScintilla::markersAtLine(int linenr) { return SendScintilla(SCI_MARKERGET,linenr); } // Delete a marker from a line. void QextScintilla::markerDelete(int linenr,int mnr) { if (mnr <= MARKER_MAX) { if (mnr < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) SendScintilla(SCI_MARKERDELETE,linenr,m); am >>= 1; } } else if (allocatedMarkers & (1 << mnr)) SendScintilla(SCI_MARKERDELETE,linenr,mnr); } } // Delete a marker from the text. void QextScintilla::markerDeleteAll(int mnr) { if (mnr <= MARKER_MAX) { if (mnr < 0) SendScintilla(SCI_MARKERDELETEALL,-1); else if (allocatedMarkers & (1 << mnr)) SendScintilla(SCI_MARKERDELETEALL,mnr); } } // Delete a marker handle from the text. void QextScintilla::markerDeleteHandle(int mhandle) { SendScintilla(SCI_MARKERDELETEHANDLE,mhandle); } // Return the line containing a marker instance. int QextScintilla::markerLine(int mhandle) { return SendScintilla(SCI_MARKERLINEFROMHANDLE,mhandle); } // Search forwards for a marker. int QextScintilla::markerFindNext(int linenr,unsigned mask) { return SendScintilla(SCI_MARKERNEXT,linenr,mask); } // Search backwards for a marker. int QextScintilla::markerFindPrevious(int linenr,unsigned mask) { return SendScintilla(SCI_MARKERPREVIOUS,linenr,mask); } // Set the marker background colour. void QextScintilla::setMarkerBackgroundColor(const TQColor &col,int mnr) { if (mnr <= MARKER_MAX) { int alpha = tqAlpha(col.rgb()); if (mnr < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) { SendScintilla(SCI_MARKERSETBACK,m,col); if (alpha < 255) SendScintilla(SCI_MARKERSETALPHA, m, alpha); } am >>= 1; } } else if (allocatedMarkers & (1 << mnr)) { SendScintilla(SCI_MARKERSETBACK,mnr,col); if (alpha < 255) SendScintilla(SCI_MARKERSETALPHA, mnr, alpha); } } } // Set the marker foreground colour. void QextScintilla::setMarkerForegroundColor(const TQColor &col,int mnr) { if (mnr <= MARKER_MAX) { if (mnr < 0) { unsigned am = allocatedMarkers; for (int m = 0; m <= MARKER_MAX; ++m) { if (am & 1) SendScintilla(SCI_MARKERSETFORE,m,col); am >>= 1; } } else if (allocatedMarkers & (1 << mnr)) SendScintilla(SCI_MARKERSETFORE,mnr,col); } } // Check a marker, allocating a marker number if necessary. void QextScintilla::checkMarker(int &mnr) { if (mnr >= 0) { // Check the explicit marker number isn't already allocated. if (mnr > MARKER_MAX || allocatedMarkers & (1 << mnr)) mnr = -1; } else { unsigned am = allocatedMarkers; // Find the smallest unallocated marker number. for (mnr = 0; mnr <= MARKER_MAX; ++mnr) { if ((am & 1) == 0) break; am >>= 1; } } // Define the marker if it is valid. if (mnr >= 0) allocatedMarkers |= (1 << mnr); } // Reset the fold margin colours. void QextScintilla::resetFoldMarginColors() { SendScintilla(SCI_SETFOLDMARGINHICOLOUR,0,0L); SendScintilla(SCI_SETFOLDMARGINCOLOUR,0,0L); } // Set the fold margin colours. void QextScintilla::setFoldMarginColors(const TQColor &fore,const TQColor &back) { SendScintilla(SCI_SETFOLDMARGINHICOLOUR,1,fore); SendScintilla(SCI_SETFOLDMARGINCOLOUR,1,back); } // Set the call tips background colour. void QextScintilla::setCallTipsBackgroundColor(const TQColor &col) { SendScintilla(SCI_CALLTIPSETBACK,col); } // Set the call tips foreground colour. void QextScintilla::setCallTipsForegroundColor(const TQColor &col) { SendScintilla(SCI_CALLTIPSETFORE,col); } // Set the call tips highlight colour. void QextScintilla::setCallTipsHighlightColor(const TQColor &col) { SendScintilla(SCI_CALLTIPSETFOREHLT,col); } // Set the matched brace background colour. void QextScintilla::setMatchedBraceBackgroundColor(const TQColor &col) { SendScintilla(SCI_STYLESETBACK,STYLE_BRACELIGHT,col); } // Set the matched brace foreground colour. void QextScintilla::setMatchedBraceForegroundColor(const TQColor &col) { SendScintilla(SCI_STYLESETFORE,STYLE_BRACELIGHT,col); } // Set the unmatched brace background colour. void QextScintilla::setUnmatchedBraceBackgroundColor(const TQColor &col) { SendScintilla(SCI_STYLESETBACK,STYLE_BRACEBAD,col); } // Set the unmatched brace foreground colour. void QextScintilla::setUnmatchedBraceForegroundColor(const TQColor &col) { SendScintilla(SCI_STYLESETFORE,STYLE_BRACEBAD,col); } // Set the lexer. void QextScintilla::setLexer(QextScintillaLexer *lexer) { // Disconnect any previous lexer. if (!lex.isNull()) { lex -> disconnect(this); SendScintilla(SCI_STYLERESETDEFAULT); } // Connect up the new lexer. lex = lexer; if (lex) { int bits = SendScintilla(SCI_GETSTYLEBITSNEEDED); int nrStyles = 1 << bits; SendScintilla(SCI_SETSTYLEBITS,bits); connect(lex,TQT_SIGNAL(colorChanged(const TQColor &,int)), TQT_SLOT(handleStyleColorChange(const TQColor &,int))); connect(lex,TQT_SIGNAL(eolFillChanged(bool,int)), TQT_SLOT(handleStyleEolFillChange(bool,int))); connect(lex,TQT_SIGNAL(fontChanged(const TQFont &,int)), TQT_SLOT(handleStyleFontChange(const TQFont &,int))); connect(lex,TQT_SIGNAL(paperChanged(const TQColor &,int)), TQT_SLOT(handleStylePaperChange(const TQColor &,int))); connect(lex,TQT_SIGNAL(propertyChanged(const char *,const char *)), TQT_SLOT(handlePropertyChange(const char *,const char *))); SendScintilla(SCI_SETLEXERLANGUAGE,lex -> lexer()); // Set the keywords. Scintilla allows for sets numbered 0 to // KEYWORDSET_MAX (although the lexers only seem to exploit 0 // to KEYWORDSET_MAX - 1). We number from 1 in line with // SciTE's property files. for (int k = 0; k <= KEYWORDSET_MAX; ++k) { const char *kw = lex -> keywords(k + 1); if (kw) SendScintilla(SCI_SETKEYWORDS,k,kw); } // Initialise each style. for (int s = 0; s < nrStyles; ++s) { if (lex -> description(s).isNull()) continue; handleStyleColorChange(lex -> color(s),s); handleStyleEolFillChange(lex -> eolFill(s),s); handleStyleFontChange(lex -> font(s),s); handleStylePaperChange(lex -> paper(s),s); } // Initialise the properties. lex -> refreshProperties(); // Set the auto-completion fillups if they haven't been // explcitly set. if (fillups_enabled && !explicit_fillups) SendScintilla(SCI_AUTOCSETFILLUPS, lex->autoCompletionFillups()); } else { SendScintilla(SCI_SETLEXER,SCLEX_NULL); setColor(nl_text_colour); setPaper(nl_paper_colour); setFont(nl_font); } } // Get the current lexer. QextScintillaLexer *QextScintilla::lexer() const { return lex; } // Handle a change in lexer style foreground colour. void QextScintilla::handleStyleColorChange(const TQColor &c,int style) { SendScintilla(SCI_STYLESETFORE,style,c); } // Handle a change in lexer style end-of-line fill. void QextScintilla::handleStyleEolFillChange(bool eolfill,int style) { SendScintilla(SCI_STYLESETEOLFILLED,style,eolfill); } // Handle a change in lexer style font. void QextScintilla::handleStyleFontChange(const TQFont &f,int style) { setStylesFont(f,style); if (style == lex->defaultStyle()) setStylesFont(f, STYLE_DEFAULT); if (style == lex -> braceStyle()) { setStylesFont(f,STYLE_BRACELIGHT); setStylesFont(f,STYLE_BRACEBAD); } } // Set the font for a style. void QextScintilla::setStylesFont(const TQFont &f,int style) { SendScintilla(SCI_STYLESETFONT,style,f.family().latin1()); SendScintilla(SCI_STYLESETSIZE,style,f.pointSize()); SendScintilla(SCI_STYLESETBOLD,style,f.bold()); SendScintilla(SCI_STYLESETITALIC,style,f.italic()); SendScintilla(SCI_STYLESETUNDERLINE,style,f.underline()); } // Handle a change in lexer style background colour. void QextScintilla::handleStylePaperChange(const TQColor &c,int style) { SendScintilla(SCI_STYLESETBACK,style,c); } // Handle a change in lexer property. void QextScintilla::handlePropertyChange(const char *prop,const char *val) { SendScintilla(SCI_SETPROPERTY,prop,val); } // Handle a change to the user visible user interface. void QextScintilla::handleUpdateUI() { long newPos = SendScintilla(SCI_GETCURRENTPOS); if (newPos != oldPos) { oldPos = newPos; int line = SendScintilla(SCI_LINEFROMPOSITION,newPos); int col = SendScintilla(SCI_GETCOLUMN,newPos); emit cursorPositionChanged(line,col); } if (braceMode != NoBraceMatch) braceMatch(); } // Handle brace matching. void QextScintilla::braceMatch() { long braceAtCaret, braceOpposite; findMatchingBrace(braceAtCaret,braceOpposite,braceMode); if (braceAtCaret >= 0 && braceOpposite < 0) { SendScintilla(SCI_BRACEBADLIGHT,braceAtCaret); SendScintilla(SCI_SETHIGHLIGHTGUIDE,0UL); } else { char chBrace = SendScintilla(SCI_GETCHARAT,braceAtCaret); SendScintilla(SCI_BRACEHIGHLIGHT,braceAtCaret,braceOpposite); long columnAtCaret = SendScintilla(SCI_GETCOLUMN,braceAtCaret); long columnOpposite = SendScintilla(SCI_GETCOLUMN,braceOpposite); if (chBrace == ':') { long lineStart = SendScintilla(SCI_LINEFROMPOSITION,braceAtCaret); long indentPos = SendScintilla(SCI_GETLINEINDENTPOSITION,lineStart); long indentPosNext = SendScintilla(SCI_GETLINEINDENTPOSITION,lineStart + 1); columnAtCaret = SendScintilla(SCI_GETCOLUMN,indentPos); long columnAtCaretNext = SendScintilla(SCI_GETCOLUMN,indentPosNext); long indentSize = SendScintilla(SCI_GETINDENT); if (columnAtCaretNext - indentSize > 1) columnAtCaret = columnAtCaretNext - indentSize; if (columnOpposite == 0) columnOpposite = columnAtCaret; } long column = columnAtCaret; if (column > columnOpposite) column = columnOpposite; SendScintilla(SCI_SETHIGHLIGHTGUIDE,column); } } // Check if the character at a position is a brace. long QextScintilla::checkBrace(long pos,int brace_style,bool &colonMode) { long brace_pos = -1; char ch = SendScintilla(SCI_GETCHARAT,pos); if (ch == ':') { // A bit of a hack. if (!lex.isNull() && strcmp(lex -> lexer(),"python") == 0) { brace_pos = pos; colonMode = TRUE; } } else if (ch && strchr("[](){}<>",ch)) { if (brace_style < 0) brace_pos = pos; else { int style = SendScintilla(SCI_GETSTYLEAT,pos) & 0x1f; if (style == brace_style) brace_pos = pos; } } return brace_pos; } // Find a brace and it's match. Return TRUE if the current position is inside // a pair of braces. bool QextScintilla::findMatchingBrace(long &brace,long &other,BraceMatch mode) { bool colonMode = FALSE; int brace_style = (lex.isNull() ? -1 : lex -> braceStyle()); brace = -1; other = -1; long caretPos = SendScintilla(SCI_GETCURRENTPOS); if (caretPos > 0) brace = checkBrace(caretPos - 1,brace_style,colonMode); bool isInside = FALSE; if (brace < 0 && mode == SloppyBraceMatch) { brace = checkBrace(caretPos,brace_style,colonMode); if (brace >= 0 && !colonMode) isInside = TRUE; } if (brace >= 0) { if (colonMode) { // Find the end of the Python indented block. long lineStart = SendScintilla(SCI_LINEFROMPOSITION,brace); long lineMaxSubord = SendScintilla(SCI_GETLASTCHILD,lineStart,-1); other = SendScintilla(SCI_GETLINEENDPOSITION,lineMaxSubord); } else other = SendScintilla(SCI_BRACEMATCH,brace); if (other > brace) isInside = !isInside; } return isInside; } // Move to the matching brace. void QextScintilla::moveToMatchingBrace() { gotoMatchingBrace(FALSE); } // Select to the matching brace. void QextScintilla::selectToMatchingBrace() { gotoMatchingBrace(TRUE); } // Move to the matching brace and optionally select the text. void QextScintilla::gotoMatchingBrace(bool select) { long braceAtCaret; long braceOpposite; bool isInside = findMatchingBrace(braceAtCaret,braceOpposite,SloppyBraceMatch); if (braceOpposite >= 0) { // Convert the character positions into caret positions based // on whether the caret position was inside or outside the // braces. if (isInside) { if (braceOpposite > braceAtCaret) braceAtCaret++; else braceOpposite++; } else { if (braceOpposite > braceAtCaret) braceOpposite++; else braceAtCaret++; } ensureLineVisible(SendScintilla(SCI_LINEFROMPOSITION,braceOpposite)); if (select) SendScintilla(SCI_SETSEL,braceAtCaret,braceOpposite); else SendScintilla(SCI_SETSEL,braceOpposite,braceOpposite); } } // Return a position from a line number and an index within the line. long QextScintilla::posFromLineIndex(int line,int index) { long pos = SendScintilla(SCI_POSITIONFROMLINE,line); // Allow for multi-byte characters. for(int i = 0; i < index; i++) pos = SendScintilla(SCI_POSITIONAFTER,pos); return pos; } // Return a line number and an index within the line from a position. void QextScintilla::lineIndexFromPos(long pos,int *line,int *index) { long lin = SendScintilla(SCI_LINEFROMPOSITION,pos); long linpos = SendScintilla(SCI_POSITIONFROMLINE,lin); *line = lin; *index = pos - linpos; } // Convert a Scintilla string to a TQt Unicode string. TQString QextScintilla::convertText(const char *s) { if (isUtf8()) return TQString::fromUtf8(s); TQString qs; qs.setLatin1(s); return qs; } // Set the source of the auto-completion list. void QextScintilla::setAutoCompletionSource(AutoCompletionSource source) { acSource = source; } // Set the threshold for automatic auto-completion. void QextScintilla::setAutoCompletionThreshold(int thresh) { acThresh = thresh; } // Set the auto-completion start characters. void QextScintilla::setAutoCompletionStartCharacters(const char *start) { acStart = start; } // Set the APIs for auto-completion. void QextScintilla::setAutoCompletionAPIs(QextScintillaAPIs *apis) { acAPIs = apis; } // Explicitly auto-complete from all sources. void QextScintilla::autoCompleteFromAll() { startAutoCompletion(AcsAll, FALSE, showSingle); } // Explicitly auto-complete from the APIs. void QextScintilla::autoCompleteFromAPIs() { startAutoCompletion(AcsAPIs, FALSE, showSingle); } // Explicitly auto-complete from the document. void QextScintilla::autoCompleteFromDocument() { // If we are not in a word then ignore. if (currentCharInWord()) startAutoCompletion(AcsDocument, FALSE, showSingle); } // Return TRUE if the current character (ie. the one before the carat) is part // of a word. bool QextScintilla::currentCharInWord() { long pos = SendScintilla(SCI_GETCURRENTPOS); if (pos <= 0) return FALSE; return isWordChar(SendScintilla(SCI_GETCHARAT,pos - 1)); } // Check if a character can be in a word. bool QextScintilla::isWordChar(char ch) const { const char *word_chars = 0; if (!lex.isNull()) word_chars = lex->wordCharacters(); if (!word_chars) word_chars = defaultWordChars; return (strchr(word_chars, ch) != NULL); } // Recolour the document. void QextScintilla::recolor(int start,int end) { SendScintilla(SCI_COLOURISE,start,end); } // Registered an image. void QextScintilla::registerImage(int id,const TQPixmap *pm) { SendScintilla(SCI_REGISTERIMAGE,id,pm); } // Clear all registered images. void QextScintilla::clearRegisteredImages() { SendScintilla(SCI_CLEARREGISTEREDIMAGES); } // Set the fill-up characters for auto-completion. void QextScintilla::setAutoCompletionFillups(const char *fillups) { if (!fillups) fillups = ""; SendScintilla(SCI_AUTOCSETFILLUPS, fillups); fillups_enabled = explicit_fillups = TRUE; // Save them in case we need to reenable them at some point. saved_fillups = fillups; } // Enable/disable fill-ups for auto-completion. void QextScintilla::setAutoCompletionFillupsEnabled(bool enabled) { const char *fillups; if (!enabled) fillups = ""; else if (!explicit_fillups && !lex.isNull()) fillups = lex->autoCompletionFillups(); else fillups = saved_fillups.data(); SendScintilla(SCI_AUTOCSETFILLUPS, fillups); fillups_enabled = enabled; } // Return the state of fill-ups for auto-completion. bool QextScintilla::autoCompletionFillupsEnabled() { return fillups_enabled; } // Set the case sensitivity for auto-completion. void QextScintilla::setAutoCompletionCaseSensitivity(bool cs) { SendScintilla(SCI_AUTOCSETIGNORECASE,!cs); } // Return the case sensitivity for auto-completion. bool QextScintilla::autoCompletionCaseSensitivity() { return !SendScintilla(SCI_AUTOCGETIGNORECASE); } // Set the replace word mode for auto-completion. void QextScintilla::setAutoCompletionReplaceWord(bool replace) { SendScintilla(SCI_AUTOCSETDROPRESTOFWORD,replace); } // Return the replace word mode for auto-completion. bool QextScintilla::autoCompletionReplaceWord() { return SendScintilla(SCI_AUTOCGETDROPRESTOFWORD); } // Set the single item mode for auto-completion. void QextScintilla::setAutoCompletionShowSingle(bool single) { showSingle = single; } // Return the single item mode for auto-completion. bool QextScintilla::autoCompletionShowSingle() { return showSingle; } // Set the APIs for call tips. void QextScintilla::setCallTipsAPIs(QextScintillaAPIs *apis) { ctAPIs = apis; } // Set maximum number of call tips displayed. void QextScintilla::setCallTipsVisible(int nr) { maxCallTips = nr; } // Set the document to display. void QextScintilla::setDocument(const QextScintillaDocument &document) { if (doc.pdoc != document.pdoc) { doc.undisplay(this); doc.attach(document); doc.display(this,&document); } } // Ensure the document is read-write and return True if was was read-only. bool QextScintilla::ensureRW() { bool ro = isReadOnly(); if (ro) setReadOnly(FALSE); return ro; } // Return the number of the first visible line. int QextScintilla::firstVisibleLine() { return SendScintilla(SCI_GETFIRSTVISIBLELINE); } // Return the height in pixels of the text in a particular line. int QextScintilla::textHeight(int linenr) { return SendScintilla(SCI_TEXTHEIGHT, linenr); } // See if auto-completion or user list is active. bool QextScintilla::isListActive() { return SendScintilla(SCI_AUTOCACTIVE); } // Cancel any current auto-completion or user list. void QextScintilla::cancelList() { SendScintilla(SCI_AUTOCCANCEL); } // Display a user list. void QextScintilla::showUserList(int id, const TQStringList &list) { // Sanity check to make sure auto-completion doesn't get confused. if (id <= 0) return; const char sep = '\x03'; SendScintilla(SCI_AUTOCSETSEPARATOR, sep); SendScintilla(SCI_USERLISTSHOW, id, list.join(TQChar(sep)).latin1()); } // Translate the SCN_USERLISTSELECTION notification into something more useful. void QextScintilla::handleUserListSelection(const char *text, int id) { emit userListActivated(id, TQString(text)); }