comparison libgui/languages/build_ts/octave-qsci/qsciscintilla.cpp @ 31537:5ceb4bfcdb0f stable

add tools and files for updating the gui's language files for translation * libgui/languages/build_ts/README.md: readme for updating language files * libgui/languages/build_ts/octave-qsci: QScintilla source files for languages without translation provided by QScintilla * libgui/languages/build_ts/octave-qt: Qt source files for languages without translation provided by Qt
author Torsten Lilge <ttl-octave@mailbox.org>
date Thu, 24 Nov 2022 06:48:25 +0100
parents
children dd5ece3664ed
comparison
equal deleted inserted replaced
31535:4b80982e0af8 31537:5ceb4bfcdb0f
1 // This module implements the "official" high-level API of the Qt port of
2 // Scintilla. It is modelled on QTextEdit - a method of the same name should
3 // behave in the same way.
4 //
5 // Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
6 //
7 // This file is part of QScintilla.
8 //
9 // This file may be used under the terms of the GNU General Public License
10 // version 3.0 as published by the Free Software Foundation and appearing in
11 // the file LICENSE included in the packaging of this file. Please review the
12 // following information to ensure the GNU General Public License version 3.0
13 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
14 //
15 // If you do not wish to use this file under the terms of the GPL version 3.0
16 // then you may purchase a commercial license. For more information contact
17 // info@riverbankcomputing.com.
18 //
19 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21
22
23 #include "Qsci/qsciscintilla.h"
24
25 #include <string.h>
26
27 #include <QAction>
28 #include <QApplication>
29 #include <QColor>
30 #include <QEvent>
31 #include <QImage>
32 #include <QIODevice>
33 #include <QKeyEvent>
34 #include <QKeySequence>
35 #include <QMenu>
36 #include <QPoint>
37
38 #include "Qsci/qsciabstractapis.h"
39 #include "Qsci/qscicommandset.h"
40 #include "Qsci/qscilexer.h"
41 #include "Qsci/qscistyle.h"
42 #include "Qsci/qscistyledtext.h"
43
44
45 // Make sure these match the values in Scintilla.h. We don't #include that
46 // file because it just causes more clashes.
47 #define KEYWORDSET_MAX 8
48 #define MARKER_MAX 31
49
50 // The list separators for auto-completion and user lists.
51 const char acSeparator = '\x03';
52 const char userSeparator = '\x04';
53
54 // The default fold margin width.
55 static const int defaultFoldMarginWidth = 14;
56
57 // The default set of characters that make up a word.
58 static const char *defaultWordChars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
59
60 // Forward declarations.
61 static QColor asQColor(long sci_colour);
62
63
64 // The ctor.
65 QsciScintilla::QsciScintilla(QWidget *parent)
66 : QsciScintillaBase(parent),
67 allocatedMarkers(0), allocatedIndicators(7), oldPos(-1), selText(false),
68 fold(NoFoldStyle), foldmargin(2), autoInd(false),
69 braceMode(NoBraceMatch), acSource(AcsNone), acThresh(-1),
70 wchars(defaultWordChars), call_tips_position(CallTipsBelowText),
71 call_tips_style(CallTipsNoContext), maxCallTips(-1),
72 use_single(AcusNever), explicit_fillups(""), fillups_enabled(false)
73 {
74 connect(this,SIGNAL(SCN_MODIFYATTEMPTRO()),
75 SIGNAL(modificationAttempted()));
76
77 connect(this,SIGNAL(SCN_MODIFIED(int,int,const char *,int,int,int,int,int,int,int)),
78 SLOT(handleModified(int,int,const char *,int,int,int,int,int,int,int)));
79 connect(this,SIGNAL(SCN_CALLTIPCLICK(int)),
80 SLOT(handleCallTipClick(int)));
81 connect(this,SIGNAL(SCN_CHARADDED(int)),
82 SLOT(handleCharAdded(int)));
83 connect(this,SIGNAL(SCN_INDICATORCLICK(int,int)),
84 SLOT(handleIndicatorClick(int,int)));
85 connect(this,SIGNAL(SCN_INDICATORRELEASE(int,int)),
86 SLOT(handleIndicatorRelease(int,int)));
87 connect(this,SIGNAL(SCN_MARGINCLICK(int,int,int)),
88 SLOT(handleMarginClick(int,int,int)));
89 connect(this,SIGNAL(SCN_MARGINRIGHTCLICK(int,int,int)),
90 SLOT(handleMarginRightClick(int,int,int)));
91 connect(this,SIGNAL(SCN_SAVEPOINTREACHED()),
92 SLOT(handleSavePointReached()));
93 connect(this,SIGNAL(SCN_SAVEPOINTLEFT()),
94 SLOT(handleSavePointLeft()));
95 connect(this,SIGNAL(SCN_UPDATEUI(int)),
96 SLOT(handleUpdateUI(int)));
97 connect(this,SIGNAL(QSCN_SELCHANGED(bool)),
98 SLOT(handleSelectionChanged(bool)));
99 connect(this,SIGNAL(SCN_AUTOCSELECTION(const char *,int)),
100 SLOT(handleAutoCompletionSelection()));
101 connect(this,SIGNAL(SCN_USERLISTSELECTION(const char *,int)),
102 SLOT(handleUserListSelection(const char *,int)));
103
104 // Set the default font.
105 setFont(QApplication::font());
106
107 // Set the default fore and background colours.
108 QPalette pal = QApplication::palette();
109 setColor(pal.text().color());
110 setPaper(pal.base().color());
111 setSelectionForegroundColor(pal.highlightedText().color());
112 setSelectionBackgroundColor(pal.highlight().color());
113
114 #if defined(Q_OS_WIN)
115 setEolMode(EolWindows);
116 #else
117 // Note that EolMac is pre-OS/X.
118 setEolMode(EolUnix);
119 #endif
120
121 // Capturing the mouse seems to cause problems on multi-head systems. Qt
122 // should do the right thing anyway.
123 SendScintilla(SCI_SETMOUSEDOWNCAPTURES, 0UL);
124
125 setMatchedBraceForegroundColor(Qt::blue);
126 setUnmatchedBraceForegroundColor(Qt::red);
127
128 setAnnotationDisplay(AnnotationStandard);
129 setLexer();
130
131 // Set the visible policy. These are the same as SciTE's defaults
132 // which, presumably, are sensible.
133 SendScintilla(SCI_SETVISIBLEPOLICY, VISIBLE_STRICT | VISIBLE_SLOP, 4);
134
135 // The default behaviour is unexpected.
136 SendScintilla(SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR,
137 SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE);
138
139 // Create the standard command set.
140 stdCmds = new QsciCommandSet(this);
141
142 doc.display(this,0);
143 }
144
145
146 // The dtor.
147 QsciScintilla::~QsciScintilla()
148 {
149 // Detach any current lexer.
150 detachLexer();
151
152 doc.undisplay(this);
153 delete stdCmds;
154 }
155
156
157 // Return the current text colour.
158 QColor QsciScintilla::color() const
159 {
160 return nl_text_colour;
161 }
162
163
164 // Set the text colour.
165 void QsciScintilla::setColor(const QColor &c)
166 {
167 if (lex.isNull())
168 {
169 // Assume style 0 applies to everything so that we don't need to use
170 // SCI_STYLECLEARALL which clears everything.
171 SendScintilla(SCI_STYLESETFORE, 0, c);
172 nl_text_colour = c;
173 }
174 }
175
176
177 // Return the overwrite mode.
178 bool QsciScintilla::overwriteMode() const
179 {
180 return SendScintilla(SCI_GETOVERTYPE);
181 }
182
183
184 // Set the overwrite mode.
185 void QsciScintilla::setOverwriteMode(bool overwrite)
186 {
187 SendScintilla(SCI_SETOVERTYPE, overwrite);
188 }
189
190
191 // Return the current paper colour.
192 QColor QsciScintilla::paper() const
193 {
194 return nl_paper_colour;
195 }
196
197
198 // Set the paper colour.
199 void QsciScintilla::setPaper(const QColor &c)
200 {
201 if (lex.isNull())
202 {
203 // Assume style 0 applies to everything so that we don't need to use
204 // SCI_STYLECLEARALL which clears everything. We still have to set the
205 // default style as well for the background without any text.
206 SendScintilla(SCI_STYLESETBACK, 0, c);
207 SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, c);
208 nl_paper_colour = c;
209 }
210 }
211
212
213 // Set the default font.
214 void QsciScintilla::setFont(const QFont &f)
215 {
216 if (lex.isNull())
217 {
218 // Assume style 0 applies to everything so that we don't need to use
219 // SCI_STYLECLEARALL which clears everything.
220 setStylesFont(f, 0);
221 QWidget::setFont(f);
222 }
223 }
224
225
226 // Enable/disable auto-indent.
227 void QsciScintilla::setAutoIndent(bool autoindent)
228 {
229 autoInd = autoindent;
230 }
231
232
233 // Set the brace matching mode.
234 void QsciScintilla::setBraceMatching(BraceMatch bm)
235 {
236 braceMode = bm;
237 }
238
239
240 // Handle the addition of a character.
241 void QsciScintilla::handleCharAdded(int ch)
242 {
243 // Ignore if there is a selection.
244 long pos = SendScintilla(SCI_GETSELECTIONSTART);
245
246 if (pos != SendScintilla(SCI_GETSELECTIONEND) || pos == 0)
247 return;
248
249 // If auto-completion is already active then see if this character is a
250 // start character. If it is then create a new list which will be a subset
251 // of the current one. The case where it isn't a start character seems to
252 // be handled correctly elsewhere.
253 if (isListActive() && isStartChar(ch))
254 {
255 cancelList();
256 startAutoCompletion(acSource, false, use_single == AcusAlways);
257
258 return;
259 }
260
261 // Handle call tips.
262 if (call_tips_style != CallTipsNone && !lex.isNull() && strchr("(),", ch) != NULL)
263 callTip();
264
265 // Handle auto-indentation.
266 if (autoInd)
267 {
268 if (lex.isNull() || (lex->autoIndentStyle() & AiMaintain))
269 maintainIndentation(ch, pos);
270 else
271 autoIndentation(ch, pos);
272 }
273
274 // See if we might want to start auto-completion.
275 if (!isCallTipActive() && acSource != AcsNone)
276 {
277 if (isStartChar(ch))
278 startAutoCompletion(acSource, false, use_single == AcusAlways);
279 else if (acThresh >= 1 && isWordCharacter(ch))
280 startAutoCompletion(acSource, true, use_single == AcusAlways);
281 }
282 }
283
284
285 // See if a call tip is active.
286 bool QsciScintilla::isCallTipActive() const
287 {
288 return SendScintilla(SCI_CALLTIPACTIVE);
289 }
290
291
292 // Handle a possible change to any current call tip.
293 void QsciScintilla::callTip()
294 {
295 QsciAbstractAPIs *apis = lex->apis();
296
297 if (!apis)
298 return;
299
300 int pos, commas = 0;
301 bool found = false;
302 char ch;
303
304 pos = SendScintilla(SCI_GETCURRENTPOS);
305
306 // Move backwards through the line looking for the start of the current
307 // call tip and working out which argument it is.
308 while ((ch = getCharacter(pos)) != '\0')
309 {
310 if (ch == ',')
311 ++commas;
312 else if (ch == ')')
313 {
314 int depth = 1;
315
316 // Ignore everything back to the start of the corresponding
317 // parenthesis.
318 while ((ch = getCharacter(pos)) != '\0')
319 {
320 if (ch == ')')
321 ++depth;
322 else if (ch == '(' && --depth == 0)
323 break;
324 }
325 }
326 else if (ch == '(')
327 {
328 found = true;
329 break;
330 }
331 }
332
333 // Cancel any existing call tip.
334 SendScintilla(SCI_CALLTIPCANCEL);
335
336 // Done if there is no new call tip to set.
337 if (!found)
338 return;
339
340 QStringList context = apiContext(pos, pos, ctPos);
341
342 if (context.isEmpty())
343 return;
344
345 // The last word is complete, not partial.
346 context << QString();
347
348 ct_cursor = 0;
349 ct_shifts.clear();
350 ct_entries = apis->callTips(context, commas, call_tips_style, ct_shifts);
351
352 int nr_entries = ct_entries.count();
353
354 if (nr_entries == 0)
355 return;
356
357 if (maxCallTips > 0 && maxCallTips < nr_entries)
358 {
359 ct_entries = ct_entries.mid(0, maxCallTips);
360 nr_entries = maxCallTips;
361 }
362
363 int shift;
364 QString ct;
365
366 int nr_shifts = ct_shifts.count();
367
368 if (maxCallTips < 0 && nr_entries > 1)
369 {
370 shift = (nr_shifts > 0 ? ct_shifts.first() : 0);
371 ct = ct_entries[0];
372 ct.prepend('\002');
373 }
374 else
375 {
376 if (nr_shifts > nr_entries)
377 nr_shifts = nr_entries;
378
379 // Find the biggest shift.
380 shift = 0;
381
382 for (int i = 0; i < nr_shifts; ++i)
383 {
384 int sh = ct_shifts[i];
385
386 if (shift < sh)
387 shift = sh;
388 }
389
390 ct = ct_entries.join("\n");
391 }
392
393 ScintillaBytes ct_bytes = textAsBytes(ct);
394 const char *cts = ScintillaBytesConstData(ct_bytes);
395
396 SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), cts);
397
398 // Done if there is more than one call tip.
399 if (nr_entries > 1)
400 return;
401
402 // Highlight the current argument.
403 const char *astart;
404
405 if (commas == 0)
406 astart = strchr(cts, '(');
407 else
408 for (astart = strchr(cts, ','); astart && --commas > 0; astart = strchr(astart + 1, ','))
409 ;
410
411 if (!astart || !*++astart)
412 return;
413
414 // The end is at the next comma or unmatched closing parenthesis.
415 const char *aend;
416 int depth = 0;
417
418 for (aend = astart; *aend; ++aend)
419 {
420 char ch = *aend;
421
422 if (ch == ',' && depth == 0)
423 break;
424 else if (ch == '(')
425 ++depth;
426 else if (ch == ')')
427 {
428 if (depth == 0)
429 break;
430
431 --depth;
432 }
433 }
434
435 if (astart != aend)
436 SendScintilla(SCI_CALLTIPSETHLT, astart - cts, aend - cts);
437 }
438
439
440 // Handle a call tip click.
441 void QsciScintilla::handleCallTipClick(int dir)
442 {
443 int nr_entries = ct_entries.count();
444
445 // Move the cursor while bounds checking.
446 if (dir == 1)
447 {
448 if (ct_cursor - 1 < 0)
449 return;
450
451 --ct_cursor;
452 }
453 else if (dir == 2)
454 {
455 if (ct_cursor + 1 >= nr_entries)
456 return;
457
458 ++ct_cursor;
459 }
460 else
461 return;
462
463 int shift = (ct_shifts.count() > ct_cursor ? ct_shifts[ct_cursor] : 0);
464 QString ct = ct_entries[ct_cursor];
465
466 // Add the arrows.
467 if (ct_cursor < nr_entries - 1)
468 ct.prepend('\002');
469
470 if (ct_cursor > 0)
471 ct.prepend('\001');
472
473 SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), ct.toLatin1().data());
474 }
475
476
477 // Shift the position of the call tip (to take any context into account) but
478 // don't go before the start of the line.
479 int QsciScintilla::adjustedCallTipPosition(int ctshift) const
480 {
481 int ct = ctPos;
482
483 if (ctshift)
484 {
485 int ctmin = SendScintilla(SCI_POSITIONFROMLINE, SendScintilla(SCI_LINEFROMPOSITION, ct));
486
487 if (ct - ctshift < ctmin)
488 ct = ctmin;
489 }
490
491 return ct;
492 }
493
494
495 // Return the list of words that make up the context preceding the given
496 // position. The list will only have more than one element if there is a lexer
497 // set and it defines start strings. If so, then the last element might be
498 // empty if a start string has just been typed. On return pos is at the start
499 // of the context.
500 QStringList QsciScintilla::apiContext(int pos, int &context_start,
501 int &last_word_start)
502 {
503 enum {
504 Either,
505 Separator,
506 Word
507 };
508
509 QStringList words;
510 int good_pos = pos, expecting = Either;
511
512 last_word_start = -1;
513
514 while (pos > 0)
515 {
516 if (getSeparator(pos))
517 {
518 if (expecting == Either)
519 words.prepend(QString());
520 else if (expecting == Word)
521 break;
522
523 good_pos = pos;
524 expecting = Word;
525 }
526 else
527 {
528 QString word = getWord(pos);
529
530 if (word.isEmpty() || expecting == Separator)
531 break;
532
533 words.prepend(word);
534 good_pos = pos;
535 expecting = Separator;
536
537 // Return the position of the start of the last word if required.
538 if (last_word_start < 0)
539 last_word_start = pos;
540 }
541
542 // Strip any preceding spaces (mainly around operators).
543 char ch;
544
545 while ((ch = getCharacter(pos)) != '\0')
546 {
547 // This is the same definition of space that Scintilla uses.
548 if (ch != ' ' && (ch < 0x09 || ch > 0x0d))
549 {
550 ++pos;
551 break;
552 }
553 }
554 }
555
556 // A valid sequence always starts with a word and so should be expecting a
557 // separator.
558 if (expecting != Separator)
559 words.clear();
560
561 context_start = good_pos;
562
563 return words;
564 }
565
566
567 // Try and get a lexer's word separator from the text before the current
568 // position. Return true if one was found and adjust the position accordingly.
569 bool QsciScintilla::getSeparator(int &pos) const
570 {
571 int opos = pos;
572
573 // Go through each separator.
574 for (int i = 0; i < wseps.count(); ++i)
575 {
576 const QString &ws = wseps[i];
577
578 // Work backwards.
579 uint l;
580
581 for (l = ws.length(); l; --l)
582 {
583 char ch = getCharacter(pos);
584
585 if (ch == '\0' || ws.at(l - 1) != ch)
586 break;
587 }
588
589 if (!l)
590 return true;
591
592 // Reset for the next separator.
593 pos = opos;
594 }
595
596 return false;
597 }
598
599
600 // Try and get a word from the text before the current position. Return the
601 // word if one was found and adjust the position accordingly.
602 QString QsciScintilla::getWord(int &pos) const
603 {
604 QString word;
605 bool numeric = true;
606 char ch;
607
608 while ((ch = getCharacter(pos)) != '\0')
609 {
610 if (!isWordCharacter(ch))
611 {
612 ++pos;
613 break;
614 }
615
616 if (ch < '0' || ch > '9')
617 numeric = false;
618
619 word.prepend(ch);
620 }
621
622 // We don't auto-complete numbers.
623 if (numeric)
624 word.truncate(0);
625
626 return word;
627 }
628
629
630 // Get the "next" character (ie. the one before the current position) in the
631 // current line. The character will be '\0' if there are no more.
632 char QsciScintilla::getCharacter(int &pos) const
633 {
634 if (pos <= 0)
635 return '\0';
636
637 char ch = SendScintilla(SCI_GETCHARAT, --pos);
638
639 // Don't go past the end of the previous line.
640 if (ch == '\n' || ch == '\r')
641 {
642 ++pos;
643 return '\0';
644 }
645
646 return ch;
647 }
648
649
650 // See if a character is an auto-completion start character, ie. the last
651 // character of a word separator.
652 bool QsciScintilla::isStartChar(char ch) const
653 {
654 QString s = QChar(ch);
655
656 for (int i = 0; i < wseps.count(); ++i)
657 if (wseps[i].endsWith(s))
658 return true;
659
660 return false;
661 }
662
663
664 // Possibly start auto-completion.
665 void QsciScintilla::startAutoCompletion(AutoCompletionSource acs,
666 bool checkThresh, bool choose_single)
667 {
668 int start, ignore;
669 QStringList context = apiContext(SendScintilla(SCI_GETCURRENTPOS), start,
670 ignore);
671
672 if (context.isEmpty())
673 return;
674
675 // Get the last word's raw data and length.
676 ScintillaBytes s = textAsBytes(context.last());
677 const char *last_data = ScintillaBytesConstData(s);
678 int last_len = s.length();
679
680 if (checkThresh && last_len < acThresh)
681 return;
682
683 // Generate the string representing the valid words to select from.
684 QStringList wlist;
685
686 if ((acs == AcsAll || acs == AcsAPIs) && !lex.isNull())
687 {
688 QsciAbstractAPIs *apis = lex->apis();
689
690 if (apis)
691 apis->updateAutoCompletionList(context, wlist);
692 }
693
694 if (acs == AcsAll || acs == AcsDocument)
695 {
696 int sflags = SCFIND_WORDSTART;
697
698 if (!SendScintilla(SCI_AUTOCGETIGNORECASE))
699 sflags |= SCFIND_MATCHCASE;
700
701 SendScintilla(SCI_SETSEARCHFLAGS, sflags);
702
703 int pos = 0;
704 int dlen = SendScintilla(SCI_GETLENGTH);
705 int caret = SendScintilla(SCI_GETCURRENTPOS);
706 int clen = caret - start;
707 char *orig_context = new char[clen + 1];
708
709 SendScintilla(SCI_GETTEXTRANGE, start, caret, orig_context);
710
711 for (;;)
712 {
713 int fstart;
714
715 SendScintilla(SCI_SETTARGETSTART, pos);
716 SendScintilla(SCI_SETTARGETEND, dlen);
717
718 if ((fstart = SendScintilla(SCI_SEARCHINTARGET, clen, orig_context)) < 0)
719 break;
720
721 // Move past the root part.
722 pos = fstart + clen;
723
724 // Skip if this is the context we are auto-completing.
725 if (pos == caret)
726 continue;
727
728 // Get the rest of this word.
729 QString w = last_data;
730
731 while (pos < dlen)
732 {
733 char ch = SendScintilla(SCI_GETCHARAT, pos);
734
735 if (!isWordCharacter(ch))
736 break;
737
738 w += ch;
739 ++pos;
740 }
741
742 // Add the word if it isn't already there.
743 if (!w.isEmpty())
744 {
745 bool keep;
746
747 // If there are APIs then check if the word is already present
748 // as an API word (i.e. with a trailing space).
749 if (acs == AcsAll)
750 {
751 QString api_w = w;
752 api_w.append(' ');
753
754 keep = !wlist.contains(api_w);
755 }
756 else
757 {
758 keep = true;
759 }
760
761 if (keep && !wlist.contains(w))
762 wlist.append(w);
763 }
764 }
765
766 delete []orig_context;
767 }
768
769 if (wlist.isEmpty())
770 return;
771
772 wlist.sort();
773
774 SendScintilla(SCI_AUTOCSETCHOOSESINGLE, choose_single);
775 SendScintilla(SCI_AUTOCSETSEPARATOR, acSeparator);
776
777 ScintillaBytes wlist_s = textAsBytes(wlist.join(QChar(acSeparator)));
778 SendScintilla(SCI_AUTOCSHOW, last_len, ScintillaBytesConstData(wlist_s));
779 }
780
781
782 // Maintain the indentation of the previous line.
783 void QsciScintilla::maintainIndentation(char ch, long pos)
784 {
785 if (ch != '\r' && ch != '\n')
786 return;
787
788 int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos);
789
790 // Get the indentation of the preceding non-zero length line.
791 int ind = 0;
792
793 for (int line = curr_line - 1; line >= 0; --line)
794 {
795 if (SendScintilla(SCI_GETLINEENDPOSITION, line) >
796 SendScintilla(SCI_POSITIONFROMLINE, line))
797 {
798 ind = indentation(line);
799 break;
800 }
801 }
802
803 if (ind > 0)
804 autoIndentLine(pos, curr_line, ind);
805 }
806
807
808 // Implement auto-indentation.
809 void QsciScintilla::autoIndentation(char ch, long pos)
810 {
811 int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos);
812 int ind_width = indentWidth();
813 long curr_line_start = SendScintilla(SCI_POSITIONFROMLINE, curr_line);
814
815 const char *block_start = lex->blockStart();
816 bool start_single = (block_start && qstrlen(block_start) == 1);
817
818 const char *block_end = lex->blockEnd();
819 bool end_single = (block_end && qstrlen(block_end) == 1);
820
821 if (end_single && block_end[0] == ch)
822 {
823 if (!(lex->autoIndentStyle() & AiClosing) && rangeIsWhitespace(curr_line_start, pos - 1))
824 autoIndentLine(pos, curr_line, blockIndent(curr_line - 1) - ind_width);
825 }
826 else if (start_single && block_start[0] == ch)
827 {
828 // De-indent if we have already indented because the previous line was
829 // a start of block keyword.
830 if (!(lex->autoIndentStyle() & AiOpening) && curr_line > 0 && getIndentState(curr_line - 1) == isKeywordStart && rangeIsWhitespace(curr_line_start, pos - 1))
831 autoIndentLine(pos, curr_line, blockIndent(curr_line - 1) - ind_width);
832 }
833 else if (ch == '\r' || ch == '\n')
834 {
835 // Don't auto-indent the line (ie. preserve its existing indentation)
836 // if we have inserted a new line above by pressing return at the start
837 // of this line - in other words, if the previous line is empty.
838 long prev_line_length = SendScintilla(SCI_GETLINEENDPOSITION, curr_line - 1) - SendScintilla(SCI_POSITIONFROMLINE, curr_line - 1);
839
840 if (prev_line_length != 0)
841 autoIndentLine(pos, curr_line, blockIndent(curr_line - 1));
842 }
843 }
844
845
846 // Set the indentation for a line.
847 void QsciScintilla::autoIndentLine(long pos, int line, int indent)
848 {
849 if (indent < 0)
850 return;
851
852 long pos_before = SendScintilla(SCI_GETLINEINDENTPOSITION, line);
853 SendScintilla(SCI_SETLINEINDENTATION, line, indent);
854 long pos_after = SendScintilla(SCI_GETLINEINDENTPOSITION, line);
855 long new_pos = -1;
856
857 if (pos_after > pos_before)
858 {
859 new_pos = pos + (pos_after - pos_before);
860 }
861 else if (pos_after < pos_before && pos >= pos_after)
862 {
863 if (pos >= pos_before)
864 new_pos = pos + (pos_after - pos_before);
865 else
866 new_pos = pos_after;
867 }
868
869 if (new_pos >= 0)
870 SendScintilla(SCI_SETSEL, new_pos, new_pos);
871 }
872
873
874 // Return the indentation of the block defined by the given line (or something
875 // significant before).
876 int QsciScintilla::blockIndent(int line)
877 {
878 if (line < 0)
879 return 0;
880
881 // Handle the trvial case.
882 if (!lex->blockStartKeyword() && !lex->blockStart() && !lex->blockEnd())
883 return indentation(line);
884
885 int line_limit = line - lex->blockLookback();
886
887 if (line_limit < 0)
888 line_limit = 0;
889
890 for (int l = line; l >= line_limit; --l)
891 {
892 IndentState istate = getIndentState(l);
893
894 if (istate != isNone)
895 {
896 int ind_width = indentWidth();
897 int ind = indentation(l);
898
899 if (istate == isBlockStart)
900 {
901 if (!(lex -> autoIndentStyle() & AiOpening))
902 ind += ind_width;
903 }
904 else if (istate == isBlockEnd)
905 {
906 if (lex -> autoIndentStyle() & AiClosing)
907 ind -= ind_width;
908
909 if (ind < 0)
910 ind = 0;
911 }
912 else if (line == l)
913 ind += ind_width;
914
915 return ind;
916 }
917 }
918
919 return indentation(line);
920 }
921
922
923 // Return true if all characters starting at spos up to, but not including
924 // epos, are spaces or tabs.
925 bool QsciScintilla::rangeIsWhitespace(long spos, long epos)
926 {
927 while (spos < epos)
928 {
929 char ch = SendScintilla(SCI_GETCHARAT, spos);
930
931 if (ch != ' ' && ch != '\t')
932 return false;
933
934 ++spos;
935 }
936
937 return true;
938 }
939
940
941 // Returns the indentation state of a line.
942 QsciScintilla::IndentState QsciScintilla::getIndentState(int line)
943 {
944 IndentState istate;
945
946 // Get the styled text.
947 long spos = SendScintilla(SCI_POSITIONFROMLINE, line);
948 long epos = SendScintilla(SCI_POSITIONFROMLINE, line + 1);
949
950 char *text = new char[(epos - spos + 1) * 2];
951
952 SendScintilla(SCI_GETSTYLEDTEXT, spos, epos, text);
953
954 int style, bstart_off, bend_off;
955
956 // Block start/end takes precedence over keywords.
957 const char *bstart_words = lex->blockStart(&style);
958 bstart_off = findStyledWord(text, style, bstart_words);
959
960 const char *bend_words = lex->blockEnd(&style);
961 bend_off = findStyledWord(text, style, bend_words);
962
963 // If there is a block start but no block end characters then ignore it
964 // unless the block start is the last significant thing on the line, ie.
965 // assume Python-like blocking.
966 if (bstart_off >= 0 && !bend_words)
967 for (int i = bstart_off * 2; text[i] != '\0'; i += 2)
968 if (!QChar(text[i]).isSpace())
969 return isNone;
970
971 if (bstart_off > bend_off)
972 istate = isBlockStart;
973 else if (bend_off > bstart_off)
974 istate = isBlockEnd;
975 else
976 {
977 const char *words = lex->blockStartKeyword(&style);
978
979 istate = (findStyledWord(text,style,words) >= 0) ? isKeywordStart : isNone;
980 }
981
982 delete[] text;
983
984 return istate;
985 }
986
987
988 // text is a pointer to some styled text (ie. a character byte followed by a
989 // style byte). style is a style number. words is a space separated list of
990 // words. Returns the position in the text immediately after the last one of
991 // the words with the style. The reason we are after the last, and not the
992 // first, occurance is that we are looking for words that start and end a block
993 // where the latest one is the most significant.
994 int QsciScintilla::findStyledWord(const char *text, int style,
995 const char *words)
996 {
997 if (!words)
998 return -1;
999
1000 // Find the range of text with the style we are looking for.
1001 const char *stext;
1002
1003 for (stext = text; stext[1] != style; stext += 2)
1004 if (stext[0] == '\0')
1005 return -1;
1006
1007 // Move to the last character.
1008 const char *etext = stext;
1009
1010 while (etext[2] != '\0')
1011 etext += 2;
1012
1013 // Backtrack until we find the style. There will be one.
1014 while (etext[1] != style)
1015 etext -= 2;
1016
1017 // Look for each word in turn.
1018 while (words[0] != '\0')
1019 {
1020 // Find the end of the word.
1021 const char *eword = words;
1022
1023 while (eword[1] != ' ' && eword[1] != '\0')
1024 ++eword;
1025
1026 // Now search the text backwards.
1027 const char *wp = eword;
1028
1029 for (const char *tp = etext; tp >= stext; tp -= 2)
1030 {
1031 if (tp[0] != wp[0] || tp[1] != style)
1032 {
1033 // Reset the search.
1034 wp = eword;
1035 continue;
1036 }
1037
1038 // See if all the word has matched.
1039 if (wp-- == words)
1040 return ((tp - text) / 2) + (eword - words) + 1;
1041 }
1042
1043 // Move to the start of the next word if there is one.
1044 words = eword + 1;
1045
1046 if (words[0] == ' ')
1047 ++words;
1048 }
1049
1050 return -1;
1051 }
1052
1053
1054 // Return true if the code page is UTF8.
1055 bool QsciScintilla::isUtf8() const
1056 {
1057 return (SendScintilla(SCI_GETCODEPAGE) == SC_CP_UTF8);
1058 }
1059
1060
1061 // Set the code page.
1062 void QsciScintilla::setUtf8(bool cp)
1063 {
1064 SendScintilla(SCI_SETCODEPAGE, (cp ? SC_CP_UTF8 : 0));
1065 }
1066
1067
1068 // Return the end-of-line mode.
1069 QsciScintilla::EolMode QsciScintilla::eolMode() const
1070 {
1071 return (EolMode)SendScintilla(SCI_GETEOLMODE);
1072 }
1073
1074
1075 // Set the end-of-line mode.
1076 void QsciScintilla::setEolMode(EolMode mode)
1077 {
1078 SendScintilla(SCI_SETEOLMODE, mode);
1079 }
1080
1081
1082 // Convert the end-of-lines to a particular mode.
1083 void QsciScintilla::convertEols(EolMode mode)
1084 {
1085 SendScintilla(SCI_CONVERTEOLS, mode);
1086 }
1087
1088
1089 // Add an edge column.
1090 void QsciScintilla::addEdgeColumn(int colnr, const QColor &col)
1091 {
1092 SendScintilla(SCI_MULTIEDGEADDLINE, colnr, col);
1093 }
1094
1095
1096 // Clear all multi-edge columns.
1097 void QsciScintilla::clearEdgeColumns()
1098 {
1099 SendScintilla(SCI_MULTIEDGECLEARALL);
1100 }
1101
1102
1103 // Return the edge colour.
1104 QColor QsciScintilla::edgeColor() const
1105 {
1106 return asQColor(SendScintilla(SCI_GETEDGECOLOUR));
1107 }
1108
1109
1110 // Set the edge colour.
1111 void QsciScintilla::setEdgeColor(const QColor &col)
1112 {
1113 SendScintilla(SCI_SETEDGECOLOUR, col);
1114 }
1115
1116
1117 // Return the edge column.
1118 int QsciScintilla::edgeColumn() const
1119 {
1120 return SendScintilla(SCI_GETEDGECOLUMN);
1121 }
1122
1123
1124 // Set the edge column.
1125 void QsciScintilla::setEdgeColumn(int colnr)
1126 {
1127 SendScintilla(SCI_SETEDGECOLUMN, colnr);
1128 }
1129
1130
1131 // Return the edge mode.
1132 QsciScintilla::EdgeMode QsciScintilla::edgeMode() const
1133 {
1134 return (EdgeMode)SendScintilla(SCI_GETEDGEMODE);
1135 }
1136
1137
1138 // Set the edge mode.
1139 void QsciScintilla::setEdgeMode(EdgeMode mode)
1140 {
1141 SendScintilla(SCI_SETEDGEMODE, mode);
1142 }
1143
1144
1145 // Return the end-of-line visibility.
1146 bool QsciScintilla::eolVisibility() const
1147 {
1148 return SendScintilla(SCI_GETVIEWEOL);
1149 }
1150
1151
1152 // Set the end-of-line visibility.
1153 void QsciScintilla::setEolVisibility(bool visible)
1154 {
1155 SendScintilla(SCI_SETVIEWEOL, visible);
1156 }
1157
1158
1159 // Return the extra ascent.
1160 int QsciScintilla::extraAscent() const
1161 {
1162 return SendScintilla(SCI_GETEXTRAASCENT);
1163 }
1164
1165
1166 // Set the extra ascent.
1167 void QsciScintilla::setExtraAscent(int extra)
1168 {
1169 SendScintilla(SCI_SETEXTRAASCENT, extra);
1170 }
1171
1172
1173 // Return the extra descent.
1174 int QsciScintilla::extraDescent() const
1175 {
1176 return SendScintilla(SCI_GETEXTRADESCENT);
1177 }
1178
1179
1180 // Set the extra descent.
1181 void QsciScintilla::setExtraDescent(int extra)
1182 {
1183 SendScintilla(SCI_SETEXTRADESCENT, extra);
1184 }
1185
1186
1187 // Return the whitespace size.
1188 int QsciScintilla::whitespaceSize() const
1189 {
1190 return SendScintilla(SCI_GETWHITESPACESIZE);
1191 }
1192
1193
1194 // Set the whitespace size.
1195 void QsciScintilla::setWhitespaceSize(int size)
1196 {
1197 SendScintilla(SCI_SETWHITESPACESIZE, size);
1198 }
1199
1200
1201 // Set the whitespace background colour.
1202 void QsciScintilla::setWhitespaceBackgroundColor(const QColor &col)
1203 {
1204 SendScintilla(SCI_SETWHITESPACEBACK, col.isValid(), col);
1205 }
1206
1207
1208 // Set the whitespace foreground colour.
1209 void QsciScintilla::setWhitespaceForegroundColor(const QColor &col)
1210 {
1211 SendScintilla(SCI_SETWHITESPACEFORE, col.isValid(), col);
1212 }
1213
1214
1215 // Return the whitespace visibility.
1216 QsciScintilla::WhitespaceVisibility QsciScintilla::whitespaceVisibility() const
1217 {
1218 return (WhitespaceVisibility)SendScintilla(SCI_GETVIEWWS);
1219 }
1220
1221
1222 // Set the whitespace visibility.
1223 void QsciScintilla::setWhitespaceVisibility(WhitespaceVisibility mode)
1224 {
1225 SendScintilla(SCI_SETVIEWWS, mode);
1226 }
1227
1228
1229 // Return the tab draw mode.
1230 QsciScintilla::TabDrawMode QsciScintilla::tabDrawMode() const
1231 {
1232 return (TabDrawMode)SendScintilla(SCI_GETTABDRAWMODE);
1233 }
1234
1235
1236 // Set the tab draw mode.
1237 void QsciScintilla::setTabDrawMode(TabDrawMode mode)
1238 {
1239 SendScintilla(SCI_SETTABDRAWMODE, mode);
1240 }
1241
1242
1243 // Return the line wrap mode.
1244 QsciScintilla::WrapMode QsciScintilla::wrapMode() const
1245 {
1246 return (WrapMode)SendScintilla(SCI_GETWRAPMODE);
1247 }
1248
1249
1250 // Set the line wrap mode.
1251 void QsciScintilla::setWrapMode(WrapMode mode)
1252 {
1253 SendScintilla(SCI_SETLAYOUTCACHE,
1254 (mode == WrapNone ? SC_CACHE_CARET : SC_CACHE_DOCUMENT));
1255 SendScintilla(SCI_SETWRAPMODE, mode);
1256 }
1257
1258
1259 // Return the line wrap indent mode.
1260 QsciScintilla::WrapIndentMode QsciScintilla::wrapIndentMode() const
1261 {
1262 return (WrapIndentMode)SendScintilla(SCI_GETWRAPINDENTMODE);
1263 }
1264
1265
1266 // Set the line wrap indent mode.
1267 void QsciScintilla::setWrapIndentMode(WrapIndentMode mode)
1268 {
1269 SendScintilla(SCI_SETWRAPINDENTMODE, mode);
1270 }
1271
1272
1273 // Set the line wrap visual flags.
1274 void QsciScintilla::setWrapVisualFlags(WrapVisualFlag endFlag,
1275 WrapVisualFlag startFlag, int indent)
1276 {
1277 int flags = SC_WRAPVISUALFLAG_NONE;
1278 int loc = SC_WRAPVISUALFLAGLOC_DEFAULT;
1279
1280 switch (endFlag)
1281 {
1282 case WrapFlagNone:
1283 break;
1284
1285 case WrapFlagByText:
1286 flags |= SC_WRAPVISUALFLAG_END;
1287 loc |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT;
1288 break;
1289
1290 case WrapFlagByBorder:
1291 flags |= SC_WRAPVISUALFLAG_END;
1292 break;
1293
1294 case WrapFlagInMargin:
1295 flags |= SC_WRAPVISUALFLAG_MARGIN;
1296 break;
1297 }
1298
1299 switch (startFlag)
1300 {
1301 case WrapFlagNone:
1302 break;
1303
1304 case WrapFlagByText:
1305 flags |= SC_WRAPVISUALFLAG_START;
1306 loc |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT;
1307 break;
1308
1309 case WrapFlagByBorder:
1310 flags |= SC_WRAPVISUALFLAG_START;
1311 break;
1312
1313 case WrapFlagInMargin:
1314 flags |= SC_WRAPVISUALFLAG_MARGIN;
1315 break;
1316 }
1317
1318 SendScintilla(SCI_SETWRAPVISUALFLAGS, flags);
1319 SendScintilla(SCI_SETWRAPVISUALFLAGSLOCATION, loc);
1320 SendScintilla(SCI_SETWRAPSTARTINDENT, indent);
1321 }
1322
1323
1324 // Set the folding style.
1325 void QsciScintilla::setFolding(FoldStyle folding, int margin)
1326 {
1327 fold = folding;
1328 foldmargin = margin;
1329
1330 if (folding == NoFoldStyle)
1331 {
1332 SendScintilla(SCI_SETMARGINWIDTHN, margin, 0L);
1333 return;
1334 }
1335
1336 int mask = SendScintilla(SCI_GETMODEVENTMASK);
1337 SendScintilla(SCI_SETMODEVENTMASK, mask | SC_MOD_CHANGEFOLD);
1338
1339 SendScintilla(SCI_SETFOLDFLAGS, SC_FOLDFLAG_LINEAFTER_CONTRACTED);
1340
1341 SendScintilla(SCI_SETMARGINTYPEN, margin, (long)SC_MARGIN_SYMBOL);
1342 SendScintilla(SCI_SETMARGINMASKN, margin, SC_MASK_FOLDERS);
1343 SendScintilla(SCI_SETMARGINSENSITIVEN, margin, 1);
1344
1345 // Set the marker symbols to use.
1346 switch (folding)
1347 {
1348 case NoFoldStyle:
1349 break;
1350
1351 case PlainFoldStyle:
1352 setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS);
1353 setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_PLUS);
1354 setFoldMarker(SC_MARKNUM_FOLDERSUB);
1355 setFoldMarker(SC_MARKNUM_FOLDERTAIL);
1356 setFoldMarker(SC_MARKNUM_FOLDEREND);
1357 setFoldMarker(SC_MARKNUM_FOLDEROPENMID);
1358 setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL);
1359 break;
1360
1361 case CircledFoldStyle:
1362 setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS);
1363 setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS);
1364 setFoldMarker(SC_MARKNUM_FOLDERSUB);
1365 setFoldMarker(SC_MARKNUM_FOLDERTAIL);
1366 setFoldMarker(SC_MARKNUM_FOLDEREND);
1367 setFoldMarker(SC_MARKNUM_FOLDEROPENMID);
1368 setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL);
1369 break;
1370
1371 case BoxedFoldStyle:
1372 setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
1373 setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
1374 setFoldMarker(SC_MARKNUM_FOLDERSUB);
1375 setFoldMarker(SC_MARKNUM_FOLDERTAIL);
1376 setFoldMarker(SC_MARKNUM_FOLDEREND);
1377 setFoldMarker(SC_MARKNUM_FOLDEROPENMID);
1378 setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL);
1379 break;
1380
1381 case CircledTreeFoldStyle:
1382 setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS);
1383 setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS);
1384 setFoldMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
1385 setFoldMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);
1386 setFoldMarker(SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED);
1387 setFoldMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED);
1388 setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);
1389 break;
1390
1391 case BoxedTreeFoldStyle:
1392 setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
1393 setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
1394 setFoldMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
1395 setFoldMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
1396 setFoldMarker(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
1397 setFoldMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
1398 setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
1399 break;
1400 }
1401
1402 SendScintilla(SCI_SETMARGINWIDTHN, margin, defaultFoldMarginWidth);
1403 }
1404
1405
1406 // Clear all current folds.
1407 void QsciScintilla::clearFolds()
1408 {
1409 recolor();
1410
1411 int maxLine = SendScintilla(SCI_GETLINECOUNT);
1412
1413 for (int line = 0; line < maxLine; line++)
1414 {
1415 int level = SendScintilla(SCI_GETFOLDLEVEL, line);
1416
1417 if (level & SC_FOLDLEVELHEADERFLAG)
1418 {
1419 SendScintilla(SCI_SETFOLDEXPANDED, line, 1);
1420 foldExpand(line, true, false, 0, level);
1421 line--;
1422 }
1423 }
1424 }
1425
1426
1427 // Set up a folder marker.
1428 void QsciScintilla::setFoldMarker(int marknr, int mark)
1429 {
1430 SendScintilla(SCI_MARKERDEFINE, marknr, mark);
1431
1432 if (mark != SC_MARK_EMPTY)
1433 {
1434 SendScintilla(SCI_MARKERSETFORE, marknr, QColor(Qt::white));
1435 SendScintilla(SCI_MARKERSETBACK, marknr, QColor(Qt::black));
1436 }
1437 }
1438
1439
1440 // Handle a click in the fold margin. This is mostly taken from SciTE.
1441 void QsciScintilla::foldClick(int lineClick, int bstate)
1442 {
1443 bool shift = bstate & Qt::ShiftModifier;
1444 bool ctrl = bstate & Qt::ControlModifier;
1445
1446 if (shift && ctrl)
1447 {
1448 foldAll();
1449 return;
1450 }
1451
1452 int levelClick = SendScintilla(SCI_GETFOLDLEVEL, lineClick);
1453
1454 if (levelClick & SC_FOLDLEVELHEADERFLAG)
1455 {
1456 if (shift)
1457 {
1458 // Ensure all children are visible.
1459 SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1);
1460 foldExpand(lineClick, true, true, 100, levelClick);
1461 }
1462 else if (ctrl)
1463 {
1464 if (SendScintilla(SCI_GETFOLDEXPANDED, lineClick))
1465 {
1466 // Contract this line and all its children.
1467 SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 0L);
1468 foldExpand(lineClick, false, true, 0, levelClick);
1469 }
1470 else
1471 {
1472 // Expand this line and all its children.
1473 SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1);
1474 foldExpand(lineClick, true, true, 100, levelClick);
1475 }
1476 }
1477 else
1478 {
1479 // Toggle this line.
1480 SendScintilla(SCI_TOGGLEFOLD, lineClick);
1481 }
1482 }
1483 }
1484
1485
1486 // Do the hard work of hiding and showing lines. This is mostly taken from
1487 // SciTE.
1488 void QsciScintilla::foldExpand(int &line, bool doExpand, bool force,
1489 int visLevels, int level)
1490 {
1491 int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, line,
1492 level & SC_FOLDLEVELNUMBERMASK);
1493
1494 line++;
1495
1496 while (line <= lineMaxSubord)
1497 {
1498 if (force)
1499 {
1500 if (visLevels > 0)
1501 SendScintilla(SCI_SHOWLINES, line, line);
1502 else
1503 SendScintilla(SCI_HIDELINES, line, line);
1504 }
1505 else if (doExpand)
1506 SendScintilla(SCI_SHOWLINES, line, line);
1507
1508 int levelLine = level;
1509
1510 if (levelLine == -1)
1511 levelLine = SendScintilla(SCI_GETFOLDLEVEL, line);
1512
1513 if (levelLine & SC_FOLDLEVELHEADERFLAG)
1514 {
1515 if (force)
1516 {
1517 if (visLevels > 1)
1518 SendScintilla(SCI_SETFOLDEXPANDED, line, 1);
1519 else
1520 SendScintilla(SCI_SETFOLDEXPANDED, line, 0L);
1521
1522 foldExpand(line, doExpand, force, visLevels - 1);
1523 }
1524 else if (doExpand)
1525 {
1526 if (!SendScintilla(SCI_GETFOLDEXPANDED, line))
1527 SendScintilla(SCI_SETFOLDEXPANDED, line, 1);
1528
1529 foldExpand(line, true, force, visLevels - 1);
1530 }
1531 else
1532 foldExpand(line, false, force, visLevels - 1);
1533 }
1534 else
1535 line++;
1536 }
1537 }
1538
1539
1540 // Fully expand (if there is any line currently folded) all text. Otherwise,
1541 // fold all text. This is mostly taken from SciTE.
1542 void QsciScintilla::foldAll(bool children)
1543 {
1544 recolor();
1545
1546 int maxLine = SendScintilla(SCI_GETLINECOUNT);
1547 bool expanding = true;
1548
1549 for (int lineSeek = 0; lineSeek < maxLine; lineSeek++)
1550 {
1551 if (SendScintilla(SCI_GETFOLDLEVEL,lineSeek) & SC_FOLDLEVELHEADERFLAG)
1552 {
1553 expanding = !SendScintilla(SCI_GETFOLDEXPANDED, lineSeek);
1554 break;
1555 }
1556 }
1557
1558 for (int line = 0; line < maxLine; line++)
1559 {
1560 int level = SendScintilla(SCI_GETFOLDLEVEL, line);
1561
1562 if (!(level & SC_FOLDLEVELHEADERFLAG))
1563 continue;
1564
1565 if (children ||
1566 (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK)))
1567 {
1568 if (expanding)
1569 {
1570 SendScintilla(SCI_SETFOLDEXPANDED, line, 1);
1571 foldExpand(line, true, false, 0, level);
1572 line--;
1573 }
1574 else
1575 {
1576 int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, line, -1);
1577
1578 SendScintilla(SCI_SETFOLDEXPANDED, line, 0L);
1579
1580 if (lineMaxSubord > line)
1581 SendScintilla(SCI_HIDELINES, line + 1, lineMaxSubord);
1582 }
1583 }
1584 }
1585 }
1586
1587
1588 // Handle a fold change. This is mostly taken from SciTE.
1589 void QsciScintilla::foldChanged(int line,int levelNow,int levelPrev)
1590 {
1591 if (levelNow & SC_FOLDLEVELHEADERFLAG)
1592 {
1593 if (!(levelPrev & SC_FOLDLEVELHEADERFLAG))
1594 SendScintilla(SCI_SETFOLDEXPANDED, line, 1);
1595 }
1596 else if (levelPrev & SC_FOLDLEVELHEADERFLAG)
1597 {
1598 if (!SendScintilla(SCI_GETFOLDEXPANDED, line))
1599 {
1600 // Removing the fold from one that has been contracted so should
1601 // expand. Otherwise lines are left invisible with no way to make
1602 // them visible.
1603 foldExpand(line, true, false, 0, levelPrev);
1604 }
1605 }
1606 }
1607
1608
1609 // Toggle the fold for a line if it contains a fold marker.
1610 void QsciScintilla::foldLine(int line)
1611 {
1612 SendScintilla(SCI_TOGGLEFOLD, line);
1613 }
1614
1615
1616 // Return the list of folded lines.
1617 QList<int> QsciScintilla::contractedFolds() const
1618 {
1619 QList<int> folds;
1620 int linenr = 0, fold_line;
1621
1622 while ((fold_line = SendScintilla(SCI_CONTRACTEDFOLDNEXT, linenr)) >= 0)
1623 {
1624 folds.append(fold_line);
1625 linenr = fold_line + 1;
1626 }
1627
1628 return folds;
1629 }
1630
1631
1632 // Set the fold state from a list.
1633 void QsciScintilla::setContractedFolds(const QList<int> &folds)
1634 {
1635 for (int i = 0; i < folds.count(); ++i)
1636 {
1637 int line = folds[i];
1638 int last_line = SendScintilla(SCI_GETLASTCHILD, line, -1);
1639
1640 SendScintilla(SCI_SETFOLDEXPANDED, line, 0L);
1641 SendScintilla(SCI_HIDELINES, line + 1, last_line);
1642 }
1643 }
1644
1645
1646 // Handle the SCN_MODIFIED notification.
1647 void QsciScintilla::handleModified(int pos, int mtype, const char *text,
1648 int len, int added, int line, int foldNow, int foldPrev, int token,
1649 int annotationLinesAdded)
1650 {
1651 Q_UNUSED(pos);
1652 Q_UNUSED(text);
1653 Q_UNUSED(len);
1654 Q_UNUSED(token);
1655 Q_UNUSED(annotationLinesAdded);
1656
1657 if (mtype & SC_MOD_CHANGEFOLD)
1658 {
1659 if (fold)
1660 foldChanged(line, foldNow, foldPrev);
1661 }
1662
1663 if (mtype & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT))
1664 {
1665 emit textChanged();
1666
1667 if (added != 0)
1668 emit linesChanged();
1669 }
1670 }
1671
1672
1673 // Zoom in a number of points.
1674 void QsciScintilla::zoomIn(int range)
1675 {
1676 zoomTo(SendScintilla(SCI_GETZOOM) + range);
1677 }
1678
1679
1680 // Zoom in a single point.
1681 void QsciScintilla::zoomIn()
1682 {
1683 SendScintilla(SCI_ZOOMIN);
1684 }
1685
1686
1687 // Zoom out a number of points.
1688 void QsciScintilla::zoomOut(int range)
1689 {
1690 zoomTo(SendScintilla(SCI_GETZOOM) - range);
1691 }
1692
1693
1694 // Zoom out a single point.
1695 void QsciScintilla::zoomOut()
1696 {
1697 SendScintilla(SCI_ZOOMOUT);
1698 }
1699
1700
1701 // Set the zoom to a number of points.
1702 void QsciScintilla::zoomTo(int size)
1703 {
1704 if (size < -10)
1705 size = -10;
1706 else if (size > 20)
1707 size = 20;
1708
1709 SendScintilla(SCI_SETZOOM, size);
1710 }
1711
1712
1713 // Find the first occurrence of a string.
1714 bool QsciScintilla::findFirst(const QString &expr, bool re, bool cs, bool wo,
1715 bool wrap, bool forward, int line, int index, bool show, bool posix,
1716 bool cxx11)
1717 {
1718 if (expr.isEmpty())
1719 {
1720 findState.status = FindState::Idle;
1721 return false;
1722 }
1723
1724 findState.status = FindState::Finding;
1725 findState.expr = expr;
1726 findState.wrap = wrap;
1727 findState.forward = forward;
1728
1729 findState.flags =
1730 (cs ? SCFIND_MATCHCASE : 0) |
1731 (wo ? SCFIND_WHOLEWORD : 0) |
1732 (re ? SCFIND_REGEXP : 0) |
1733 (posix ? SCFIND_POSIX : 0) |
1734 (cxx11 ? SCFIND_CXX11REGEX : 0);
1735
1736 if (line < 0 || index < 0)
1737 findState.startpos = SendScintilla(SCI_GETCURRENTPOS);
1738 else
1739 findState.startpos = positionFromLineIndex(line, index);
1740
1741 if (forward)
1742 findState.endpos = SendScintilla(SCI_GETLENGTH);
1743 else
1744 findState.endpos = 0;
1745
1746 findState.show = show;
1747
1748 return doFind();
1749 }
1750
1751
1752 // Find the first occurrence of a string in the current selection.
1753 bool QsciScintilla::findFirstInSelection(const QString &expr, bool re, bool cs,
1754 bool wo, bool forward, bool show, bool posix, bool cxx11)
1755 {
1756 if (expr.isEmpty())
1757 {
1758 findState.status = FindState::Idle;
1759 return false;
1760 }
1761
1762 findState.status = FindState::FindingInSelection;
1763 findState.expr = expr;
1764 findState.wrap = false;
1765 findState.forward = forward;
1766
1767 findState.flags =
1768 (cs ? SCFIND_MATCHCASE : 0) |
1769 (wo ? SCFIND_WHOLEWORD : 0) |
1770 (re ? SCFIND_REGEXP : 0) |
1771 (posix ? SCFIND_POSIX : 0) |
1772 (cxx11 ? SCFIND_CXX11REGEX : 0);
1773
1774 findState.startpos_orig = SendScintilla(SCI_GETSELECTIONSTART);
1775 findState.endpos_orig = SendScintilla(SCI_GETSELECTIONEND);
1776
1777 if (forward)
1778 {
1779 findState.startpos = findState.startpos_orig;
1780 findState.endpos = findState.endpos_orig;
1781 }
1782 else
1783 {
1784 findState.startpos = findState.endpos_orig;
1785 findState.endpos = findState.startpos_orig;
1786 }
1787
1788 findState.show = show;
1789
1790 return doFind();
1791 }
1792
1793
1794 // Cancel any current search.
1795 void QsciScintilla::cancelFind()
1796 {
1797 findState.status = FindState::Idle;
1798 }
1799
1800
1801 // Find the next occurrence of a string.
1802 bool QsciScintilla::findNext()
1803 {
1804 if (findState.status == FindState::Idle)
1805 return false;
1806
1807 return doFind();
1808 }
1809
1810
1811 // Do the hard work of the find methods.
1812 bool QsciScintilla::doFind()
1813 {
1814 SendScintilla(SCI_SETSEARCHFLAGS, findState.flags);
1815
1816 int pos = simpleFind();
1817
1818 // See if it was found. If not and wraparound is wanted, try again.
1819 if (pos == -1 && findState.wrap)
1820 {
1821 if (findState.forward)
1822 {
1823 findState.startpos = 0;
1824 findState.endpos = SendScintilla(SCI_GETLENGTH);
1825 }
1826 else
1827 {
1828 findState.startpos = SendScintilla(SCI_GETLENGTH);
1829 findState.endpos = 0;
1830 }
1831
1832 pos = simpleFind();
1833 }
1834
1835 if (pos == -1)
1836 {
1837 // Restore the original selection.
1838 if (findState.status == FindState::FindingInSelection)
1839 SendScintilla(SCI_SETSEL, findState.startpos_orig,
1840 findState.endpos_orig);
1841
1842 findState.status = FindState::Idle;
1843 return false;
1844 }
1845
1846 // It was found.
1847 long targstart = SendScintilla(SCI_GETTARGETSTART);
1848 long targend = SendScintilla(SCI_GETTARGETEND);
1849
1850 // Ensure the text found is visible if required.
1851 if (findState.show)
1852 {
1853 int startLine = SendScintilla(SCI_LINEFROMPOSITION, targstart);
1854 int endLine = SendScintilla(SCI_LINEFROMPOSITION, targend);
1855
1856 for (int i = startLine; i <= endLine; ++i)
1857 SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, i);
1858 }
1859
1860 // Now set the selection.
1861 SendScintilla(SCI_SETSEL, targstart, targend);
1862
1863 // Finally adjust the start position so that we don't find the same one
1864 // again.
1865 if (findState.forward)
1866 findState.startpos = targend;
1867 else if ((findState.startpos = targstart - 1) < 0)
1868 findState.startpos = 0;
1869
1870 return true;
1871 }
1872
1873
1874 // Do a simple find between the start and end positions.
1875 int QsciScintilla::simpleFind()
1876 {
1877 if (findState.startpos == findState.endpos)
1878 return -1;
1879
1880 SendScintilla(SCI_SETTARGETSTART, findState.startpos);
1881 SendScintilla(SCI_SETTARGETEND, findState.endpos);
1882
1883 ScintillaBytes s = textAsBytes(findState.expr);
1884
1885 return SendScintilla(SCI_SEARCHINTARGET, s.length(),
1886 ScintillaBytesConstData(s));
1887 }
1888
1889
1890 // Replace the text found with the previous find method.
1891 void QsciScintilla::replace(const QString &replaceStr)
1892 {
1893 if (findState.status == FindState::Idle)
1894 return;
1895
1896 long start = SendScintilla(SCI_GETSELECTIONSTART);
1897 long orig_len = SendScintilla(SCI_GETSELECTIONEND) - start;
1898
1899 SendScintilla(SCI_TARGETFROMSELECTION);
1900
1901 int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET;
1902
1903 ScintillaBytes s = textAsBytes(replaceStr);
1904 long len = SendScintilla(cmd, -1, ScintillaBytesConstData(s));
1905
1906 // Reset the selection.
1907 SendScintilla(SCI_SETSELECTIONSTART, start);
1908 SendScintilla(SCI_SETSELECTIONEND, start + len);
1909
1910 // Fix the original selection.
1911 findState.endpos_orig += (len - orig_len);
1912
1913 if (findState.forward)
1914 findState.startpos = start + len;
1915 }
1916
1917
1918 // Query the modified state.
1919 bool QsciScintilla::isModified() const
1920 {
1921 return doc.isModified();
1922 }
1923
1924
1925 // Set the modified state.
1926 void QsciScintilla::setModified(bool m)
1927 {
1928 if (!m)
1929 SendScintilla(SCI_SETSAVEPOINT);
1930 }
1931
1932
1933 // Handle the SCN_INDICATORCLICK notification.
1934 void QsciScintilla::handleIndicatorClick(int pos, int modifiers)
1935 {
1936 int state = mapModifiers(modifiers);
1937 int line, index;
1938
1939 lineIndexFromPosition(pos, &line, &index);
1940
1941 emit indicatorClicked(line, index, Qt::KeyboardModifiers(state));
1942 }
1943
1944
1945 // Handle the SCN_INDICATORRELEASE notification.
1946 void QsciScintilla::handleIndicatorRelease(int pos, int modifiers)
1947 {
1948 int state = mapModifiers(modifiers);
1949 int line, index;
1950
1951 lineIndexFromPosition(pos, &line, &index);
1952
1953 emit indicatorReleased(line, index, Qt::KeyboardModifiers(state));
1954 }
1955
1956
1957 // Handle the SCN_MARGINCLICK notification.
1958 void QsciScintilla::handleMarginClick(int pos, int modifiers, int margin)
1959 {
1960 int state = mapModifiers(modifiers);
1961 int line = SendScintilla(SCI_LINEFROMPOSITION, pos);
1962
1963 if (fold && margin == foldmargin)
1964 foldClick(line, state);
1965 else
1966 emit marginClicked(margin, line, Qt::KeyboardModifiers(state));
1967 }
1968
1969
1970 // Handle the SCN_MARGINRIGHTCLICK notification.
1971 void QsciScintilla::handleMarginRightClick(int pos, int modifiers, int margin)
1972 {
1973 int state = mapModifiers(modifiers);
1974 int line = SendScintilla(SCI_LINEFROMPOSITION, pos);
1975
1976 emit marginRightClicked(margin, line, Qt::KeyboardModifiers(state));
1977 }
1978
1979
1980 // Handle the SCN_SAVEPOINTREACHED notification.
1981 void QsciScintilla::handleSavePointReached()
1982 {
1983 doc.setModified(false);
1984 emit modificationChanged(false);
1985 }
1986
1987
1988 // Handle the SCN_SAVEPOINTLEFT notification.
1989 void QsciScintilla::handleSavePointLeft()
1990 {
1991 doc.setModified(true);
1992 emit modificationChanged(true);
1993 }
1994
1995
1996 // Handle the QSCN_SELCHANGED signal.
1997 void QsciScintilla::handleSelectionChanged(bool yes)
1998 {
1999 selText = yes;
2000
2001 emit copyAvailable(yes);
2002 emit selectionChanged();
2003 }
2004
2005
2006 // Get the current selection.
2007 void QsciScintilla::getSelection(int *lineFrom, int *indexFrom, int *lineTo,
2008 int *indexTo) const
2009 {
2010 if (selText)
2011 {
2012 lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONSTART), lineFrom,
2013 indexFrom);
2014 lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONEND), lineTo,
2015 indexTo);
2016 }
2017 else
2018 *lineFrom = *indexFrom = *lineTo = *indexTo = -1;
2019 }
2020
2021
2022 // Sets the current selection.
2023 void QsciScintilla::setSelection(int lineFrom, int indexFrom, int lineTo,
2024 int indexTo)
2025 {
2026 SendScintilla(SCI_SETSEL, positionFromLineIndex(lineFrom, indexFrom),
2027 positionFromLineIndex(lineTo, indexTo));
2028 }
2029
2030
2031 // Set the background colour of selected text.
2032 void QsciScintilla::setSelectionBackgroundColor(const QColor &col)
2033 {
2034 int alpha = col.alpha();
2035
2036 if (alpha == 255)
2037 alpha = SC_ALPHA_NOALPHA;
2038
2039 SendScintilla(SCI_SETSELBACK, 1, col);
2040 SendScintilla(SCI_SETSELALPHA, alpha);
2041 }
2042
2043
2044 // Set the foreground colour of selected text.
2045 void QsciScintilla::setSelectionForegroundColor(const QColor &col)
2046 {
2047 SendScintilla(SCI_SETSELFORE, 1, col);
2048 }
2049
2050
2051 // Reset the background colour of selected text to the default.
2052 void QsciScintilla::resetSelectionBackgroundColor()
2053 {
2054 SendScintilla(SCI_SETSELALPHA, SC_ALPHA_NOALPHA);
2055 SendScintilla(SCI_SETSELBACK, 0UL);
2056 }
2057
2058
2059 // Reset the foreground colour of selected text to the default.
2060 void QsciScintilla::resetSelectionForegroundColor()
2061 {
2062 SendScintilla(SCI_SETSELFORE, 0UL);
2063 }
2064
2065
2066 // Set the fill to the end-of-line for the selection.
2067 void QsciScintilla::setSelectionToEol(bool filled)
2068 {
2069 SendScintilla(SCI_SETSELEOLFILLED, filled);
2070 }
2071
2072
2073 // Return the fill to the end-of-line for the selection.
2074 bool QsciScintilla::selectionToEol() const
2075 {
2076 return SendScintilla(SCI_GETSELEOLFILLED);
2077 }
2078
2079
2080 // Set the width of the caret.
2081 void QsciScintilla::setCaretWidth(int width)
2082 {
2083 SendScintilla(SCI_SETCARETWIDTH, width);
2084 }
2085
2086
2087 // Set the width of the frame of the line containing the caret.
2088 void QsciScintilla::setCaretLineFrameWidth(int width)
2089 {
2090 SendScintilla(SCI_SETCARETLINEFRAME, width);
2091 }
2092
2093
2094 // Set the foreground colour of the caret.
2095 void QsciScintilla::setCaretForegroundColor(const QColor &col)
2096 {
2097 SendScintilla(SCI_SETCARETFORE, col);
2098 }
2099
2100
2101 // Set the background colour of the line containing the caret.
2102 void QsciScintilla::setCaretLineBackgroundColor(const QColor &col)
2103 {
2104 int alpha = col.alpha();
2105
2106 if (alpha == 255)
2107 alpha = SC_ALPHA_NOALPHA;
2108
2109 SendScintilla(SCI_SETCARETLINEBACK, col);
2110 SendScintilla(SCI_SETCARETLINEBACKALPHA, alpha);
2111 }
2112
2113
2114 // Set the state of the background colour of the line containing the caret.
2115 void QsciScintilla::setCaretLineVisible(bool enable)
2116 {
2117 SendScintilla(SCI_SETCARETLINEVISIBLE, enable);
2118 }
2119
2120
2121 // Set the background colour of a hotspot area.
2122 void QsciScintilla::setHotspotBackgroundColor(const QColor &col)
2123 {
2124 SendScintilla(SCI_SETHOTSPOTACTIVEBACK, 1, col);
2125 }
2126
2127
2128 // Set the foreground colour of a hotspot area.
2129 void QsciScintilla::setHotspotForegroundColor(const QColor &col)
2130 {
2131 SendScintilla(SCI_SETHOTSPOTACTIVEFORE, 1, col);
2132 }
2133
2134
2135 // Reset the background colour of a hotspot area to the default.
2136 void QsciScintilla::resetHotspotBackgroundColor()
2137 {
2138 SendScintilla(SCI_SETHOTSPOTACTIVEBACK, 0UL);
2139 }
2140
2141
2142 // Reset the foreground colour of a hotspot area to the default.
2143 void QsciScintilla::resetHotspotForegroundColor()
2144 {
2145 SendScintilla(SCI_SETHOTSPOTACTIVEFORE, 0UL);
2146 }
2147
2148
2149 // Set the underline of a hotspot area.
2150 void QsciScintilla::setHotspotUnderline(bool enable)
2151 {
2152 SendScintilla(SCI_SETHOTSPOTACTIVEUNDERLINE, enable);
2153 }
2154
2155
2156 // Set the wrapping of a hotspot area.
2157 void QsciScintilla::setHotspotWrap(bool enable)
2158 {
2159 SendScintilla(SCI_SETHOTSPOTSINGLELINE, !enable);
2160 }
2161
2162
2163 // Query the read-only state.
2164 bool QsciScintilla::isReadOnly() const
2165 {
2166 return SendScintilla(SCI_GETREADONLY);
2167 }
2168
2169
2170 // Set the read-only state.
2171 void QsciScintilla::setReadOnly(bool ro)
2172 {
2173 setAttribute(Qt::WA_InputMethodEnabled, !ro);
2174 SendScintilla(SCI_SETREADONLY, ro);
2175 }
2176
2177
2178 // Append the given text.
2179 void QsciScintilla::append(const QString &text)
2180 {
2181 bool ro = ensureRW();
2182
2183 ScintillaBytes s = textAsBytes(text);
2184 SendScintilla(SCI_APPENDTEXT, s.length(), ScintillaBytesConstData(s));
2185
2186 SendScintilla(SCI_EMPTYUNDOBUFFER);
2187
2188 setReadOnly(ro);
2189 }
2190
2191
2192 // Insert the given text at the current position.
2193 void QsciScintilla::insert(const QString &text)
2194 {
2195 insertAtPos(text, -1);
2196 }
2197
2198
2199 // Insert the given text at the given line and offset.
2200 void QsciScintilla::insertAt(const QString &text, int line, int index)
2201 {
2202 insertAtPos(text, positionFromLineIndex(line, index));
2203 }
2204
2205
2206 // Insert the given text at the given position.
2207 void QsciScintilla::insertAtPos(const QString &text, int pos)
2208 {
2209 bool ro = ensureRW();
2210
2211 SendScintilla(SCI_BEGINUNDOACTION);
2212 SendScintilla(SCI_INSERTTEXT, pos,
2213 ScintillaBytesConstData(textAsBytes(text)));
2214 SendScintilla(SCI_ENDUNDOACTION);
2215
2216 setReadOnly(ro);
2217 }
2218
2219
2220 // Begin a sequence of undoable actions.
2221 void QsciScintilla::beginUndoAction()
2222 {
2223 SendScintilla(SCI_BEGINUNDOACTION);
2224 }
2225
2226
2227 // End a sequence of undoable actions.
2228 void QsciScintilla::endUndoAction()
2229 {
2230 SendScintilla(SCI_ENDUNDOACTION);
2231 }
2232
2233
2234 // Redo a sequence of actions.
2235 void QsciScintilla::redo()
2236 {
2237 SendScintilla(SCI_REDO);
2238 }
2239
2240
2241 // Undo a sequence of actions.
2242 void QsciScintilla::undo()
2243 {
2244 SendScintilla(SCI_UNDO);
2245 }
2246
2247
2248 // See if there is something to redo.
2249 bool QsciScintilla::isRedoAvailable() const
2250 {
2251 return SendScintilla(SCI_CANREDO);
2252 }
2253
2254
2255 // See if there is something to undo.
2256 bool QsciScintilla::isUndoAvailable() const
2257 {
2258 return SendScintilla(SCI_CANUNDO);
2259 }
2260
2261
2262 // Return the number of lines.
2263 int QsciScintilla::lines() const
2264 {
2265 return SendScintilla(SCI_GETLINECOUNT);
2266 }
2267
2268
2269 // Return the line at a position.
2270 int QsciScintilla::lineAt(const QPoint &pos) const
2271 {
2272 long chpos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, pos.x(), pos.y());
2273
2274 if (chpos < 0)
2275 return -1;
2276
2277 return SendScintilla(SCI_LINEFROMPOSITION, chpos);
2278 }
2279
2280
2281 // Return the length of a line.
2282 int QsciScintilla::lineLength(int line) const
2283 {
2284 if (line < 0 || line >= SendScintilla(SCI_GETLINECOUNT))
2285 return -1;
2286
2287 return SendScintilla(SCI_LINELENGTH, line);
2288 }
2289
2290
2291 // Return the length of the current text.
2292 int QsciScintilla::length() const
2293 {
2294 return SendScintilla(SCI_GETTEXTLENGTH);
2295 }
2296
2297
2298 // Remove any selected text.
2299 void QsciScintilla::removeSelectedText()
2300 {
2301 SendScintilla(SCI_REPLACESEL, "");
2302 }
2303
2304
2305 // Replace any selected text.
2306 void QsciScintilla::replaceSelectedText(const QString &text)
2307 {
2308 SendScintilla(SCI_REPLACESEL, ScintillaBytesConstData(textAsBytes(text)));
2309 }
2310
2311
2312 // Return the current selected text.
2313 QString QsciScintilla::selectedText() const
2314 {
2315 if (!selText)
2316 return QString();
2317
2318 char *buf = new char[SendScintilla(SCI_GETSELECTIONEND) - SendScintilla(SCI_GETSELECTIONSTART) + 1];
2319
2320 SendScintilla(SCI_GETSELTEXT, buf);
2321
2322 QString qs = bytesAsText(buf);
2323 delete[] buf;
2324
2325 return qs;
2326 }
2327
2328
2329 // Return the current text.
2330 QString QsciScintilla::text() const
2331 {
2332 int buflen = length() + 1;
2333 char *buf = new char[buflen];
2334
2335 SendScintilla(SCI_GETTEXT, buflen, buf);
2336
2337 QString qs = bytesAsText(buf);
2338 delete[] buf;
2339
2340 return qs;
2341 }
2342
2343
2344 // Return the text of a line.
2345 QString QsciScintilla::text(int line) const
2346 {
2347 int line_len = lineLength(line);
2348
2349 if (line_len < 1)
2350 return QString();
2351
2352 char *buf = new char[line_len + 1];
2353
2354 SendScintilla(SCI_GETLINE, line, buf);
2355 buf[line_len] = '\0';
2356
2357 QString qs = bytesAsText(buf);
2358 delete[] buf;
2359
2360 return qs;
2361 }
2362
2363
2364 // Return the text between two positions.
2365 QString QsciScintilla::text(int start, int end) const
2366 {
2367 char *buf = new char[end - start + 1];
2368 SendScintilla(SCI_GETTEXTRANGE, start, end, buf);
2369 QString text = bytesAsText(buf);
2370 delete[] buf;
2371
2372 return text;
2373 }
2374
2375
2376 // Return the text as encoded bytes between two positions.
2377 QByteArray QsciScintilla::bytes(int start, int end) const
2378 {
2379 QByteArray bytes(end - start + 1, '\0');
2380
2381 SendScintilla(SCI_GETTEXTRANGE, start, end, bytes.data());
2382
2383 return bytes;
2384 }
2385
2386
2387 // Set the given text.
2388 void QsciScintilla::setText(const QString &text)
2389 {
2390 bool ro = ensureRW();
2391
2392 SendScintilla(SCI_SETTEXT, ScintillaBytesConstData(textAsBytes(text)));
2393 SendScintilla(SCI_EMPTYUNDOBUFFER);
2394
2395 setReadOnly(ro);
2396 }
2397
2398
2399 // Get the cursor position
2400 void QsciScintilla::getCursorPosition(int *line, int *index) const
2401 {
2402 lineIndexFromPosition(SendScintilla(SCI_GETCURRENTPOS), line, index);
2403 }
2404
2405
2406 // Set the cursor position
2407 void QsciScintilla::setCursorPosition(int line, int index)
2408 {
2409 SendScintilla(SCI_GOTOPOS, positionFromLineIndex(line, index));
2410 }
2411
2412
2413 // Ensure the cursor is visible.
2414 void QsciScintilla::ensureCursorVisible()
2415 {
2416 SendScintilla(SCI_SCROLLCARET);
2417 }
2418
2419
2420 // Ensure a line is visible.
2421 void QsciScintilla::ensureLineVisible(int line)
2422 {
2423 SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, line);
2424 }
2425
2426
2427 // Copy text to the clipboard.
2428 void QsciScintilla::copy()
2429 {
2430 SendScintilla(SCI_COPY);
2431 }
2432
2433
2434 // Cut text to the clipboard.
2435 void QsciScintilla::cut()
2436 {
2437 SendScintilla(SCI_CUT);
2438 }
2439
2440
2441 // Paste text from the clipboard.
2442 void QsciScintilla::paste()
2443 {
2444 SendScintilla(SCI_PASTE);
2445 }
2446
2447
2448 // Select all text, or deselect any selected text.
2449 void QsciScintilla::selectAll(bool select)
2450 {
2451 if (select)
2452 SendScintilla(SCI_SELECTALL);
2453 else
2454 SendScintilla(SCI_SETANCHOR, SendScintilla(SCI_GETCURRENTPOS));
2455 }
2456
2457
2458 // Delete all text.
2459 void QsciScintilla::clear()
2460 {
2461 bool ro = ensureRW();
2462
2463 SendScintilla(SCI_CLEARALL);
2464 SendScintilla(SCI_EMPTYUNDOBUFFER);
2465
2466 setReadOnly(ro);
2467 }
2468
2469
2470 // Return the indentation of a line.
2471 int QsciScintilla::indentation(int line) const
2472 {
2473 return SendScintilla(SCI_GETLINEINDENTATION, line);
2474 }
2475
2476
2477 // Set the indentation of a line.
2478 void QsciScintilla::setIndentation(int line, int indentation)
2479 {
2480 SendScintilla(SCI_BEGINUNDOACTION);
2481 SendScintilla(SCI_SETLINEINDENTATION, line, indentation);
2482 SendScintilla(SCI_ENDUNDOACTION);
2483 }
2484
2485
2486 // Indent a line.
2487 void QsciScintilla::indent(int line)
2488 {
2489 setIndentation(line, indentation(line) + indentWidth());
2490 }
2491
2492
2493 // Unindent a line.
2494 void QsciScintilla::unindent(int line)
2495 {
2496 int newIndent = indentation(line) - indentWidth();
2497
2498 if (newIndent < 0)
2499 newIndent = 0;
2500
2501 setIndentation(line, newIndent);
2502 }
2503
2504
2505 // Return the indentation of the current line.
2506 int QsciScintilla::currentIndent() const
2507 {
2508 return indentation(SendScintilla(SCI_LINEFROMPOSITION,
2509 SendScintilla(SCI_GETCURRENTPOS)));
2510 }
2511
2512
2513 // Return the current indentation width.
2514 int QsciScintilla::indentWidth() const
2515 {
2516 int w = indentationWidth();
2517
2518 if (w == 0)
2519 w = tabWidth();
2520
2521 return w;
2522 }
2523
2524
2525 // Return the state of indentation guides.
2526 bool QsciScintilla::indentationGuides() const
2527 {
2528 return (SendScintilla(SCI_GETINDENTATIONGUIDES) != SC_IV_NONE);
2529 }
2530
2531
2532 // Enable and disable indentation guides.
2533 void QsciScintilla::setIndentationGuides(bool enable)
2534 {
2535 int iv;
2536
2537 if (!enable)
2538 iv = SC_IV_NONE;
2539 else if (lex.isNull())
2540 iv = SC_IV_REAL;
2541 else
2542 iv = lex->indentationGuideView();
2543
2544 SendScintilla(SCI_SETINDENTATIONGUIDES, iv);
2545 }
2546
2547
2548 // Set the background colour of indentation guides.
2549 void QsciScintilla::setIndentationGuidesBackgroundColor(const QColor &col)
2550 {
2551 SendScintilla(SCI_STYLESETBACK, STYLE_INDENTGUIDE, col);
2552 }
2553
2554
2555 // Set the foreground colour of indentation guides.
2556 void QsciScintilla::setIndentationGuidesForegroundColor(const QColor &col)
2557 {
2558 SendScintilla(SCI_STYLESETFORE, STYLE_INDENTGUIDE, col);
2559 }
2560
2561
2562 // Return the indentation width.
2563 int QsciScintilla::indentationWidth() const
2564 {
2565 return SendScintilla(SCI_GETINDENT);
2566 }
2567
2568
2569 // Set the indentation width.
2570 void QsciScintilla::setIndentationWidth(int width)
2571 {
2572 SendScintilla(SCI_SETINDENT, width);
2573 }
2574
2575
2576 // Return the tab width.
2577 int QsciScintilla::tabWidth() const
2578 {
2579 return SendScintilla(SCI_GETTABWIDTH);
2580 }
2581
2582
2583 // Set the tab width.
2584 void QsciScintilla::setTabWidth(int width)
2585 {
2586 SendScintilla(SCI_SETTABWIDTH, width);
2587 }
2588
2589
2590 // Return the effect of the backspace key.
2591 bool QsciScintilla::backspaceUnindents() const
2592 {
2593 return SendScintilla(SCI_GETBACKSPACEUNINDENTS);
2594 }
2595
2596
2597 // Set the effect of the backspace key.
2598 void QsciScintilla::setBackspaceUnindents(bool unindents)
2599 {
2600 SendScintilla(SCI_SETBACKSPACEUNINDENTS, unindents);
2601 }
2602
2603
2604 // Return the effect of the tab key.
2605 bool QsciScintilla::tabIndents() const
2606 {
2607 return SendScintilla(SCI_GETTABINDENTS);
2608 }
2609
2610
2611 // Set the effect of the tab key.
2612 void QsciScintilla::setTabIndents(bool indents)
2613 {
2614 SendScintilla(SCI_SETTABINDENTS, indents);
2615 }
2616
2617
2618 // Return the indentation use of tabs.
2619 bool QsciScintilla::indentationsUseTabs() const
2620 {
2621 return SendScintilla(SCI_GETUSETABS);
2622 }
2623
2624
2625 // Set the indentation use of tabs.
2626 void QsciScintilla::setIndentationsUseTabs(bool tabs)
2627 {
2628 SendScintilla(SCI_SETUSETABS, tabs);
2629 }
2630
2631
2632 // Return the number of margins.
2633 int QsciScintilla::margins() const
2634 {
2635 return SendScintilla(SCI_GETMARGINS);
2636 }
2637
2638
2639 // Set the number of margins.
2640 void QsciScintilla::setMargins(int margins)
2641 {
2642 SendScintilla(SCI_SETMARGINS, margins);
2643 }
2644
2645
2646 // Return the margin background colour.
2647 QColor QsciScintilla::marginBackgroundColor(int margin) const
2648 {
2649 return asQColor(SendScintilla(SCI_GETMARGINBACKN, margin));
2650 }
2651
2652
2653 // Set the margin background colour.
2654 void QsciScintilla::setMarginBackgroundColor(int margin, const QColor &col)
2655 {
2656 SendScintilla(SCI_SETMARGINBACKN, margin, col);
2657 }
2658
2659
2660 // Return the margin options.
2661 int QsciScintilla::marginOptions() const
2662 {
2663 return SendScintilla(SCI_GETMARGINOPTIONS);
2664 }
2665
2666
2667 // Set the margin options.
2668 void QsciScintilla::setMarginOptions(int options)
2669 {
2670 SendScintilla(SCI_SETMARGINOPTIONS, options);
2671 }
2672
2673
2674 // Return the margin type.
2675 QsciScintilla::MarginType QsciScintilla::marginType(int margin) const
2676 {
2677 return (MarginType)SendScintilla(SCI_GETMARGINTYPEN, margin);
2678 }
2679
2680
2681 // Set the margin type.
2682 void QsciScintilla::setMarginType(int margin, QsciScintilla::MarginType type)
2683 {
2684 SendScintilla(SCI_SETMARGINTYPEN, margin, type);
2685 }
2686
2687
2688 // Clear margin text.
2689 void QsciScintilla::clearMarginText(int line)
2690 {
2691 if (line < 0)
2692 SendScintilla(SCI_MARGINTEXTCLEARALL);
2693 else
2694 SendScintilla(SCI_MARGINSETTEXT, line, (const char *)0);
2695 }
2696
2697
2698 // Annotate a line.
2699 void QsciScintilla::setMarginText(int line, const QString &text, int style)
2700 {
2701 int style_offset = SendScintilla(SCI_MARGINGETSTYLEOFFSET);
2702
2703 SendScintilla(SCI_MARGINSETTEXT, line,
2704 ScintillaBytesConstData(textAsBytes(text)));
2705
2706 SendScintilla(SCI_MARGINSETSTYLE, line, style - style_offset);
2707 }
2708
2709
2710 // Annotate a line.
2711 void QsciScintilla::setMarginText(int line, const QString &text, const QsciStyle &style)
2712 {
2713 style.apply(this);
2714
2715 setMarginText(line, text, style.style());
2716 }
2717
2718
2719 // Annotate a line.
2720 void QsciScintilla::setMarginText(int line, const QsciStyledText &text)
2721 {
2722 text.apply(this);
2723
2724 setMarginText(line, text.text(), text.style());
2725 }
2726
2727
2728 // Annotate a line.
2729 void QsciScintilla::setMarginText(int line, const QList<QsciStyledText> &text)
2730 {
2731 char *styles;
2732 ScintillaBytes styled_text = styleText(text, &styles,
2733 SendScintilla(SCI_MARGINGETSTYLEOFFSET));
2734
2735 SendScintilla(SCI_MARGINSETTEXT, line,
2736 ScintillaBytesConstData(styled_text));
2737 SendScintilla(SCI_MARGINSETSTYLES, line, styles);
2738
2739 delete[] styles;
2740 }
2741
2742
2743 // Return the state of line numbers in a margin.
2744 bool QsciScintilla::marginLineNumbers(int margin) const
2745 {
2746 return SendScintilla(SCI_GETMARGINTYPEN, margin);
2747 }
2748
2749
2750 // Enable and disable line numbers in a margin.
2751 void QsciScintilla::setMarginLineNumbers(int margin, bool lnrs)
2752 {
2753 SendScintilla(SCI_SETMARGINTYPEN, margin,
2754 lnrs ? SC_MARGIN_NUMBER : SC_MARGIN_SYMBOL);
2755 }
2756
2757
2758 // Return the marker mask of a margin.
2759 int QsciScintilla::marginMarkerMask(int margin) const
2760 {
2761 return SendScintilla(SCI_GETMARGINMASKN, margin);
2762 }
2763
2764
2765 // Set the marker mask of a margin.
2766 void QsciScintilla::setMarginMarkerMask(int margin,int mask)
2767 {
2768 SendScintilla(SCI_SETMARGINMASKN, margin, mask);
2769 }
2770
2771
2772 // Return the state of a margin's sensitivity.
2773 bool QsciScintilla::marginSensitivity(int margin) const
2774 {
2775 return SendScintilla(SCI_GETMARGINSENSITIVEN, margin);
2776 }
2777
2778
2779 // Enable and disable a margin's sensitivity.
2780 void QsciScintilla::setMarginSensitivity(int margin,bool sens)
2781 {
2782 SendScintilla(SCI_SETMARGINSENSITIVEN, margin, sens);
2783 }
2784
2785
2786 // Return the width of a margin.
2787 int QsciScintilla::marginWidth(int margin) const
2788 {
2789 return SendScintilla(SCI_GETMARGINWIDTHN, margin);
2790 }
2791
2792
2793 // Set the width of a margin.
2794 void QsciScintilla::setMarginWidth(int margin, int width)
2795 {
2796 SendScintilla(SCI_SETMARGINWIDTHN, margin, width);
2797 }
2798
2799
2800 // Set the width of a margin to the width of some text.
2801 void QsciScintilla::setMarginWidth(int margin, const QString &s)
2802 {
2803 int width = SendScintilla(SCI_TEXTWIDTH, STYLE_LINENUMBER,
2804 ScintillaBytesConstData(textAsBytes(s)));
2805
2806 setMarginWidth(margin, width);
2807 }
2808
2809
2810 // Set the background colour of all margins.
2811 void QsciScintilla::setMarginsBackgroundColor(const QColor &col)
2812 {
2813 handleStylePaperChange(col, STYLE_LINENUMBER);
2814 }
2815
2816
2817 // Set the foreground colour of all margins.
2818 void QsciScintilla::setMarginsForegroundColor(const QColor &col)
2819 {
2820 handleStyleColorChange(col, STYLE_LINENUMBER);
2821 }
2822
2823
2824 // Set the font of all margins.
2825 void QsciScintilla::setMarginsFont(const QFont &f)
2826 {
2827 setStylesFont(f, STYLE_LINENUMBER);
2828 }
2829
2830
2831 // Define an indicator.
2832 int QsciScintilla::indicatorDefine(IndicatorStyle style, int indicatorNumber)
2833 {
2834 checkIndicator(indicatorNumber);
2835
2836 if (indicatorNumber >= 0)
2837 SendScintilla(SCI_INDICSETSTYLE, indicatorNumber,
2838 static_cast<long>(style));
2839
2840 return indicatorNumber;
2841 }
2842
2843
2844 // Return the state of an indicator being drawn under the text.
2845 bool QsciScintilla::indicatorDrawUnder(int indicatorNumber) const
2846 {
2847 if (indicatorNumber < 0 || indicatorNumber >= INDIC_IME)
2848 return false;
2849
2850 return SendScintilla(SCI_INDICGETUNDER, indicatorNumber);
2851 }
2852
2853
2854 // Set the state of indicators being drawn under the text.
2855 void QsciScintilla::setIndicatorDrawUnder(bool under, int indicatorNumber)
2856 {
2857 if (indicatorNumber < INDIC_IME)
2858 {
2859 // We ignore allocatedIndicators to allow any indicators defined
2860 // elsewhere (e.g. in lexers) to be set.
2861 if (indicatorNumber < 0)
2862 {
2863 for (int i = 0; i < INDIC_IME; ++i)
2864 SendScintilla(SCI_INDICSETUNDER, i, under);
2865 }
2866 else
2867 {
2868 SendScintilla(SCI_INDICSETUNDER, indicatorNumber, under);
2869 }
2870 }
2871 }
2872
2873
2874 // Set the indicator foreground colour.
2875 void QsciScintilla::setIndicatorForegroundColor(const QColor &col,
2876 int indicatorNumber)
2877 {
2878 if (indicatorNumber < INDIC_IME)
2879 {
2880 int alpha = col.alpha();
2881
2882 // We ignore allocatedIndicators to allow any indicators defined
2883 // elsewhere (e.g. in lexers) to be set.
2884 if (indicatorNumber < 0)
2885 {
2886 for (int i = 0; i < INDIC_IME; ++i)
2887 {
2888 SendScintilla(SCI_INDICSETFORE, i, col);
2889 SendScintilla(SCI_INDICSETALPHA, i, alpha);
2890 }
2891 }
2892 else
2893 {
2894 SendScintilla(SCI_INDICSETFORE, indicatorNumber, col);
2895 SendScintilla(SCI_INDICSETALPHA, indicatorNumber, alpha);
2896 }
2897 }
2898 }
2899
2900
2901 // Set the indicator hover foreground colour.
2902 void QsciScintilla::setIndicatorHoverForegroundColor(const QColor &col,
2903 int indicatorNumber)
2904 {
2905 if (indicatorNumber < INDIC_IME)
2906 {
2907 // We ignore allocatedIndicators to allow any indicators defined
2908 // elsewhere (e.g. in lexers) to be set.
2909 if (indicatorNumber < 0)
2910 {
2911 for (int i = 0; i < INDIC_IME; ++i)
2912 SendScintilla(SCI_INDICSETHOVERFORE, i, col);
2913 }
2914 else
2915 {
2916 SendScintilla(SCI_INDICSETHOVERFORE, indicatorNumber, col);
2917 }
2918 }
2919 }
2920
2921
2922 // Set the indicator hover style.
2923 void QsciScintilla::setIndicatorHoverStyle(IndicatorStyle style,
2924 int indicatorNumber)
2925 {
2926 if (indicatorNumber < INDIC_IME)
2927 {
2928 // We ignore allocatedIndicators to allow any indicators defined
2929 // elsewhere (e.g. in lexers) to be set.
2930 if (indicatorNumber < 0)
2931 {
2932 for (int i = 0; i < INDIC_IME; ++i)
2933 SendScintilla(SCI_INDICSETHOVERSTYLE, i,
2934 static_cast<long>(style));
2935 }
2936 else
2937 {
2938 SendScintilla(SCI_INDICSETHOVERSTYLE, indicatorNumber,
2939 static_cast<long>(style));
2940 }
2941 }
2942 }
2943
2944
2945 // Set the indicator outline colour.
2946 void QsciScintilla::setIndicatorOutlineColor(const QColor &col, int indicatorNumber)
2947 {
2948 if (indicatorNumber < INDIC_IME)
2949 {
2950 int alpha = col.alpha();
2951
2952 // We ignore allocatedIndicators to allow any indicators defined
2953 // elsewhere (e.g. in lexers) to be set.
2954 if (indicatorNumber < 0)
2955 {
2956 for (int i = 0; i < INDIC_IME; ++i)
2957 SendScintilla(SCI_INDICSETOUTLINEALPHA, i, alpha);
2958 }
2959 else
2960 {
2961 SendScintilla(SCI_INDICSETOUTLINEALPHA, indicatorNumber, alpha);
2962 }
2963 }
2964 }
2965
2966
2967 // Fill a range with an indicator.
2968 void QsciScintilla::fillIndicatorRange(int lineFrom, int indexFrom,
2969 int lineTo, int indexTo, int indicatorNumber)
2970 {
2971 if (indicatorNumber < INDIC_IME)
2972 {
2973 int start = positionFromLineIndex(lineFrom, indexFrom);
2974 int finish = positionFromLineIndex(lineTo, indexTo);
2975
2976 // We ignore allocatedIndicators to allow any indicators defined
2977 // elsewhere (e.g. in lexers) to be set.
2978 if (indicatorNumber < 0)
2979 {
2980 for (int i = 0; i < INDIC_IME; ++i)
2981 {
2982 SendScintilla(SCI_SETINDICATORCURRENT, i);
2983 SendScintilla(SCI_INDICATORFILLRANGE, start, finish - start);
2984 }
2985 }
2986 else
2987 {
2988 SendScintilla(SCI_SETINDICATORCURRENT, indicatorNumber);
2989 SendScintilla(SCI_INDICATORFILLRANGE, start, finish - start);
2990 }
2991 }
2992 }
2993
2994
2995 // Clear a range with an indicator.
2996 void QsciScintilla::clearIndicatorRange(int lineFrom, int indexFrom,
2997 int lineTo, int indexTo, int indicatorNumber)
2998 {
2999 if (indicatorNumber < INDIC_IME)
3000 {
3001 int start = positionFromLineIndex(lineFrom, indexFrom);
3002 int finish = positionFromLineIndex(lineTo, indexTo);
3003
3004 // We ignore allocatedIndicators to allow any indicators defined
3005 // elsewhere (e.g. in lexers) to be set.
3006 if (indicatorNumber < 0)
3007 {
3008 for (int i = 0; i < INDIC_IME; ++i)
3009 {
3010 SendScintilla(SCI_SETINDICATORCURRENT, i);
3011 SendScintilla(SCI_INDICATORCLEARRANGE, start, finish - start);
3012 }
3013 }
3014 else
3015 {
3016 SendScintilla(SCI_SETINDICATORCURRENT, indicatorNumber);
3017 SendScintilla(SCI_INDICATORCLEARRANGE, start, finish - start);
3018 }
3019 }
3020 }
3021
3022
3023 // Define a marker based on a symbol.
3024 int QsciScintilla::markerDefine(MarkerSymbol sym, int markerNumber)
3025 {
3026 checkMarker(markerNumber);
3027
3028 if (markerNumber >= 0)
3029 SendScintilla(SCI_MARKERDEFINE, markerNumber, static_cast<long>(sym));
3030
3031 return markerNumber;
3032 }
3033
3034
3035 // Define a marker based on a character.
3036 int QsciScintilla::markerDefine(char ch, int markerNumber)
3037 {
3038 checkMarker(markerNumber);
3039
3040 if (markerNumber >= 0)
3041 SendScintilla(SCI_MARKERDEFINE, markerNumber,
3042 static_cast<long>(SC_MARK_CHARACTER) + ch);
3043
3044 return markerNumber;
3045 }
3046
3047
3048 // Define a marker based on a QPixmap.
3049 int QsciScintilla::markerDefine(const QPixmap &pm, int markerNumber)
3050 {
3051 checkMarker(markerNumber);
3052
3053 if (markerNumber >= 0)
3054 SendScintilla(SCI_MARKERDEFINEPIXMAP, markerNumber, pm);
3055
3056 return markerNumber;
3057 }
3058
3059
3060 // Define a marker based on a QImage.
3061 int QsciScintilla::markerDefine(const QImage &im, int markerNumber)
3062 {
3063 checkMarker(markerNumber);
3064
3065 if (markerNumber >= 0)
3066 {
3067 SendScintilla(SCI_RGBAIMAGESETHEIGHT, im.height());
3068 SendScintilla(SCI_RGBAIMAGESETWIDTH, im.width());
3069 SendScintilla(SCI_MARKERDEFINERGBAIMAGE, markerNumber, im);
3070 }
3071
3072 return markerNumber;
3073 }
3074
3075
3076 // Add a marker to a line.
3077 int QsciScintilla::markerAdd(int linenr, int markerNumber)
3078 {
3079 if (markerNumber < 0 || markerNumber > MARKER_MAX || (allocatedMarkers & (1 << markerNumber)) == 0)
3080 return -1;
3081
3082 return SendScintilla(SCI_MARKERADD, linenr, markerNumber);
3083 }
3084
3085
3086 // Get the marker mask for a line.
3087 unsigned QsciScintilla::markersAtLine(int linenr) const
3088 {
3089 return SendScintilla(SCI_MARKERGET, linenr);
3090 }
3091
3092
3093 // Delete a marker from a line.
3094 void QsciScintilla::markerDelete(int linenr, int markerNumber)
3095 {
3096 if (markerNumber <= MARKER_MAX)
3097 {
3098 if (markerNumber < 0)
3099 {
3100 unsigned am = allocatedMarkers;
3101
3102 for (int m = 0; m <= MARKER_MAX; ++m)
3103 {
3104 if (am & 1)
3105 SendScintilla(SCI_MARKERDELETE, linenr, m);
3106
3107 am >>= 1;
3108 }
3109 }
3110 else if (allocatedMarkers & (1 << markerNumber))
3111 SendScintilla(SCI_MARKERDELETE, linenr, markerNumber);
3112 }
3113 }
3114
3115
3116 // Delete a marker from the text.
3117 void QsciScintilla::markerDeleteAll(int markerNumber)
3118 {
3119 if (markerNumber <= MARKER_MAX)
3120 {
3121 if (markerNumber < 0)
3122 SendScintilla(SCI_MARKERDELETEALL, -1);
3123 else if (allocatedMarkers & (1 << markerNumber))
3124 SendScintilla(SCI_MARKERDELETEALL, markerNumber);
3125 }
3126 }
3127
3128
3129 // Delete a marker handle from the text.
3130 void QsciScintilla::markerDeleteHandle(int mhandle)
3131 {
3132 SendScintilla(SCI_MARKERDELETEHANDLE, mhandle);
3133 }
3134
3135
3136 // Return the line containing a marker instance.
3137 int QsciScintilla::markerLine(int mhandle) const
3138 {
3139 return SendScintilla(SCI_MARKERLINEFROMHANDLE, mhandle);
3140 }
3141
3142
3143 // Search forwards for a marker.
3144 int QsciScintilla::markerFindNext(int linenr, unsigned mask) const
3145 {
3146 return SendScintilla(SCI_MARKERNEXT, linenr, mask);
3147 }
3148
3149
3150 // Search backwards for a marker.
3151 int QsciScintilla::markerFindPrevious(int linenr, unsigned mask) const
3152 {
3153 return SendScintilla(SCI_MARKERPREVIOUS, linenr, mask);
3154 }
3155
3156
3157 // Set the marker background colour.
3158 void QsciScintilla::setMarkerBackgroundColor(const QColor &col, int markerNumber)
3159 {
3160 if (markerNumber <= MARKER_MAX)
3161 {
3162 int alpha = col.alpha();
3163
3164 // An opaque background would make the text invisible.
3165 if (alpha == 255)
3166 alpha = SC_ALPHA_NOALPHA;
3167
3168 if (markerNumber < 0)
3169 {
3170 unsigned am = allocatedMarkers;
3171
3172 for (int m = 0; m <= MARKER_MAX; ++m)
3173 {
3174 if (am & 1)
3175 {
3176 SendScintilla(SCI_MARKERSETBACK, m, col);
3177 SendScintilla(SCI_MARKERSETALPHA, m, alpha);
3178 }
3179
3180 am >>= 1;
3181 }
3182 }
3183 else if (allocatedMarkers & (1 << markerNumber))
3184 {
3185 SendScintilla(SCI_MARKERSETBACK, markerNumber, col);
3186 SendScintilla(SCI_MARKERSETALPHA, markerNumber, alpha);
3187 }
3188 }
3189 }
3190
3191
3192 // Set the marker foreground colour.
3193 void QsciScintilla::setMarkerForegroundColor(const QColor &col, int markerNumber)
3194 {
3195 if (markerNumber <= MARKER_MAX)
3196 {
3197 if (markerNumber < 0)
3198 {
3199 unsigned am = allocatedMarkers;
3200
3201 for (int m = 0; m <= MARKER_MAX; ++m)
3202 {
3203 if (am & 1)
3204 SendScintilla(SCI_MARKERSETFORE, m, col);
3205
3206 am >>= 1;
3207 }
3208 }
3209 else if (allocatedMarkers & (1 << markerNumber))
3210 {
3211 SendScintilla(SCI_MARKERSETFORE, markerNumber, col);
3212 }
3213 }
3214 }
3215
3216
3217 // Check a marker, allocating a marker number if necessary.
3218 void QsciScintilla::checkMarker(int &markerNumber)
3219 {
3220 allocateId(markerNumber, allocatedMarkers, 0, MARKER_MAX);
3221 }
3222
3223
3224 // Check an indicator, allocating an indicator number if necessary.
3225 void QsciScintilla::checkIndicator(int &indicatorNumber)
3226 {
3227 allocateId(indicatorNumber, allocatedIndicators, INDIC_CONTAINER,
3228 INDIC_IME - 1);
3229 }
3230
3231
3232 // Make sure an identifier is valid and allocate it if necessary.
3233 void QsciScintilla::allocateId(int &id, unsigned &allocated, int min, int max)
3234 {
3235 if (id >= 0)
3236 {
3237 // Note that we allow existing identifiers to be explicitly redefined.
3238 if (id > max)
3239 id = -1;
3240 }
3241 else
3242 {
3243 unsigned aids = allocated >> min;
3244
3245 // Find the smallest unallocated identifier.
3246 for (id = min; id <= max; ++id)
3247 {
3248 if ((aids & 1) == 0)
3249 break;
3250
3251 aids >>= 1;
3252 }
3253 }
3254
3255 // Allocate the identifier if it is valid.
3256 if (id >= 0)
3257 allocated |= (1 << id);
3258 }
3259
3260
3261 // Reset the fold margin colours.
3262 void QsciScintilla::resetFoldMarginColors()
3263 {
3264 SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 0, 0L);
3265 SendScintilla(SCI_SETFOLDMARGINCOLOUR, 0, 0L);
3266 }
3267
3268
3269 // Set the fold margin colours.
3270 void QsciScintilla::setFoldMarginColors(const QColor &fore, const QColor &back)
3271 {
3272 SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 1, fore);
3273 SendScintilla(SCI_SETFOLDMARGINCOLOUR, 1, back);
3274 }
3275
3276
3277 // Set the call tips background colour.
3278 void QsciScintilla::setCallTipsBackgroundColor(const QColor &col)
3279 {
3280 SendScintilla(SCI_CALLTIPSETBACK, col);
3281 }
3282
3283
3284 // Set the call tips foreground colour.
3285 void QsciScintilla::setCallTipsForegroundColor(const QColor &col)
3286 {
3287 SendScintilla(SCI_CALLTIPSETFORE, col);
3288 }
3289
3290
3291 // Set the call tips highlight colour.
3292 void QsciScintilla::setCallTipsHighlightColor(const QColor &col)
3293 {
3294 SendScintilla(SCI_CALLTIPSETFOREHLT, col);
3295 }
3296
3297
3298 // Set the matched brace background colour.
3299 void QsciScintilla::setMatchedBraceBackgroundColor(const QColor &col)
3300 {
3301 SendScintilla(SCI_STYLESETBACK, STYLE_BRACELIGHT, col);
3302 }
3303
3304
3305 // Set the matched brace foreground colour.
3306 void QsciScintilla::setMatchedBraceForegroundColor(const QColor &col)
3307 {
3308 SendScintilla(SCI_STYLESETFORE, STYLE_BRACELIGHT, col);
3309 }
3310
3311
3312 // Set the matched brace indicator.
3313 void QsciScintilla::setMatchedBraceIndicator(int indicatorNumber)
3314 {
3315 SendScintilla(SCI_BRACEHIGHLIGHTINDICATOR, 1, indicatorNumber);
3316 }
3317
3318
3319 // Reset the matched brace indicator.
3320 void QsciScintilla::resetMatchedBraceIndicator()
3321 {
3322 SendScintilla(SCI_BRACEHIGHLIGHTINDICATOR, 0, 0L);
3323 }
3324
3325
3326 // Set the unmatched brace background colour.
3327 void QsciScintilla::setUnmatchedBraceBackgroundColor(const QColor &col)
3328 {
3329 SendScintilla(SCI_STYLESETBACK, STYLE_BRACEBAD, col);
3330 }
3331
3332
3333 // Set the unmatched brace foreground colour.
3334 void QsciScintilla::setUnmatchedBraceForegroundColor(const QColor &col)
3335 {
3336 SendScintilla(SCI_STYLESETFORE, STYLE_BRACEBAD, col);
3337 }
3338
3339
3340 // Set the unmatched brace indicator.
3341 void QsciScintilla::setUnmatchedBraceIndicator(int indicatorNumber)
3342 {
3343 SendScintilla(SCI_BRACEBADLIGHTINDICATOR, 1, indicatorNumber);
3344 }
3345
3346
3347 // Reset the unmatched brace indicator.
3348 void QsciScintilla::resetUnmatchedBraceIndicator()
3349 {
3350 SendScintilla(SCI_BRACEBADLIGHTINDICATOR, 0, 0L);
3351 }
3352
3353
3354 // Detach any lexer.
3355 void QsciScintilla::detachLexer()
3356 {
3357 if (!lex.isNull())
3358 {
3359 lex->setEditor(0);
3360 lex->disconnect(this);
3361
3362 SendScintilla(SCI_STYLERESETDEFAULT);
3363 SendScintilla(SCI_STYLECLEARALL);
3364 }
3365 }
3366
3367
3368 // Set the lexer.
3369 void QsciScintilla::setLexer(QsciLexer *lexer)
3370 {
3371 // Detach any current lexer.
3372 detachLexer();
3373
3374 // Connect up the new lexer.
3375 lex = lexer;
3376
3377 if (lex)
3378 {
3379 SendScintilla(SCI_CLEARDOCUMENTSTYLE);
3380
3381 if (lex->lexer())
3382 SendScintilla(SCI_SETLEXERLANGUAGE, lex->lexer());
3383 else
3384 SendScintilla(SCI_SETLEXER, lex->lexerId());
3385
3386 lex->setEditor(this);
3387
3388 connect(lex,SIGNAL(colorChanged(const QColor &, int)),
3389 SLOT(handleStyleColorChange(const QColor &, int)));
3390 connect(lex,SIGNAL(eolFillChanged(bool, int)),
3391 SLOT(handleStyleEolFillChange(bool, int)));
3392 connect(lex,SIGNAL(fontChanged(const QFont &, int)),
3393 SLOT(handleStyleFontChange(const QFont &, int)));
3394 connect(lex,SIGNAL(paperChanged(const QColor &, int)),
3395 SLOT(handleStylePaperChange(const QColor &, int)));
3396 connect(lex,SIGNAL(propertyChanged(const char *, const char *)),
3397 SLOT(handlePropertyChange(const char *, const char *)));
3398
3399 SendScintilla(SCI_SETPROPERTY, "fold", "1");
3400 SendScintilla(SCI_SETPROPERTY, "fold.html", "1");
3401
3402 // Set the keywords. Scintilla allows for sets numbered 0 to
3403 // KEYWORDSET_MAX (although the lexers only seem to exploit 0 to
3404 // KEYWORDSET_MAX - 1). We number from 1 in line with SciTE's property
3405 // files.
3406 for (int k = 0; k <= KEYWORDSET_MAX; ++k)
3407 {
3408 const char *kw = lex -> keywords(k + 1);
3409
3410 if (!kw)
3411 kw = "";
3412
3413 SendScintilla(SCI_SETKEYWORDS, k, kw);
3414 }
3415
3416 // Initialise each style. Do the default first so its (possibly
3417 // incorrect) font setting gets reset when style 0 is set.
3418 setLexerStyle(STYLE_DEFAULT);
3419
3420 for (int s = 0; s <= STYLE_MAX; ++s)
3421 if (!lex->description(s).isEmpty())
3422 setLexerStyle(s);
3423
3424 // Initialise the properties.
3425 lex->refreshProperties();
3426
3427 // Set the auto-completion fillups and word separators.
3428 setAutoCompletionFillupsEnabled(fillups_enabled);
3429 wseps = lex->autoCompletionWordSeparators();
3430
3431 wchars = lex->wordCharacters();
3432
3433 if (!wchars)
3434 wchars = defaultWordChars;
3435
3436 SendScintilla(SCI_AUTOCSETIGNORECASE, !lex->caseSensitive());
3437
3438 recolor();
3439 }
3440 else
3441 {
3442 SendScintilla(SCI_SETLEXER, SCLEX_CONTAINER);
3443
3444 setColor(nl_text_colour);
3445 setPaper(nl_paper_colour);
3446
3447 SendScintilla(SCI_AUTOCSETFILLUPS, "");
3448 SendScintilla(SCI_AUTOCSETIGNORECASE, false);
3449 wseps.clear();
3450 wchars = defaultWordChars;
3451 }
3452 }
3453
3454
3455 // Set a particular style of the current lexer.
3456 void QsciScintilla::setLexerStyle(int style)
3457 {
3458 handleStyleColorChange(lex->color(style), style);
3459 handleStyleEolFillChange(lex->eolFill(style), style);
3460 handleStyleFontChange(lex->font(style), style);
3461 handleStylePaperChange(lex->paper(style), style);
3462 }
3463
3464
3465 // Get the current lexer.
3466 QsciLexer *QsciScintilla::lexer() const
3467 {
3468 return lex;
3469 }
3470
3471
3472 // Handle a change in lexer style foreground colour.
3473 void QsciScintilla::handleStyleColorChange(const QColor &c, int style)
3474 {
3475 SendScintilla(SCI_STYLESETFORE, style, c);
3476 }
3477
3478
3479 // Handle a change in lexer style end-of-line fill.
3480 void QsciScintilla::handleStyleEolFillChange(bool eolfill, int style)
3481 {
3482 SendScintilla(SCI_STYLESETEOLFILLED, style, eolfill);
3483 }
3484
3485
3486 // Handle a change in lexer style font.
3487 void QsciScintilla::handleStyleFontChange(const QFont &f, int style)
3488 {
3489 setStylesFont(f, style);
3490
3491 if (style == lex->braceStyle())
3492 {
3493 setStylesFont(f, STYLE_BRACELIGHT);
3494 setStylesFont(f, STYLE_BRACEBAD);
3495 }
3496 }
3497
3498
3499 // Set the font for a style.
3500 void QsciScintilla::setStylesFont(const QFont &f, int style)
3501 {
3502 SendScintilla(SCI_STYLESETFONT, style, f.family().toLatin1().data());
3503 SendScintilla(SCI_STYLESETSIZEFRACTIONAL, style,
3504 long(f.pointSizeF() * SC_FONT_SIZE_MULTIPLIER));
3505
3506 // Pass the Qt weight via the back door.
3507 SendScintilla(SCI_STYLESETWEIGHT, style, -f.weight());
3508
3509 SendScintilla(SCI_STYLESETITALIC, style, f.italic());
3510 SendScintilla(SCI_STYLESETUNDERLINE, style, f.underline());
3511
3512 // Tie the font settings of the default style to that of style 0 (the style
3513 // conventionally used for whitespace by lexers). This is needed so that
3514 // fold marks, indentations, edge columns etc are set properly.
3515 if (style == 0)
3516 setStylesFont(f, STYLE_DEFAULT);
3517 }
3518
3519
3520 // Handle a change in lexer style background colour.
3521 void QsciScintilla::handleStylePaperChange(const QColor &c, int style)
3522 {
3523 SendScintilla(SCI_STYLESETBACK, style, c);
3524 }
3525
3526
3527 // Handle a change in lexer property.
3528 void QsciScintilla::handlePropertyChange(const char *prop, const char *val)
3529 {
3530 SendScintilla(SCI_SETPROPERTY, prop, val);
3531 }
3532
3533
3534 // Handle a change to the user visible user interface.
3535 void QsciScintilla::handleUpdateUI(int)
3536 {
3537 int newPos = SendScintilla(SCI_GETCURRENTPOS);
3538
3539 if (newPos != oldPos)
3540 {
3541 oldPos = newPos;
3542
3543 int line = SendScintilla(SCI_LINEFROMPOSITION, newPos);
3544 int col = SendScintilla(SCI_GETCOLUMN, newPos);
3545
3546 emit cursorPositionChanged(line, col);
3547 }
3548
3549 if (braceMode != NoBraceMatch)
3550 braceMatch();
3551 }
3552
3553
3554 // Handle brace matching.
3555 void QsciScintilla::braceMatch()
3556 {
3557 long braceAtCaret, braceOpposite;
3558
3559 findMatchingBrace(braceAtCaret, braceOpposite, braceMode);
3560
3561 if (braceAtCaret >= 0 && braceOpposite < 0)
3562 {
3563 SendScintilla(SCI_BRACEBADLIGHT, braceAtCaret);
3564 SendScintilla(SCI_SETHIGHLIGHTGUIDE, 0UL);
3565 }
3566 else
3567 {
3568 char chBrace = SendScintilla(SCI_GETCHARAT, braceAtCaret);
3569
3570 SendScintilla(SCI_BRACEHIGHLIGHT, braceAtCaret, braceOpposite);
3571
3572 long columnAtCaret = SendScintilla(SCI_GETCOLUMN, braceAtCaret);
3573 long columnOpposite = SendScintilla(SCI_GETCOLUMN, braceOpposite);
3574
3575 if (chBrace == ':')
3576 {
3577 long lineStart = SendScintilla(SCI_LINEFROMPOSITION, braceAtCaret);
3578 long indentPos = SendScintilla(SCI_GETLINEINDENTPOSITION,
3579 lineStart);
3580 long indentPosNext = SendScintilla(SCI_GETLINEINDENTPOSITION,
3581 lineStart + 1);
3582
3583 columnAtCaret = SendScintilla(SCI_GETCOLUMN, indentPos);
3584
3585 long columnAtCaretNext = SendScintilla(SCI_GETCOLUMN,
3586 indentPosNext);
3587 long indentSize = SendScintilla(SCI_GETINDENT);
3588
3589 if (columnAtCaretNext - indentSize > 1)
3590 columnAtCaret = columnAtCaretNext - indentSize;
3591
3592 if (columnOpposite == 0)
3593 columnOpposite = columnAtCaret;
3594 }
3595
3596 long column = columnAtCaret;
3597
3598 if (column > columnOpposite)
3599 column = columnOpposite;
3600
3601 SendScintilla(SCI_SETHIGHLIGHTGUIDE, column);
3602 }
3603 }
3604
3605
3606 // Check if the character at a position is a brace.
3607 long QsciScintilla::checkBrace(long pos, int brace_style, bool &colonMode)
3608 {
3609 long brace_pos = -1;
3610 char ch = SendScintilla(SCI_GETCHARAT, pos);
3611
3612 if (ch == ':')
3613 {
3614 // A bit of a hack, we should really use a virtual.
3615 if (!lex.isNull() && qstrcmp(lex->lexer(), "python") == 0)
3616 {
3617 brace_pos = pos;
3618 colonMode = true;
3619 }
3620 }
3621 else if (ch && strchr("[](){}<>", ch))
3622 {
3623 if (brace_style < 0)
3624 brace_pos = pos;
3625 else
3626 {
3627 int style = SendScintilla(SCI_GETSTYLEAT, pos) & 0x1f;
3628
3629 if (style == brace_style)
3630 brace_pos = pos;
3631 }
3632 }
3633
3634 return brace_pos;
3635 }
3636
3637
3638 // Find a brace and it's match. Return true if the current position is inside
3639 // a pair of braces.
3640 bool QsciScintilla::findMatchingBrace(long &brace, long &other, BraceMatch mode)
3641 {
3642 bool colonMode = false;
3643 int brace_style = (lex.isNull() ? -1 : lex->braceStyle());
3644
3645 brace = -1;
3646 other = -1;
3647
3648 long caretPos = SendScintilla(SCI_GETCURRENTPOS);
3649
3650 if (caretPos > 0)
3651 brace = checkBrace(caretPos - 1, brace_style, colonMode);
3652
3653 bool isInside = false;
3654
3655 if (brace < 0 && mode == SloppyBraceMatch)
3656 {
3657 brace = checkBrace(caretPos, brace_style, colonMode);
3658
3659 if (brace >= 0 && !colonMode)
3660 isInside = true;
3661 }
3662
3663 if (brace >= 0)
3664 {
3665 if (colonMode)
3666 {
3667 // Find the end of the Python indented block.
3668 long lineStart = SendScintilla(SCI_LINEFROMPOSITION, brace);
3669 long lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, lineStart, -1);
3670
3671 other = SendScintilla(SCI_GETLINEENDPOSITION, lineMaxSubord);
3672 }
3673 else
3674 other = SendScintilla(SCI_BRACEMATCH, brace, 0L);
3675
3676 if (other > brace)
3677 isInside = !isInside;
3678 }
3679
3680 return isInside;
3681 }
3682
3683
3684 // Move to the matching brace.
3685 void QsciScintilla::moveToMatchingBrace()
3686 {
3687 gotoMatchingBrace(false);
3688 }
3689
3690
3691 // Select to the matching brace.
3692 void QsciScintilla::selectToMatchingBrace()
3693 {
3694 gotoMatchingBrace(true);
3695 }
3696
3697
3698 // Move to the matching brace and optionally select the text.
3699 void QsciScintilla::gotoMatchingBrace(bool select)
3700 {
3701 long braceAtCaret;
3702 long braceOpposite;
3703
3704 bool isInside = findMatchingBrace(braceAtCaret, braceOpposite,
3705 SloppyBraceMatch);
3706
3707 if (braceOpposite >= 0)
3708 {
3709 // Convert the character positions into caret positions based on
3710 // whether the caret position was inside or outside the braces.
3711 if (isInside)
3712 {
3713 if (braceOpposite > braceAtCaret)
3714 braceAtCaret++;
3715 else
3716 braceOpposite++;
3717 }
3718 else
3719 {
3720 if (braceOpposite > braceAtCaret)
3721 braceOpposite++;
3722 else
3723 braceAtCaret++;
3724 }
3725
3726 ensureLineVisible(SendScintilla(SCI_LINEFROMPOSITION, braceOpposite));
3727
3728 if (select)
3729 SendScintilla(SCI_SETSEL, braceAtCaret, braceOpposite);
3730 else
3731 SendScintilla(SCI_SETSEL, braceOpposite, braceOpposite);
3732 }
3733 }
3734
3735
3736 // Return a position from a line number and an index within the line.
3737 int QsciScintilla::positionFromLineIndex(int line, int index) const
3738 {
3739 int pos = SendScintilla(SCI_POSITIONFROMLINE, line);
3740
3741 // Allow for multi-byte characters.
3742 for(int i = 0; i < index; i++)
3743 pos = SendScintilla(SCI_POSITIONAFTER, pos);
3744
3745 return pos;
3746 }
3747
3748
3749 // Return a line number and an index within the line from a position.
3750 void QsciScintilla::lineIndexFromPosition(int position, int *line, int *index) const
3751 {
3752 int lin = SendScintilla(SCI_LINEFROMPOSITION, position);
3753 int linpos = SendScintilla(SCI_POSITIONFROMLINE, lin);
3754 int indx = 0;
3755
3756 // Allow for multi-byte characters.
3757 while (linpos < position)
3758 {
3759 int new_linpos = SendScintilla(SCI_POSITIONAFTER, linpos);
3760
3761 // If the position hasn't moved then we must be at the end of the text
3762 // (which implies that the position passed was beyond the end of the
3763 // text).
3764 if (new_linpos == linpos)
3765 break;
3766
3767 linpos = new_linpos;
3768 ++indx;
3769 }
3770
3771 *line = lin;
3772 *index = indx;
3773 }
3774
3775
3776 // Set the source of the automatic auto-completion list.
3777 void QsciScintilla::setAutoCompletionSource(AutoCompletionSource source)
3778 {
3779 acSource = source;
3780 }
3781
3782
3783 // Set the threshold for automatic auto-completion.
3784 void QsciScintilla::setAutoCompletionThreshold(int thresh)
3785 {
3786 acThresh = thresh;
3787 }
3788
3789
3790 // Set the auto-completion word separators if there is no current lexer.
3791 void QsciScintilla::setAutoCompletionWordSeparators(const QStringList &separators)
3792 {
3793 if (lex.isNull())
3794 wseps = separators;
3795 }
3796
3797
3798 // Explicitly auto-complete from all sources.
3799 void QsciScintilla::autoCompleteFromAll()
3800 {
3801 startAutoCompletion(AcsAll, false, use_single != AcusNever);
3802 }
3803
3804
3805 // Explicitly auto-complete from the APIs.
3806 void QsciScintilla::autoCompleteFromAPIs()
3807 {
3808 startAutoCompletion(AcsAPIs, false, use_single != AcusNever);
3809 }
3810
3811
3812 // Explicitly auto-complete from the document.
3813 void QsciScintilla::autoCompleteFromDocument()
3814 {
3815 startAutoCompletion(AcsDocument, false, use_single != AcusNever);
3816 }
3817
3818
3819 // Check if a character can be in a word.
3820 bool QsciScintilla::isWordCharacter(char ch) const
3821 {
3822 return (strchr(wchars, ch) != NULL);
3823 }
3824
3825
3826 // Return the set of valid word characters.
3827 const char *QsciScintilla::wordCharacters() const
3828 {
3829 return wchars;
3830 }
3831
3832
3833 // Recolour the document.
3834 void QsciScintilla::recolor(int start, int end)
3835 {
3836 SendScintilla(SCI_COLOURISE, start, end);
3837 }
3838
3839
3840 // Registered a QPixmap image.
3841 void QsciScintilla::registerImage(int id, const QPixmap &pm)
3842 {
3843 SendScintilla(SCI_REGISTERIMAGE, id, pm);
3844 }
3845
3846
3847 // Registered a QImage image.
3848 void QsciScintilla::registerImage(int id, const QImage &im)
3849 {
3850 SendScintilla(SCI_RGBAIMAGESETHEIGHT, im.height());
3851 SendScintilla(SCI_RGBAIMAGESETWIDTH, im.width());
3852 SendScintilla(SCI_REGISTERRGBAIMAGE, id, im);
3853 }
3854
3855
3856 // Clear all registered images.
3857 void QsciScintilla::clearRegisteredImages()
3858 {
3859 SendScintilla(SCI_CLEARREGISTEREDIMAGES);
3860 }
3861
3862
3863 // Enable auto-completion fill-ups.
3864 void QsciScintilla::setAutoCompletionFillupsEnabled(bool enable)
3865 {
3866 const char *fillups;
3867
3868 if (!enable)
3869 fillups = "";
3870 else if (!lex.isNull())
3871 fillups = lex->autoCompletionFillups();
3872 else
3873 fillups = explicit_fillups.data();
3874
3875 SendScintilla(SCI_AUTOCSETFILLUPS, fillups);
3876
3877 fillups_enabled = enable;
3878 }
3879
3880
3881 // See if auto-completion fill-ups are enabled.
3882 bool QsciScintilla::autoCompletionFillupsEnabled() const
3883 {
3884 return fillups_enabled;
3885 }
3886
3887
3888 // Set the fill-up characters for auto-completion if there is no current lexer.
3889 void QsciScintilla::setAutoCompletionFillups(const char *fillups)
3890 {
3891 explicit_fillups = fillups;
3892 setAutoCompletionFillupsEnabled(fillups_enabled);
3893 }
3894
3895
3896 // Set the case sensitivity for auto-completion.
3897 void QsciScintilla::setAutoCompletionCaseSensitivity(bool cs)
3898 {
3899 SendScintilla(SCI_AUTOCSETIGNORECASE, !cs);
3900 }
3901
3902
3903 // Return the case sensitivity for auto-completion.
3904 bool QsciScintilla::autoCompletionCaseSensitivity() const
3905 {
3906 return !SendScintilla(SCI_AUTOCGETIGNORECASE);
3907 }
3908
3909
3910 // Set the replace word mode for auto-completion.
3911 void QsciScintilla::setAutoCompletionReplaceWord(bool replace)
3912 {
3913 SendScintilla(SCI_AUTOCSETDROPRESTOFWORD, replace);
3914 }
3915
3916
3917 // Return the replace word mode for auto-completion.
3918 bool QsciScintilla::autoCompletionReplaceWord() const
3919 {
3920 return SendScintilla(SCI_AUTOCGETDROPRESTOFWORD);
3921 }
3922
3923
3924 // Set the single item mode for auto-completion.
3925 void QsciScintilla::setAutoCompletionUseSingle(AutoCompletionUseSingle single)
3926 {
3927 use_single = single;
3928 }
3929
3930
3931 // Return the single item mode for auto-completion.
3932 QsciScintilla::AutoCompletionUseSingle QsciScintilla::autoCompletionUseSingle() const
3933 {
3934 return use_single;
3935 }
3936
3937
3938 // Set the single item mode for auto-completion (deprecated).
3939 void QsciScintilla::setAutoCompletionShowSingle(bool single)
3940 {
3941 use_single = (single ? AcusExplicit : AcusNever);
3942 }
3943
3944
3945 // Return the single item mode for auto-completion (deprecated).
3946 bool QsciScintilla::autoCompletionShowSingle() const
3947 {
3948 return (use_single != AcusNever);
3949 }
3950
3951
3952 // Set current call tip position.
3953 void QsciScintilla::setCallTipsPosition(CallTipsPosition position)
3954 {
3955 SendScintilla(SCI_CALLTIPSETPOSITION, (position == CallTipsAboveText));
3956 call_tips_position = position;
3957 }
3958
3959
3960 // Set current call tip style.
3961 void QsciScintilla::setCallTipsStyle(CallTipsStyle style)
3962 {
3963 call_tips_style = style;
3964 }
3965
3966
3967 // Set maximum number of call tips displayed.
3968 void QsciScintilla::setCallTipsVisible(int nr)
3969 {
3970 maxCallTips = nr;
3971 }
3972
3973
3974 // Set the document to display.
3975 void QsciScintilla::setDocument(const QsciDocument &document)
3976 {
3977 if (doc.pdoc != document.pdoc)
3978 {
3979 doc.undisplay(this);
3980 doc.attach(document);
3981 doc.display(this,&document);
3982 }
3983 }
3984
3985
3986 // Ensure the document is read-write and return true if was was read-only.
3987 bool QsciScintilla::ensureRW()
3988 {
3989 bool ro = isReadOnly();
3990
3991 if (ro)
3992 setReadOnly(false);
3993
3994 return ro;
3995 }
3996
3997
3998 // Return the number of the first visible line.
3999 int QsciScintilla::firstVisibleLine() const
4000 {
4001 return SendScintilla(SCI_GETFIRSTVISIBLELINE);
4002 }
4003
4004
4005 // Set the number of the first visible line.
4006 void QsciScintilla::setFirstVisibleLine(int linenr)
4007 {
4008 SendScintilla(SCI_SETFIRSTVISIBLELINE, linenr);
4009 }
4010
4011
4012 // Return the height in pixels of the text in a particular line.
4013 int QsciScintilla::textHeight(int linenr) const
4014 {
4015 return SendScintilla(SCI_TEXTHEIGHT, linenr);
4016 }
4017
4018
4019 // See if auto-completion or user list is active.
4020 bool QsciScintilla::isListActive() const
4021 {
4022 return SendScintilla(SCI_AUTOCACTIVE);
4023 }
4024
4025
4026 // Cancel any current auto-completion or user list.
4027 void QsciScintilla::cancelList()
4028 {
4029 SendScintilla(SCI_AUTOCCANCEL);
4030 }
4031
4032
4033 // Handle a selection from the auto-completion list.
4034 void QsciScintilla::handleAutoCompletionSelection()
4035 {
4036 if (!lex.isNull())
4037 {
4038 QsciAbstractAPIs *apis = lex->apis();
4039
4040 if (apis)
4041 apis->autoCompletionSelected(acSelection);
4042 }
4043 }
4044
4045
4046 // Display a user list.
4047 void QsciScintilla::showUserList(int id, const QStringList &list)
4048 {
4049 // Sanity check to make sure auto-completion doesn't get confused.
4050 if (id <= 0)
4051 return;
4052
4053 SendScintilla(SCI_AUTOCSETSEPARATOR, userSeparator);
4054
4055 ScintillaBytes s = textAsBytes(list.join(QChar(userSeparator)));
4056 SendScintilla(SCI_USERLISTSHOW, id, ScintillaBytesConstData(s));
4057 }
4058
4059
4060 // Translate the SCN_USERLISTSELECTION notification into something more useful.
4061 void QsciScintilla::handleUserListSelection(const char *text, int id)
4062 {
4063 emit userListActivated(id, QString(text));
4064
4065 // Make sure the editor hasn't been deactivated as a side effect.
4066 activateWindow();
4067 }
4068
4069
4070 // Return the case sensitivity of any lexer.
4071 bool QsciScintilla::caseSensitive() const
4072 {
4073 return lex.isNull() ? true : lex->caseSensitive();
4074 }
4075
4076
4077 // Return true if the current list is an auto-completion list rather than a
4078 // user list.
4079 bool QsciScintilla::isAutoCompletionList() const
4080 {
4081 return (SendScintilla(SCI_AUTOCGETSEPARATOR) == acSeparator);
4082 }
4083
4084
4085 // Read the text from a QIODevice.
4086 bool QsciScintilla::read(QIODevice *io)
4087 {
4088 const int min_size = 1024 * 8;
4089
4090 int buf_size = min_size;
4091 char *buf = new char[buf_size];
4092
4093 int data_len = 0;
4094 bool ok = true;
4095
4096 qint64 part;
4097
4098 // Read the whole lot in so we don't have to worry about character
4099 // boundaries.
4100 do
4101 {
4102 // Make sure there is a minimum amount of room.
4103 if (buf_size - data_len < min_size)
4104 {
4105 buf_size *= 2;
4106 char *new_buf = new char[buf_size * 2];
4107
4108 memcpy(new_buf, buf, data_len);
4109 delete[] buf;
4110 buf = new_buf;
4111 }
4112
4113 part = io->read(buf + data_len, buf_size - data_len - 1);
4114 data_len += part;
4115 }
4116 while (part > 0);
4117
4118 if (part < 0)
4119 ok = false;
4120 else
4121 {
4122 buf[data_len] = '\0';
4123
4124 bool ro = ensureRW();
4125
4126 SendScintilla(SCI_SETTEXT, buf);
4127 SendScintilla(SCI_EMPTYUNDOBUFFER);
4128
4129 setReadOnly(ro);
4130 }
4131
4132 delete[] buf;
4133
4134 return ok;
4135 }
4136
4137
4138 // Write the text to a QIODevice.
4139 bool QsciScintilla::write(QIODevice *io) const
4140 {
4141 const char *buf = reinterpret_cast<const char *>(SendScintillaPtrResult(SCI_GETCHARACTERPOINTER));
4142
4143 const char *bp = buf;
4144 uint buflen = qstrlen(buf);
4145
4146 while (buflen > 0)
4147 {
4148 qint64 part = io->write(bp, buflen);
4149
4150 if (part < 0)
4151 return false;
4152
4153 bp += part;
4154 buflen -= part;
4155 }
4156
4157 return true;
4158 }
4159
4160
4161 // Return the word at the given coordinates.
4162 QString QsciScintilla::wordAtLineIndex(int line, int index) const
4163 {
4164 return wordAtPosition(positionFromLineIndex(line, index));
4165 }
4166
4167
4168 // Return the word at the given coordinates.
4169 QString QsciScintilla::wordAtPoint(const QPoint &point) const
4170 {
4171 long close_pos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, point.x(),
4172 point.y());
4173
4174 return wordAtPosition(close_pos);
4175 }
4176
4177
4178 // Return the word at the given position.
4179 QString QsciScintilla::wordAtPosition(int position) const
4180 {
4181 if (position < 0)
4182 return QString();
4183
4184 long start_pos = SendScintilla(SCI_WORDSTARTPOSITION, position, true);
4185 long end_pos = SendScintilla(SCI_WORDENDPOSITION, position, true);
4186
4187 if (start_pos >= end_pos)
4188 return QString();
4189
4190 return text(start_pos, end_pos);
4191 }
4192
4193
4194 // Return the display style for annotations.
4195 QsciScintilla::AnnotationDisplay QsciScintilla::annotationDisplay() const
4196 {
4197 return (AnnotationDisplay)SendScintilla(SCI_ANNOTATIONGETVISIBLE);
4198 }
4199
4200
4201 // Set the display style for annotations.
4202 void QsciScintilla::setAnnotationDisplay(QsciScintilla::AnnotationDisplay display)
4203 {
4204 SendScintilla(SCI_ANNOTATIONSETVISIBLE, display);
4205 setScrollBars();
4206 }
4207
4208
4209 // Clear annotations.
4210 void QsciScintilla::clearAnnotations(int line)
4211 {
4212 if (line >= 0)
4213 SendScintilla(SCI_ANNOTATIONSETTEXT, line, (const char *)0);
4214 else
4215 SendScintilla(SCI_ANNOTATIONCLEARALL);
4216
4217 setScrollBars();
4218 }
4219
4220
4221 // Annotate a line.
4222 void QsciScintilla::annotate(int line, const QString &text, int style)
4223 {
4224 int style_offset = SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET);
4225
4226 ScintillaBytes s = textAsBytes(text);
4227
4228 SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaBytesConstData(s));
4229 SendScintilla(SCI_ANNOTATIONSETSTYLE, line, style - style_offset);
4230
4231 setScrollBars();
4232 }
4233
4234
4235 // Annotate a line.
4236 void QsciScintilla::annotate(int line, const QString &text, const QsciStyle &style)
4237 {
4238 style.apply(this);
4239
4240 annotate(line, text, style.style());
4241 }
4242
4243
4244 // Annotate a line.
4245 void QsciScintilla::annotate(int line, const QsciStyledText &text)
4246 {
4247 text.apply(this);
4248
4249 annotate(line, text.text(), text.style());
4250 }
4251
4252
4253 // Annotate a line.
4254 void QsciScintilla::annotate(int line, const QList<QsciStyledText> &text)
4255 {
4256 char *styles;
4257 ScintillaBytes styled_text = styleText(text, &styles,
4258 SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET));
4259
4260 SendScintilla(SCI_ANNOTATIONSETTEXT, line,
4261 ScintillaBytesConstData(styled_text));
4262 SendScintilla(SCI_ANNOTATIONSETSTYLES, line, styles);
4263
4264 delete[] styles;
4265 }
4266
4267
4268 // Get the annotation for a line, if any.
4269 QString QsciScintilla::annotation(int line) const
4270 {
4271 char *buf = new char[SendScintilla(SCI_ANNOTATIONGETTEXT, line, (const char *)0) + 1];
4272
4273 buf[SendScintilla(SCI_ANNOTATIONGETTEXT, line, buf)] = '\0';
4274
4275 QString qs = bytesAsText(buf);
4276 delete[] buf;
4277
4278 return qs;
4279 }
4280
4281
4282 // Convert a list of styled text to the low-level arrays.
4283 QsciScintillaBase::ScintillaBytes QsciScintilla::styleText(const QList<QsciStyledText> &styled_text, char **styles, int style_offset)
4284 {
4285 QString text;
4286 int i;
4287
4288 // Build the full text.
4289 for (i = 0; i < styled_text.count(); ++i)
4290 {
4291 const QsciStyledText &st = styled_text[i];
4292
4293 st.apply(this);
4294
4295 text.append(st.text());
4296 }
4297
4298 ScintillaBytes s = textAsBytes(text);
4299
4300 // There is a style byte for every byte.
4301 char *sp = *styles = new char[s.length()];
4302
4303 for (i = 0; i < styled_text.count(); ++i)
4304 {
4305 const QsciStyledText &st = styled_text[i];
4306 ScintillaBytes part = textAsBytes(st.text());
4307 int part_length = part.length();
4308
4309 for (int c = 0; c < part_length; ++c)
4310 *sp++ = (char)(st.style() - style_offset);
4311 }
4312
4313 return s;
4314 }
4315
4316
4317 // Convert Scintilla modifiers to the Qt equivalent.
4318 int QsciScintilla::mapModifiers(int modifiers)
4319 {
4320 int state = 0;
4321
4322 if (modifiers & SCMOD_SHIFT)
4323 state |= Qt::ShiftModifier;
4324
4325 if (modifiers & SCMOD_CTRL)
4326 state |= Qt::ControlModifier;
4327
4328 if (modifiers & SCMOD_ALT)
4329 state |= Qt::AltModifier;
4330
4331 if (modifiers & (SCMOD_SUPER | SCMOD_META))
4332 state |= Qt::MetaModifier;
4333
4334 return state;
4335 }
4336
4337
4338 // Re-implemented to handle shortcut overrides.
4339 bool QsciScintilla::event(QEvent *e)
4340 {
4341 if (e->type() == QEvent::ShortcutOverride && !isReadOnly())
4342 {
4343 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
4344
4345 if (ke->key())
4346 {
4347 // We want ordinary characters.
4348 if ((ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier || ke->modifiers() == Qt::KeypadModifier) && ke->key() < Qt::Key_Escape)
4349 {
4350 ke->accept();
4351 return true;
4352 }
4353
4354 // We want any key that is bound.
4355 QsciCommand *cmd = stdCmds->boundTo(ke->key() | (ke->modifiers() & ~Qt::KeypadModifier));
4356
4357 if (cmd)
4358 {
4359 ke->accept();
4360 return true;
4361 }
4362 }
4363 }
4364
4365 return QsciScintillaBase::event(e);
4366 }
4367
4368
4369 // Re-implemented to zoom when the Control modifier is pressed.
4370 void QsciScintilla::wheelEvent(QWheelEvent *e)
4371 {
4372 #if defined(Q_OS_MAC)
4373 const Qt::KeyboardModifier zoom_modifier = Qt::MetaModifier;
4374 #else
4375 const Qt::KeyboardModifier zoom_modifier = Qt::ControlModifier;
4376 #endif
4377
4378 if ((e->modifiers() & zoom_modifier) != 0)
4379 {
4380 if (e->delta() > 0)
4381 zoomIn();
4382 else
4383 zoomOut();
4384 }
4385 else
4386 {
4387 QsciScintillaBase::wheelEvent(e);
4388 }
4389 }
4390
4391
4392 // Re-implemented to handle chenges to the enabled state.
4393 void QsciScintilla::changeEvent(QEvent *e)
4394 {
4395 QsciScintillaBase::changeEvent(e);
4396
4397 if (e->type() != QEvent::EnabledChange)
4398 return;
4399
4400 if (isEnabled())
4401 SendScintilla(SCI_SETCARETSTYLE, CARETSTYLE_LINE);
4402 else
4403 SendScintilla(SCI_SETCARETSTYLE, CARETSTYLE_INVISIBLE);
4404
4405 QColor fore = palette().color(QPalette::Disabled, QPalette::Text);
4406 QColor back = palette().color(QPalette::Disabled, QPalette::Base);
4407
4408 if (lex.isNull())
4409 {
4410 if (isEnabled())
4411 {
4412 fore = nl_text_colour;
4413 back = nl_paper_colour;
4414 }
4415
4416 SendScintilla(SCI_STYLESETFORE, 0, fore);
4417
4418 // Assume style 0 applies to everything so that we don't need to use
4419 // SCI_STYLECLEARALL which clears everything. We still have to set the
4420 // default style as well for the background without any text.
4421 SendScintilla(SCI_STYLESETBACK, 0, back);
4422 SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, back);
4423 }
4424 else
4425 {
4426 setEnabledColors(STYLE_DEFAULT, fore, back);
4427
4428 for (int s = 0; s <= STYLE_MAX; ++s)
4429 if (!lex->description(s).isNull())
4430 setEnabledColors(s, fore, back);
4431 }
4432 }
4433
4434
4435 // Set the foreground and background colours for a style.
4436 void QsciScintilla::setEnabledColors(int style, QColor &fore, QColor &back)
4437 {
4438 if (isEnabled())
4439 {
4440 fore = lex->color(style);
4441 back = lex->paper(style);
4442 }
4443
4444 handleStyleColorChange(fore, style);
4445 handleStylePaperChange(back, style);
4446 }
4447
4448
4449 // Re-implemented to implement a more Qt-like context menu.
4450 void QsciScintilla::contextMenuEvent(QContextMenuEvent *e)
4451 {
4452 if (contextMenuNeeded(e->x(), e->y()))
4453 {
4454 QMenu *menu = createStandardContextMenu();
4455
4456 if (menu)
4457 {
4458 menu->setAttribute(Qt::WA_DeleteOnClose);
4459 menu->popup(e->globalPos());
4460 }
4461 }
4462 }
4463
4464
4465 // Create an instance of the standard context menu.
4466 QMenu *QsciScintilla::createStandardContextMenu()
4467 {
4468 bool read_only = isReadOnly();
4469 bool has_selection = hasSelectedText();
4470 QMenu *menu = new QMenu(this);
4471 QAction *action;
4472
4473 if (!read_only)
4474 {
4475 action = menu->addAction(tr("&Undo"), this, SLOT(undo()));
4476 set_shortcut(action, QsciCommand::Undo);
4477 action->setEnabled(isUndoAvailable());
4478
4479 action = menu->addAction(tr("&Redo"), this, SLOT(redo()));
4480 set_shortcut(action, QsciCommand::Redo);
4481 action->setEnabled(isRedoAvailable());
4482
4483 menu->addSeparator();
4484
4485 action = menu->addAction(tr("Cu&t"), this, SLOT(cut()));
4486 set_shortcut(action, QsciCommand::SelectionCut);
4487 action->setEnabled(has_selection);
4488 }
4489
4490 action = menu->addAction(tr("&Copy"), this, SLOT(copy()));
4491 set_shortcut(action, QsciCommand::SelectionCopy);
4492 action->setEnabled(has_selection);
4493
4494 if (!read_only)
4495 {
4496 action = menu->addAction(tr("&Paste"), this, SLOT(paste()));
4497 set_shortcut(action, QsciCommand::Paste);
4498 action->setEnabled(SendScintilla(SCI_CANPASTE));
4499
4500 action = menu->addAction(tr("Delete"), this, SLOT(delete_selection()));
4501 action->setEnabled(has_selection);
4502 }
4503
4504 if (!menu->isEmpty())
4505 menu->addSeparator();
4506
4507 action = menu->addAction(tr("Select All"), this, SLOT(selectAll()));
4508 set_shortcut(action, QsciCommand::SelectAll);
4509 action->setEnabled(length() != 0);
4510
4511 return menu;
4512 }
4513
4514
4515 // Set the shortcut for an action using any current key binding.
4516 void QsciScintilla::set_shortcut(QAction *action, QsciCommand::Command cmd_id) const
4517 {
4518 QsciCommand *cmd = stdCmds->find(cmd_id);
4519
4520 if (cmd && cmd->key())
4521 action->setShortcut(QKeySequence(cmd->key()));
4522 }
4523
4524
4525 // Delete the current selection.
4526 void QsciScintilla::delete_selection()
4527 {
4528 SendScintilla(SCI_CLEAR);
4529 }
4530
4531
4532 // Convert a Scintilla colour to a QColor.
4533 static QColor asQColor(long sci_colour)
4534 {
4535 return QColor(
4536 ((int)sci_colour) & 0x00ff,
4537 ((int)(sci_colour >> 8)) & 0x00ff,
4538 ((int)(sci_colour >> 16)) & 0x00ff);
4539 }
4540
4541
4542 // Set the scroll width.
4543 void QsciScintilla::setScrollWidth(int pixelWidth)
4544 {
4545 SendScintilla(SCI_SETSCROLLWIDTH, pixelWidth);
4546 }
4547
4548 // Get the scroll width.
4549 int QsciScintilla::scrollWidth() const
4550 {
4551 return SendScintilla(SCI_GETSCROLLWIDTH);
4552 }
4553
4554
4555 // Set scroll width tracking.
4556 void QsciScintilla::setScrollWidthTracking(bool enabled)
4557 {
4558 SendScintilla(SCI_SETSCROLLWIDTHTRACKING, enabled);
4559 }
4560
4561
4562 // Get scroll width tracking.
4563 bool QsciScintilla::scrollWidthTracking() const
4564 {
4565 return SendScintilla(SCI_GETSCROLLWIDTHTRACKING);
4566 }