diff --git a/harbour/ChangeLog b/harbour/ChangeLog index d8f3a7cfed..dff2cc7f48 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,35 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-05-20 06:56 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) + + contrib/hbide/qscintilla + + contrib/hbide/qscintilla/qt + + Initial port of QScintilla ( http://www.riverbankcomputing.co.uk/software/qscintilla/intro ) + + This port is greatly trimmed one excluding all lexer code + except CPP and FLAGSHIP which are relevant to Xbase code + at present. Also directory structure is normalized and sources + are modified to respect them. SVN properties are eol:native, + I am not sure what other properties should go inside. + QScintilla actually is divided into two libs but for sake + of convinience I have kept them as one. + + It is a base commit. In the next days a Harbour wrapped + is scheduled to be built onto it and then actual application + experiments will follow. On success, current edit component + of hbIDE will be transferred. + + I am poor in looking at licensing, so please feel free to + delete this commit if it does not confirm to original intent. + + I have also touched the sources to suppress a lot of warnings + and library seems to be working fine after these changes. Still + some warnings are there which I could not supress, please look. + + To build the lib qscintilla.hbp is there, just issue + hbmk2 qscintilla.hbp while residing in hbide/qscintilla. + 2010-05-20 13:40 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * utils/hbmk2/hbmk2.prg ! Fixed to ignore .cpp files in main entry detection function. diff --git a/harbour/contrib/hbide/qscintilla/Accessor.h b/harbour/contrib/hbide/qscintilla/Accessor.h new file mode 100644 index 0000000000..d9db9c7bfe --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Accessor.h @@ -0,0 +1,79 @@ +// Scintilla source code edit control +/** @file Accessor.h + ** Rapid easy access to contents of a Scintilla. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +enum { wsSpace = 1, wsTab = 2, wsSpaceTab = 4, wsInconsistent=8}; + +class Accessor; + +typedef bool (*PFNIsCommentLeader)(Accessor &styler, int pos, int len); + +/** + * Interface to data in a Scintilla. + */ +class Accessor { +protected: + enum {extremePosition=0x7FFFFFFF}; + /** @a bufferSize is a trade off between time taken to copy the characters + * and retrieval overhead. + * @a slopSize positions the buffer before the desired position + * in case there is some backtracking. */ + enum {bufferSize=4000, slopSize=bufferSize/8}; + char buf[bufferSize+1]; + int startPos; + int endPos; + int codePage; + + virtual bool InternalIsLeadByte(char ch)=0; + virtual void Fill(int position)=0; + +public: + Accessor() : startPos(extremePosition), endPos(0), codePage(0) {} + virtual ~Accessor() {} + char operator[](int position) { + if (position < startPos || position >= endPos) { + Fill(position); + } + return buf[position - startPos]; + } + /** Safe version of operator[], returning a defined value for invalid position. */ + char SafeGetCharAt(int position, char chDefault=' ') { + if (position < startPos || position >= endPos) { + Fill(position); + if (position < startPos || position >= endPos) { + // Position is outside range of document + return chDefault; + } + } + return buf[position - startPos]; + } + bool IsLeadByte(char ch) { + return codePage && InternalIsLeadByte(ch); + } + void SetCodePage(int codePage_) { codePage = codePage_; } + + virtual bool Match(int pos, const char *s)=0; + virtual char StyleAt(int position)=0; + virtual int GetLine(int position)=0; + virtual int LineStart(int line)=0; + virtual int LevelAt(int line)=0; + virtual int Length()=0; + virtual void Flush()=0; + virtual int GetLineState(int line)=0; + virtual int SetLineState(int line, int state)=0; + virtual int GetPropertyInt(const char *key, int defaultValue=0)=0; + virtual char *GetProperties()=0; + + // Style setting + virtual void StartAt(unsigned int start, char chMask=31)=0; + virtual void SetFlags(char chFlags_, char chWhile_)=0; + virtual unsigned int GetStartSegment()=0; + virtual void StartSegment(unsigned int pos)=0; + virtual void ColourTo(unsigned int pos, int chAttr)=0; + virtual void SetLevel(int line, int level)=0; + virtual int IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0)=0; + virtual void IndicatorFill(int start, int end, int indicator, int value)=0; +}; diff --git a/harbour/contrib/hbide/qscintilla/AutoComplete.cpp b/harbour/contrib/hbide/qscintilla/AutoComplete.cpp new file mode 100644 index 0000000000..af6154ea13 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/AutoComplete.cpp @@ -0,0 +1,178 @@ +// Scintilla source code edit control +/** @file AutoComplete.cxx + ** Defines the auto completion list box. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "AutoComplete.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +AutoComplete::AutoComplete() : + active(false), + separator(' '), + typesep('?'), + ignoreCase(false), + chooseSingle(false), + lb(0), + posStart(0), + startLen(0), + cancelAtStartPos(true), + autoHide(true), + dropRestOfWord(false) { + lb = ListBox::Allocate(); + stopChars[0] = '\0'; + fillUpChars[0] = '\0'; +} + +AutoComplete::~AutoComplete() { + if (lb) { + lb->Destroy(); + delete lb; + lb = 0; + } +} + +bool AutoComplete::Active() { + return active; +} + +void AutoComplete::Start(Window &parent, int ctrlID, + int position, Point location, int startLen_, + int lineHeight, bool unicodeMode) { + if (active) { + Cancel(); + } + lb->Create(parent, ctrlID, location, lineHeight, unicodeMode); + lb->Clear(); + active = true; + startLen = startLen_; + posStart = position; +} + +void AutoComplete::SetStopChars(const char *stopChars_) { + strncpy(stopChars, stopChars_, sizeof(stopChars)); + stopChars[sizeof(stopChars) - 1] = '\0'; +} + +bool AutoComplete::IsStopChar(char ch) { + return ch && strchr(stopChars, ch); +} + +void AutoComplete::SetFillUpChars(const char *fillUpChars_) { + strncpy(fillUpChars, fillUpChars_, sizeof(fillUpChars)); + fillUpChars[sizeof(fillUpChars) - 1] = '\0'; +} + +bool AutoComplete::IsFillUpChar(char ch) { + return ch && strchr(fillUpChars, ch); +} + +void AutoComplete::SetSeparator(char separator_) { + separator = separator_; +} + +char AutoComplete::GetSeparator() { + return separator; +} + +void AutoComplete::SetTypesep(char separator_) { + typesep = separator_; +} + +char AutoComplete::GetTypesep() { + return typesep; +} + +void AutoComplete::SetList(const char *list) { + lb->SetList(list, separator, typesep); +} + +void AutoComplete::Show(bool show) { + lb->Show(show); + if (show) + lb->Select(0); +} + +void AutoComplete::Cancel() { + if (lb->Created()) { + lb->Clear(); + lb->Destroy(); + active = false; + } +} + + +void AutoComplete::Move(int delta) { + int count = lb->Length(); + int current = lb->GetSelection(); + current += delta; + if (current >= count) + current = count - 1; + if (current < 0) + current = 0; + lb->Select(current); +} + +void AutoComplete::Select(const char *word) { + size_t lenWord = strlen(word); + int location = -1; + const int maxItemLen=1000; + char item[maxItemLen]; + int start = 0; // lower bound of the api array block to search + int end = lb->Length() - 1; // upper bound of the api array block to search + while ((start <= end) && (location == -1)) { // Binary searching loop + int pivot = (start + end) / 2; + lb->GetValue(pivot, item, maxItemLen); + int cond; + if (ignoreCase) + cond = CompareNCaseInsensitive(word, item, lenWord); + else + cond = strncmp(word, item, lenWord); + if (!cond) { + // Find first match + while (pivot > start) { + lb->GetValue(pivot-1, item, maxItemLen); + if (ignoreCase) + cond = CompareNCaseInsensitive(word, item, lenWord); + else + cond = strncmp(word, item, lenWord); + if (0 != cond) + break; + --pivot; + } + location = pivot; + if (ignoreCase) { + // Check for exact-case match + for (; pivot <= end; pivot++) { + lb->GetValue(pivot, item, maxItemLen); + if (!strncmp(word, item, lenWord)) { + location = pivot; + break; + } + if (CompareNCaseInsensitive(word, item, lenWord)) + break; + } + } + } else if (cond < 0) { + end = pivot - 1; + } else if (cond > 0) { + start = pivot + 1; + } + } + if (location == -1 && autoHide) + Cancel(); + else + lb->Select(location); +} + diff --git a/harbour/contrib/hbide/qscintilla/AutoComplete.h b/harbour/contrib/hbide/qscintilla/AutoComplete.h new file mode 100644 index 0000000000..b10cdce82f --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/AutoComplete.h @@ -0,0 +1,78 @@ +// Scintilla source code edit control +/** @file AutoComplete.h + ** Defines the auto completion list box. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef AUTOCOMPLETE_H +#define AUTOCOMPLETE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class AutoComplete { + bool active; + char stopChars[256]; + char fillUpChars[256]; + char separator; + char typesep; // Type seperator + +public: + bool ignoreCase; + bool chooseSingle; + ListBox *lb; + int posStart; + int startLen; + /// Should autocompletion be canceled if editor's currentPos <= startPos? + bool cancelAtStartPos; + bool autoHide; + bool dropRestOfWord; + + AutoComplete(); + ~AutoComplete(); + + /// Is the auto completion list displayed? + bool Active(); + + /// Display the auto completion list positioned to be near a character position + void Start(Window &parent, int ctrlID, int position, Point location, + int startLen_, int lineHeight, bool unicodeMode); + + /// The stop chars are characters which, when typed, cause the auto completion list to disappear + void SetStopChars(const char *stopChars_); + bool IsStopChar(char ch); + + /// The fillup chars are characters which, when typed, fill up the selected word + void SetFillUpChars(const char *fillUpChars_); + bool IsFillUpChar(char ch); + + /// The separator character is used when interpreting the list in SetList + void SetSeparator(char separator_); + char GetSeparator(); + + /// The typesep character is used for seperating the word from the type + void SetTypesep(char separator_); + char GetTypesep(); + + /// The list string contains a sequence of words separated by the separator character + void SetList(const char *list); + + void Show(bool show); + void Cancel(); + + /// Move the current list element by delta, scrolling appropriately + void Move(int delta); + + /// Select a list element that starts with word as the current element + void Select(const char *word); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/CallTip.cpp b/harbour/contrib/hbide/qscintilla/CallTip.cpp new file mode 100644 index 0000000000..4fdc2226ee --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CallTip.cpp @@ -0,0 +1,329 @@ +// Scintilla source code edit control +/** @file CallTip.cxx + ** Code for displaying call tips. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "CallTip.h" +#include + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static const int insetX = 5; // text inset in x from calltip border +static const int widthArrow = 14; + +CallTip::CallTip() { + wCallTip = 0; + inCallTipMode = false; + posStartCallTip = 0; + val = 0; + rectUp = PRectangle(0,0,0,0); + rectDown = PRectangle(0,0,0,0); + lineHeight = 1; + startHighlight = 0; + endHighlight = 0; + tabSize = 0; + useStyleCallTip = false; // for backwards compatibility + +#ifdef __APPLE__ + // proper apple colours for the default + colourBG.desired = ColourDesired(0xff, 0xff, 0xc6); + colourUnSel.desired = ColourDesired(0, 0, 0); +#else + colourBG.desired = ColourDesired(0xff, 0xff, 0xff); + colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80); +#endif + colourSel.desired = ColourDesired(0, 0, 0x80); + colourShade.desired = ColourDesired(0, 0, 0); + colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0); +} + +CallTip::~CallTip() { + font.Release(); + wCallTip.Destroy(); + delete []val; + val = 0; +} + +void CallTip::RefreshColourPalette(Palette &pal, bool want) { + pal.WantFind(colourBG, want); + pal.WantFind(colourUnSel, want); + pal.WantFind(colourSel, want); + pal.WantFind(colourShade, want); + pal.WantFind(colourLight, want); +} + +// Although this test includes 0, we should never see a \0 character. +static bool IsArrowCharacter(char ch) { + return (ch == 0) || (ch == '\001') || (ch == '\002'); +} + +// We ignore tabs unless a tab width has been set. +bool CallTip::IsTabCharacter(char ch) { + return (tabSize > 0) && (ch == '\t'); +} + +int CallTip::NextTabPos(int x) { + if (tabSize > 0) { // paranoia... not called unless this is true + x -= insetX; // position relative to text + x = (x + tabSize) / tabSize; // tab "number" + return tabSize*x + insetX; // position of next tab + } else { + return x + 1; // arbitrary + } +} + +// Draw a section of the call tip that does not include \n in one colour. +// The text may include up to numEnds tabs or arrow characters. +void CallTip::DrawChunk(Surface *surface, int &x, const char *s, + int posStart, int posEnd, int ytext, PRectangle rcClient, + bool highlight, bool draw) { + s += posStart; + int len = posEnd - posStart; + + // Divide the text into sections that are all text, or that are + // single arrows or single tab characters (if tabSize > 0). + int maxEnd = 0; + const int numEnds = 10; + int ends[numEnds + 2]; + for (int i=0;i 0) + ends[maxEnd++] = i; + ends[maxEnd++] = i+1; + } + } + ends[maxEnd++] = len; + int startSeg = 0; + int xEnd; + for (int seg = 0; seg startSeg) { + if (IsArrowCharacter(s[startSeg])) { + bool upArrow = s[startSeg] == '\001'; + rcClient.left = x; + rcClient.right = rcClient.left + widthArrow; + if (draw) { + const int halfWidth = widthArrow / 2 - 3; + const int centreX = rcClient.left + widthArrow / 2 - 1; + const int centreY = (rcClient.top + rcClient.bottom) / 2; + surface->FillRectangle(rcClient, colourBG.allocated); + PRectangle rcClientInner(rcClient.left + 1, rcClient.top + 1, + rcClient.right - 2, rcClient.bottom - 1); + surface->FillRectangle(rcClientInner, colourUnSel.allocated); + + if (upArrow) { // Up arrow + Point pts[] = { + Point(centreX - halfWidth, centreY + halfWidth / 2), + Point(centreX + halfWidth, centreY + halfWidth / 2), + Point(centreX, centreY - halfWidth + halfWidth / 2), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + colourBG.allocated, colourBG.allocated); + } else { // Down arrow + Point pts[] = { + Point(centreX - halfWidth, centreY - halfWidth / 2), + Point(centreX + halfWidth, centreY - halfWidth / 2), + Point(centreX, centreY + halfWidth - halfWidth / 2), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + colourBG.allocated, colourBG.allocated); + } + } + xEnd = rcClient.right; + offsetMain = xEnd; + if (upArrow) { + rectUp = rcClient; + } else { + rectDown = rcClient; + } + } else if (IsTabCharacter(s[startSeg])) { + xEnd = NextTabPos(x); + } else { + xEnd = x + surface->WidthText(font, s + startSeg, endSeg - startSeg); + if (draw) { + rcClient.left = x; + rcClient.right = xEnd; + surface->DrawTextTransparent(rcClient, font, ytext, + s+startSeg, endSeg - startSeg, + highlight ? colourSel.allocated : colourUnSel.allocated); + } + } + x = xEnd; + startSeg = endSeg; + } + } +} + +int CallTip::PaintContents(Surface *surfaceWindow, bool draw) { + PRectangle rcClientPos = wCallTip.GetClientPosition(); + PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left, + rcClientPos.bottom - rcClientPos.top); + PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1); + + // To make a nice small call tip window, it is only sized to fit most normal characters without accents + int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font); + + // For each line... + // Draw the definition in three parts: before highlight, highlighted, after highlight + int ytext = rcClient.top + ascent + 1; + rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1; + char *chunkVal = val; + bool moreChunks = true; + int maxWidth = 0; + + while (moreChunks) { + char *chunkEnd = strchr(chunkVal, '\n'); + if (chunkEnd == NULL) { + chunkEnd = chunkVal + strlen(chunkVal); + moreChunks = false; + } + int chunkOffset = chunkVal - val; + int chunkLength = chunkEnd - chunkVal; + int chunkEndOffset = chunkOffset + chunkLength; + int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset); + thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset); + thisStartHighlight -= chunkOffset; + int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset); + thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset); + thisEndHighlight -= chunkOffset; + rcClient.top = ytext - ascent - 1; + + int x = insetX; // start each line at this inset + + DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight, + ytext, rcClient, false, draw); + DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight, + ytext, rcClient, true, draw); + DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength, + ytext, rcClient, false, draw); + + chunkVal = chunkEnd + 1; + ytext += lineHeight; + rcClient.bottom += lineHeight; + maxWidth = Platform::Maximum(maxWidth, x); + } + return maxWidth; +} + +void CallTip::PaintCT(Surface *surfaceWindow) { + if (!val) + return; + PRectangle rcClientPos = wCallTip.GetClientPosition(); + PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left, + rcClientPos.bottom - rcClientPos.top); + PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1); + + surfaceWindow->FillRectangle(rcClient, colourBG.allocated); + + offsetMain = insetX; // initial alignment assuming no arrows + PaintContents(surfaceWindow, true); + +#ifndef __APPLE__ + // OSX doesn't put borders on "help tags" + // Draw a raised border around the edges of the window + surfaceWindow->MoveTo(0, rcClientSize.bottom - 1); + surfaceWindow->PenColour(colourShade.allocated); + surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1); + surfaceWindow->LineTo(rcClientSize.right - 1, 0); + surfaceWindow->PenColour(colourLight.allocated); + surfaceWindow->LineTo(0, 0); + surfaceWindow->LineTo(0, rcClientSize.bottom - 1); +#endif +} + +void CallTip::MouseClick(Point pt) { + clickPlace = 0; + if (rectUp.Contains(pt)) + clickPlace = 1; + if (rectDown.Contains(pt)) + clickPlace = 2; +} + +PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn, + const char *faceName, int size, + int codePage_, int characterSet, Window &wParent) { + clickPlace = 0; + if (val) + delete []val; + val = new char[strlen(defn) + 1]; + if (!val) + return PRectangle(); + strcpy(val, defn); + codePage = codePage_; + Surface *surfaceMeasure = Surface::Allocate(); + if (!surfaceMeasure) + return PRectangle(); + surfaceMeasure->Init(wParent.GetID()); + surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage); + surfaceMeasure->SetDBCSMode(codePage); + startHighlight = 0; + endHighlight = 0; + inCallTipMode = true; + posStartCallTip = pos; + int deviceHeight = surfaceMeasure->DeviceHeightFont(size); + font.Create(faceName, characterSet, deviceHeight, false, false); + // Look for multiple lines in the text + // Only support \n here - simply means container must avoid \r! + int numLines = 1; + const char *newline; + const char *look = val; + rectUp = PRectangle(0,0,0,0); + rectDown = PRectangle(0,0,0,0); + offsetMain = insetX; // changed to right edge of any arrows + int width = PaintContents(surfaceMeasure, false) + insetX; + while ((newline = strchr(look, '\n')) != NULL) { + look = newline + 1; + numLines++; + } + lineHeight = surfaceMeasure->Height(font); + + // Extra line for border and an empty line at top and bottom. The returned + // rectangle is aligned to the right edge of the last arrow encountered in + // the tip text, else to the tip text left edge. + int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2; + delete surfaceMeasure; + return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height); +} + +void CallTip::CallTipCancel() { + inCallTipMode = false; + if (wCallTip.Created()) { + wCallTip.Destroy(); + } +} + +void CallTip::SetHighlight(int start, int end) { + // Avoid flashing by checking something has really changed + if ((start != startHighlight) || (end != endHighlight)) { + startHighlight = start; + endHighlight = end; + if (wCallTip.Created()) { + wCallTip.InvalidateAll(); + } + } +} + +// Set the tab size (sizes > 0 enable the use of tabs). This also enables the +// use of the STYLE_CALLTIP. +void CallTip::SetTabSize(int tabSz) { + tabSize = tabSz; + useStyleCallTip = true; +} + +// It might be better to have two access functions for this and to use +// them for all settings of colours. +void CallTip::SetForeBack(const ColourPair &fore, const ColourPair &back) { + colourBG = back; + colourUnSel = fore; +} diff --git a/harbour/contrib/hbide/qscintilla/CallTip.h b/harbour/contrib/hbide/qscintilla/CallTip.h new file mode 100644 index 0000000000..bdf1123c74 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CallTip.h @@ -0,0 +1,87 @@ +// Scintilla source code edit control +/** @file CallTip.h + ** Interface to the call tip control. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CALLTIP_H +#define CALLTIP_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class CallTip { + int startHighlight; // character offset to start and... + int endHighlight; // ...end of highlighted text + char *val; + Font font; + PRectangle rectUp; // rectangle of last up angle in the tip + PRectangle rectDown; // rectangle of last down arrow in the tip + int lineHeight; // vertical line spacing + int offsetMain; // The alignment point of the call tip + int tabSize; // Tab size in pixels, <=0 no TAB expand + bool useStyleCallTip; // if true, STYLE_CALLTIP should be used + + // Private so CallTip objects can not be copied + CallTip(const CallTip &) {} + CallTip &operator=(const CallTip &) { return *this; } + void DrawChunk(Surface *surface, int &x, const char *s, + int posStart, int posEnd, int ytext, PRectangle rcClient, + bool highlight, bool draw); + int PaintContents(Surface *surfaceWindow, bool draw); + bool IsTabCharacter(char c); + int NextTabPos(int x); + +public: + Window wCallTip; + Window wDraw; + bool inCallTipMode; + int posStartCallTip; + ColourPair colourBG; + ColourPair colourUnSel; + ColourPair colourSel; + ColourPair colourShade; + ColourPair colourLight; + int codePage; + int clickPlace; + + CallTip(); + ~CallTip(); + + /// Claim or accept palette entries for the colours required to paint a calltip. + void RefreshColourPalette(Palette &pal, bool want); + + void PaintCT(Surface *surfaceWindow); + + void MouseClick(Point pt); + + /// Setup the calltip and return a rectangle of the area required. + PRectangle CallTipStart(int pos, Point pt, const char *defn, + const char *faceName, int size, int codePage_, + int characterSet, Window &wParent); + + void CallTipCancel(); + + /// Set a range of characters to be displayed in a highlight style. + /// Commonly used to highlight the current parameter. + void SetHighlight(int start, int end); + + /// Set the tab size in pixels for the call tip. 0 or -ve means no tab expand. + void SetTabSize(int tabSz); + + /// Used to determine which STYLE_xxxx to use for call tip information + bool UseStyleCallTip() const { return useStyleCallTip;} + + // Modify foreground and background colours + void SetForeBack(const ColourPair &fore, const ColourPair &back); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/CellBuffer.cpp b/harbour/contrib/hbide/qscintilla/CellBuffer.cpp new file mode 100644 index 0000000000..6ce0605897 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CellBuffer.cpp @@ -0,0 +1,651 @@ +// Scintilla source code edit control +/** @file CellBuffer.cxx + ** Manages a buffer of cells. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "CellBuffer.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +LineVector::LineVector() : starts(256) { + Init(); +} + +LineVector::~LineVector() { + starts.DeleteAll(); +} + +void LineVector::Init() { + starts.DeleteAll(); +} + +void LineVector::SetPerLine(PerLine *pl) { + perLine = pl; +} + +void LineVector::InsertText(int line, int delta) { + starts.InsertText(line, delta); +} + +void LineVector::InsertLine(int line, int position) { + starts.InsertPartition(line, position); + if (perLine) { + perLine->InsertLine(line); + } +} + +void LineVector::SetLineStart(int line, int position) { + starts.SetPartitionStartPosition(line, position); +} + +void LineVector::RemoveLine(int line) { + starts.RemovePartition(line); + if (perLine) { + perLine->RemoveLine(line); + } +} + +int LineVector::LineFromPosition(int pos) { + return starts.PartitionFromPosition(pos); +} + +Action::Action() { + at = startAction; + position = 0; + data = 0; + lenData = 0; +} + +Action::~Action() { + Destroy(); +} + +void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_) { + delete []data; + position = position_; + at = at_; + data = data_; + lenData = lenData_; + mayCoalesce = mayCoalesce_; +} + +void Action::Destroy() { + delete []data; + data = 0; +} + +void Action::Grab(Action *source) { + delete []data; + + position = source->position; + at = source->at; + data = source->data; + lenData = source->lenData; + mayCoalesce = source->mayCoalesce; + + // Ownership of source data transferred to this + source->position = 0; + source->at = startAction; + source->data = 0; + source->lenData = 0; + source->mayCoalesce = true; +} + +// The undo history stores a sequence of user operations that represent the user's view of the +// commands executed on the text. +// Each user operation contains a sequence of text insertion and text deletion actions. +// All the user operations are stored in a list of individual actions with 'start' actions used +// as delimiters between user operations. +// Initially there is one start action in the history. +// As each action is performed, it is recorded in the history. The action may either become +// part of the current user operation or may start a new user operation. If it is to be part of the +// current operation, then it overwrites the current last action. If it is to be part of a new +// operation, it is appended after the current last action. +// After writing the new action, a new start action is appended at the end of the history. +// The decision of whether to start a new user operation is based upon two factors. If a +// compound operation has been explicitly started by calling BeginUndoAction and no matching +// EndUndoAction (these calls nest) has been called, then the action is coalesced into the current +// operation. If there is no outstanding BeginUndoAction call then a new operation is started +// unless it looks as if the new action is caused by the user typing or deleting a stream of text. +// Sequences that look like typing or deletion are coalesced into a single user operation. + +UndoHistory::UndoHistory() { + + lenActions = 100; + actions = new Action[lenActions]; + maxAction = 0; + currentAction = 0; + undoSequenceDepth = 0; + savePoint = 0; + + actions[currentAction].Create(startAction); +} + +UndoHistory::~UndoHistory() { + delete []actions; + actions = 0; +} + +void UndoHistory::EnsureUndoRoom() { + // Have to test that there is room for 2 more actions in the array + // as two actions may be created by the calling function + if (currentAction >= (lenActions - 2)) { + // Run out of undo nodes so extend the array + int lenActionsNew = lenActions * 2; + Action *actionsNew = new Action[lenActionsNew]; + if (!actionsNew) + return; + for (int act = 0; act <= currentAction; act++) + actionsNew[act].Grab(&actions[act]); + delete []actions; + lenActions = lenActionsNew; + actions = actionsNew; + } +} + +void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData, + bool &startSequence, bool mayCoalesce) { + EnsureUndoRoom(); + //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction); + //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at, + // actions[currentAction - 1].position, actions[currentAction - 1].lenData); + if (currentAction < savePoint) { + savePoint = -1; + } + int oldCurrentAction = currentAction; + if (currentAction >= 1) { + if (0 == undoSequenceDepth) { + // Top level actions may not always be coalesced + int targetAct = -1; + const Action *actPrevious = &(actions[currentAction + targetAct]); + // Container actions may forward the coalesce state of Scintilla Actions. + while ((actPrevious->at == containerAction) && actPrevious->mayCoalesce) { + targetAct--; + actPrevious = &(actions[currentAction + targetAct]); + } + // See if current action can be coalesced into previous action + // Will work if both are inserts or deletes and position is same + if (currentAction == savePoint) { + currentAction++; + } else if (!actions[currentAction].mayCoalesce) { + // Not allowed to coalesce if this set + currentAction++; + } else if (!mayCoalesce || !actPrevious->mayCoalesce) { + currentAction++; + } else if (at == containerAction || actions[currentAction].at == containerAction) { + ; // A coalescible containerAction + } else if ((at != actPrevious->at) && (actPrevious->at != startAction)) { + currentAction++; + } else if ((at == insertAction) && + (position != (actPrevious->position + actPrevious->lenData))) { + // Insertions must be immediately after to coalesce + currentAction++; + } else if (at == removeAction) { + if ((lengthData == 1) || (lengthData == 2)){ + if ((position + lengthData) == actPrevious->position) { + ; // Backspace -> OK + } else if (position == actPrevious->position) { + ; // Delete -> OK + } else { + // Removals must be at same position to coalesce + currentAction++; + } + } else { + // Removals must be of one character to coalesce + currentAction++; + } + } else { + // Action coalesced. + } + + } else { + // Actions not at top level are always coalesced unless this is after return to top level + if (!actions[currentAction].mayCoalesce) + currentAction++; + } + } else { + currentAction++; + } + startSequence = oldCurrentAction != currentAction; + actions[currentAction].Create(at, position, data, lengthData, mayCoalesce); + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; +} + +void UndoHistory::BeginUndoAction() { + EnsureUndoRoom(); + if (undoSequenceDepth == 0) { + if (actions[currentAction].at != startAction) { + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } + actions[currentAction].mayCoalesce = false; + } + undoSequenceDepth++; +} + +void UndoHistory::EndUndoAction() { + PLATFORM_ASSERT(undoSequenceDepth > 0); + EnsureUndoRoom(); + undoSequenceDepth--; + if (0 == undoSequenceDepth) { + if (actions[currentAction].at != startAction) { + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } + actions[currentAction].mayCoalesce = false; + } +} + +void UndoHistory::DropUndoSequence() { + undoSequenceDepth = 0; +} + +void UndoHistory::DeleteUndoHistory() { + for (int i = 1; i < maxAction; i++) + actions[i].Destroy(); + maxAction = 0; + currentAction = 0; + actions[currentAction].Create(startAction); + savePoint = 0; +} + +void UndoHistory::SetSavePoint() { + savePoint = currentAction; +} + +bool UndoHistory::IsSavePoint() const { + return savePoint == currentAction; +} + +bool UndoHistory::CanUndo() const { + return (currentAction > 0) && (maxAction > 0); +} + +int UndoHistory::StartUndo() { + // Drop any trailing startAction + if (actions[currentAction].at == startAction && currentAction > 0) + currentAction--; + + // Count the steps in this action + int act = currentAction; + while (actions[act].at != startAction && act > 0) { + act--; + } + return currentAction - act; +} + +const Action &UndoHistory::GetUndoStep() const { + return actions[currentAction]; +} + +void UndoHistory::CompletedUndoStep() { + currentAction--; +} + +bool UndoHistory::CanRedo() const { + return maxAction > currentAction; +} + +int UndoHistory::StartRedo() { + // Drop any leading startAction + if (actions[currentAction].at == startAction && currentAction < maxAction) + currentAction++; + + // Count the steps in this action + int act = currentAction; + while (actions[act].at != startAction && act < maxAction) { + act++; + } + return act - currentAction; +} + +const Action &UndoHistory::GetRedoStep() const { + return actions[currentAction]; +} + +void UndoHistory::CompletedRedoStep() { + currentAction++; +} + +CellBuffer::CellBuffer() { + readOnly = false; + collectingUndo = true; +} + +CellBuffer::~CellBuffer() { +} + +char CellBuffer::CharAt(int position) const { + return substance.ValueAt(position); +} + +void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) { + if (lengthRetrieve < 0) + return; + if (position < 0) + return; + if ((position + lengthRetrieve) > substance.Length()) { + Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", position, + lengthRetrieve, substance.Length()); + return; + } + + for (int i=0; i((curVal & ~mask) | styleValue)); + return true; + } else { + return false; + } +} + +bool CellBuffer::SetStyleFor(int position, int lengthStyle, char styleValue, char mask) { + bool changed = false; + PLATFORM_ASSERT(lengthStyle == 0 || + (lengthStyle > 0 && lengthStyle + position <= style.Length())); + while (lengthStyle--) { + char curVal = style.ValueAt(position); + if ((curVal & mask) != styleValue) { + style.SetValueAt(position, static_cast((curVal & ~mask) | styleValue)); + changed = true; + } + position++; + } + return changed; +} + +// The char* returned is to an allocation owned by the undo history +const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startSequence) { + // InsertString and DeleteChars are the bottleneck though which all changes occur + PLATFORM_ASSERT(deleteLength > 0); + char *data = 0; + if (!readOnly) { + if (collectingUndo) { + // Save into the undo/redo stack, but only the characters - not the formatting + data = new char[deleteLength]; + for (int i = 0; i < deleteLength; i++) { + data[i] = substance.ValueAt(position + i); + } + uh.AppendAction(removeAction, position, data, deleteLength, startSequence); + } + + BasicDeleteChars(position, deleteLength); + } + return data; +} + +int CellBuffer::Length() const { + return substance.Length(); +} + +void CellBuffer::Allocate(int newSize) { + substance.ReAllocate(newSize); + style.ReAllocate(newSize); +} + +void CellBuffer::SetPerLine(PerLine *pl) { + lv.SetPerLine(pl); +} + +int CellBuffer::Lines() const { + return lv.Lines(); +} + +int CellBuffer::LineStart(int line) const { + if (line < 0) + return 0; + else if (line >= Lines()) + return Length(); + else + return lv.LineStart(line); +} + +bool CellBuffer::IsReadOnly() { + return readOnly; +} + +void CellBuffer::SetReadOnly(bool set) { + readOnly = set; +} + +void CellBuffer::SetSavePoint() { + uh.SetSavePoint(); +} + +bool CellBuffer::IsSavePoint() { + return uh.IsSavePoint(); +} + +// Without undo + +void CellBuffer::InsertLine(int line, int position) { + lv.InsertLine(line, position); +} + +void CellBuffer::RemoveLine(int line) { + lv.RemoveLine(line); +} + +void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) { + if (insertLength == 0) + return; + PLATFORM_ASSERT(insertLength > 0); + + substance.InsertFromArray(position, s, 0, insertLength); + style.InsertValue(position, insertLength, 0); + + int lineInsert = lv.LineFromPosition(position) + 1; + // Point all the lines after the insertion point further along in the buffer + lv.InsertText(lineInsert-1, insertLength); + char chPrev = substance.ValueAt(position - 1); + char chAfter = substance.ValueAt(position + insertLength); + if (chPrev == '\r' && chAfter == '\n') { + // Splitting up a crlf pair at position + InsertLine(lineInsert, position); + lineInsert++; + } + char ch = ' '; + for (int i = 0; i < insertLength; i++) { + ch = s[i]; + if (ch == '\r') { + InsertLine(lineInsert, (position + i) + 1); + lineInsert++; + } else if (ch == '\n') { + if (chPrev == '\r') { + // Patch up what was end of line + lv.SetLineStart(lineInsert - 1, (position + i) + 1); + } else { + InsertLine(lineInsert, (position + i) + 1); + lineInsert++; + } + } + chPrev = ch; + } + // Joining two lines where last insertion is cr and following substance starts with lf + if (chAfter == '\n') { + if (ch == '\r') { + // End of line already in buffer so drop the newly created one + RemoveLine(lineInsert - 1); + } + } +} + +void CellBuffer::BasicDeleteChars(int position, int deleteLength) { + if (deleteLength == 0) + return; + + if ((position == 0) && (deleteLength == substance.Length())) { + // If whole buffer is being deleted, faster to reinitialise lines data + // than to delete each line. + lv.Init(); + } else { + // Have to fix up line positions before doing deletion as looking at text in buffer + // to work out which lines have been removed + + int lineRemove = lv.LineFromPosition(position) + 1; + lv.InsertText(lineRemove-1, - (deleteLength)); + char chPrev = substance.ValueAt(position - 1); + char chBefore = chPrev; + char chNext = substance.ValueAt(position); + bool ignoreNL = false; + if (chPrev == '\r' && chNext == '\n') { + // Move back one + lv.SetLineStart(lineRemove, position); + lineRemove++; + ignoreNL = true; // First \n is not real deletion + } + + char ch = chNext; + for (int i = 0; i < deleteLength; i++) { + chNext = substance.ValueAt(position + i + 1); + if (ch == '\r') { + if (chNext != '\n') { + RemoveLine(lineRemove); + } + } else if (ch == '\n') { + if (ignoreNL) { + ignoreNL = false; // Further \n are real deletions + } else { + RemoveLine(lineRemove); + } + } + + ch = chNext; + } + // May have to fix up end if last deletion causes cr to be next to lf + // or removes one of a crlf pair + char chAfter = substance.ValueAt(position + deleteLength); + if (chBefore == '\r' && chAfter == '\n') { + // Using lineRemove-1 as cr ended line before start of deletion + RemoveLine(lineRemove - 1); + lv.SetLineStart(lineRemove - 1, position + 1); + } + } + substance.DeleteRange(position, deleteLength); + style.DeleteRange(position, deleteLength); +} + +bool CellBuffer::SetUndoCollection(bool collectUndo) { + collectingUndo = collectUndo; + uh.DropUndoSequence(); + return collectingUndo; +} + +bool CellBuffer::IsCollectingUndo() { + return collectingUndo; +} + +void CellBuffer::BeginUndoAction() { + uh.BeginUndoAction(); +} + +void CellBuffer::EndUndoAction() { + uh.EndUndoAction(); +} + +void CellBuffer::AddUndoAction(int token, bool mayCoalesce) { + bool startSequence; + uh.AppendAction(containerAction, token, 0, 0, startSequence, mayCoalesce); +} + +void CellBuffer::DeleteUndoHistory() { + uh.DeleteUndoHistory(); +} + +bool CellBuffer::CanUndo() { + return uh.CanUndo(); +} + +int CellBuffer::StartUndo() { + return uh.StartUndo(); +} + +const Action &CellBuffer::GetUndoStep() const { + return uh.GetUndoStep(); +} + +void CellBuffer::PerformUndoStep() { + const Action &actionStep = uh.GetUndoStep(); + if (actionStep.at == insertAction) { + BasicDeleteChars(actionStep.position, actionStep.lenData); + } else if (actionStep.at == removeAction) { + BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData); + } + uh.CompletedUndoStep(); +} + +bool CellBuffer::CanRedo() { + return uh.CanRedo(); +} + +int CellBuffer::StartRedo() { + return uh.StartRedo(); +} + +const Action &CellBuffer::GetRedoStep() const { + return uh.GetRedoStep(); +} + +void CellBuffer::PerformRedoStep() { + const Action &actionStep = uh.GetRedoStep(); + if (actionStep.at == insertAction) { + BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData); + } else if (actionStep.at == removeAction) { + BasicDeleteChars(actionStep.position, actionStep.lenData); + } + uh.CompletedRedoStep(); +} + diff --git a/harbour/contrib/hbide/qscintilla/CellBuffer.h b/harbour/contrib/hbide/qscintilla/CellBuffer.h new file mode 100644 index 0000000000..5af135736a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CellBuffer.h @@ -0,0 +1,207 @@ +// Scintilla source code edit control +/** @file CellBuffer.h + ** Manages the text of the document. + **/ +// Copyright 1998-2004 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CELLBUFFER_H +#define CELLBUFFER_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +// Interface to per-line data that wants to see each line insertion and deletion +class PerLine { +public: + virtual ~PerLine() {} + virtual void InsertLine(int)=0; + virtual void RemoveLine(int)=0; +}; + +/** + * The line vector contains information about each of the lines in a cell buffer. + */ +class LineVector { + + Partitioning starts; + PerLine *perLine; + +public: + + LineVector(); + ~LineVector(); + void Init(); + void SetPerLine(PerLine *pl); + + void InsertText(int line, int delta); + void InsertLine(int line, int position); + void SetLineStart(int line, int position); + void RemoveLine(int line); + int Lines() const { + return starts.Partitions(); + } + int LineFromPosition(int pos); + int LineStart(int line) const { + return starts.PositionFromPartition(line); + } + + int MarkValue(int line); + int AddMark(int line, int marker); + void MergeMarkers(int pos); + void DeleteMark(int line, int markerNum, bool all); + void DeleteMarkFromHandle(int markerHandle); + int LineFromHandle(int markerHandle); + + void ClearLevels(); + int SetLevel(int line, int level); + int GetLevel(int line); + + int SetLineState(int line, int state); + int GetLineState(int line); + int GetMaxLineState(); + +}; + +enum actionType { insertAction, removeAction, startAction, containerAction }; + +/** + * Actions are used to store all the information required to perform one undo/redo step. + */ +class Action { +public: + actionType at; + int position; + char *data; + int lenData; + bool mayCoalesce; + + Action(); + ~Action(); + void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true); + void Destroy(); + void Grab(Action *source); +}; + +/** + * + */ +class UndoHistory { + Action *actions; + int lenActions; + int maxAction; + int currentAction; + int undoSequenceDepth; + int savePoint; + + void EnsureUndoRoom(); + +public: + UndoHistory(); + ~UndoHistory(); + + void AppendAction(actionType at, int position, char *data, int length, bool &startSequence, bool mayCoalesce=true); + + void BeginUndoAction(); + void EndUndoAction(); + void DropUndoSequence(); + void DeleteUndoHistory(); + + /// The save point is a marker in the undo stack where the container has stated that + /// the buffer was saved. Undo and redo can move over the save point. + void SetSavePoint(); + bool IsSavePoint() const; + + /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is + /// called that many times. Similarly for redo. + bool CanUndo() const; + int StartUndo(); + const Action &GetUndoStep() const; + void CompletedUndoStep(); + bool CanRedo() const; + int StartRedo(); + const Action &GetRedoStep() const; + void CompletedRedoStep(); +}; + +/** + * Holder for an expandable array of characters that supports undo and line markers. + * Based on article "Data Structures in a Bit-Mapped Text Editor" + * by Wilfred J. Hansen, Byte January 1987, page 183. + */ +class CellBuffer { +private: + SplitVector substance; + SplitVector style; + bool readOnly; + + bool collectingUndo; + UndoHistory uh; + + LineVector lv; + +public: + + CellBuffer(); + ~CellBuffer(); + + /// Retrieving positions outside the range of the buffer works and returns 0 + char CharAt(int position) const; + void GetCharRange(char *buffer, int position, int lengthRetrieve); + char StyleAt(int position); + const char *BufferPointer(); + + int Length() const; + void Allocate(int newSize); + void SetPerLine(PerLine *pl); + int Lines() const; + int LineStart(int line) const; + int LineFromPosition(int pos) { return lv.LineFromPosition(pos); } + void InsertLine(int line, int position); + void RemoveLine(int line); + const char *InsertString(int position, const char *s, int insertLength, bool &startSequence); + + /// Setting styles for positions outside the range of the buffer is safe and has no effect. + /// @return true if the style of a character is changed. + bool SetStyleAt(int position, char styleValue, char mask='\377'); + bool SetStyleFor(int position, int length, char styleValue, char mask); + + const char *DeleteChars(int position, int deleteLength, bool &startSequence); + + bool IsReadOnly(); + void SetReadOnly(bool set); + + /// The save point is a marker in the undo stack where the container has stated that + /// the buffer was saved. Undo and redo can move over the save point. + void SetSavePoint(); + bool IsSavePoint(); + + /// Actions without undo + void BasicInsertString(int position, const char *s, int insertLength); + void BasicDeleteChars(int position, int deleteLength); + + bool SetUndoCollection(bool collectUndo); + bool IsCollectingUndo(); + void BeginUndoAction(); + void EndUndoAction(); + void AddUndoAction(int token, bool mayCoalesce); + void DeleteUndoHistory(); + + /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is + /// called that many times. Similarly for redo. + bool CanUndo(); + int StartUndo(); + const Action &GetUndoStep() const; + void PerformUndoStep(); + bool CanRedo(); + int StartRedo(); + const Action &GetRedoStep() const; + void PerformRedoStep(); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/CharClassify.cpp b/harbour/contrib/hbide/qscintilla/CharClassify.cpp new file mode 100644 index 0000000000..acab4b2295 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CharClassify.cpp @@ -0,0 +1,43 @@ +// Scintilla source code edit control +/** @file CharClassify.cxx + ** Character classifications used by Document and RESearch. + **/ +// Copyright 2006 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "CharClassify.h" + +// Shut up annoying Visual C++ warnings: +#ifdef _MSC_VER +#pragma warning(disable: 4514) +#endif + +CharClassify::CharClassify() { + SetDefaultCharClasses(true); +} + +void CharClassify::SetDefaultCharClasses(bool includeWordClass) { + // Initialize all char classes to default values + for (int ch = 0; ch < 256; ch++) { + if (ch == '\r' || ch == '\n') + charClass[ch] = ccNewLine; + else if (ch < 0x20 || ch == ' ') + charClass[ch] = ccSpace; + else if (includeWordClass && (ch >= 0x80 || isalnum(ch) || ch == '_')) + charClass[ch] = ccWord; + else + charClass[ch] = ccPunctuation; + } +} + +void CharClassify::SetCharClasses(const unsigned char *chars, cc newCharClass) { + // Apply the newCharClass to the specifed chars + if (chars) { + while (*chars) { + charClass[*chars] = static_cast(newCharClass); + chars++; + } + } +} diff --git a/harbour/contrib/hbide/qscintilla/CharClassify.h b/harbour/contrib/hbide/qscintilla/CharClassify.h new file mode 100644 index 0000000000..881d3a114b --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CharClassify.h @@ -0,0 +1,25 @@ +// Scintilla source code edit control +/** @file CharClassify.h + ** Character classifications used by Document and RESearch. + **/ +// Copyright 2006 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CHARCLASSIFY_H +#define CHARCLASSIFY_H + +class CharClassify { +public: + CharClassify(); + + enum cc { ccSpace, ccNewLine, ccWord, ccPunctuation }; + void SetDefaultCharClasses(bool includeWordClass); + void SetCharClasses(const unsigned char *chars, cc newCharClass); + cc GetClass(unsigned char ch) const { return static_cast(charClass[ch]);} + bool IsWord(unsigned char ch) const { return static_cast(charClass[ch]) == ccWord;} + +private: + enum { maxChar=256 }; + unsigned char charClass[maxChar]; // not type cc to save space +}; +#endif diff --git a/harbour/contrib/hbide/qscintilla/CharacterSet.h b/harbour/contrib/hbide/qscintilla/CharacterSet.h new file mode 100644 index 0000000000..4e8ffbdf6f --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/CharacterSet.h @@ -0,0 +1,58 @@ +// Scintilla source code edit control +/** @file CharacterSet.h + ** Encapsulates a set of characters. Used to test if a character is within a set. + **/ +// Copyright 2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +class CharacterSet { + int size; + bool valueAfter; + bool *bset; +public: + enum setBase { + setNone=0, + setLower=1, + setUpper=2, + setDigits=4, + setAlpha=setLower|setUpper, + setAlphaNum=setAlpha|setDigits + }; + CharacterSet(setBase base=setNone, const char *initialSet="", int size_=0x80, bool valueAfter_=false) { + size = size_; + valueAfter = valueAfter_; + bset = new bool[size]; + for (int i=0; i < size; i++) { + bset[i] = false; + } + AddString(initialSet); + if (base & setLower) + AddString("abcdefghijklmnopqrstuvwxyz"); + if (base & setUpper) + AddString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + if (base & setDigits) + AddString("0123456789"); + } + ~CharacterSet() { + delete []bset; + bset = 0; + size = 0; + } + void Add(int val) { + PLATFORM_ASSERT(val >= 0); + PLATFORM_ASSERT(val < size); + bset[val] = true; + } + void AddString(const char *CharacterSet) { + for (const char *cp=CharacterSet; *cp; cp++) { + int val = static_cast(*cp); + PLATFORM_ASSERT(val >= 0); + PLATFORM_ASSERT(val < size); + bset[val] = true; + } + } + bool Contains(int val) const { + PLATFORM_ASSERT(val >= 0); + return (val < size) ? bset[val] : valueAfter; + } +}; diff --git a/harbour/contrib/hbide/qscintilla/ContractionState.cpp b/harbour/contrib/hbide/qscintilla/ContractionState.cpp new file mode 100644 index 0000000000..08de5cf1f7 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ContractionState.cpp @@ -0,0 +1,251 @@ +// Scintilla source code edit control +/** @file ContractionState.cxx + ** Manages visibility of lines for folding and wrapping. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +ContractionState::ContractionState() : visible(0), expanded(0), heights(0), displayLines(0), linesInDocument(1) { + //InsertLine(0); +} + +ContractionState::~ContractionState() { + Clear(); +} + +void ContractionState::EnsureData() { + if (OneToOne()) { + visible = new RunStyles(); + expanded = new RunStyles(); + heights = new RunStyles(); + displayLines = new Partitioning(4); + InsertLines(0, linesInDocument); + } +} + +void ContractionState::Clear() { + delete visible; + visible = 0; + delete expanded; + expanded = 0; + delete heights; + heights = 0; + delete displayLines; + displayLines = 0; + linesInDocument = 1; +} + +int ContractionState::LinesInDoc() const { + if (OneToOne()) { + return linesInDocument; + } else { + return displayLines->Partitions() - 1; + } +} + +int ContractionState::LinesDisplayed() const { + if (OneToOne()) { + return linesInDocument; + } else { + return displayLines->PositionFromPartition(LinesInDoc()); + } +} + +int ContractionState::DisplayFromDoc(int lineDoc) const { + if (OneToOne()) { + return lineDoc; + } else { + if (lineDoc > displayLines->Partitions()) + lineDoc = displayLines->Partitions(); + return displayLines->PositionFromPartition(lineDoc); + } +} + +int ContractionState::DocFromDisplay(int lineDisplay) const { + if (OneToOne()) { + return lineDisplay; + } else { + if (lineDisplay <= 0) { + return 0; + } + if (lineDisplay > LinesDisplayed()) { + return displayLines->PartitionFromPosition(LinesDisplayed()); + } + int lineDoc = displayLines->PartitionFromPosition(lineDisplay); + PLATFORM_ASSERT(GetVisible(lineDoc)); + return lineDoc; + } +} + +void ContractionState::InsertLine(int lineDoc) { + if (OneToOne()) { + linesInDocument++; + } else { + visible->InsertSpace(lineDoc, 1); + visible->SetValueAt(lineDoc, 1); + expanded->InsertSpace(lineDoc, 1); + expanded->SetValueAt(lineDoc, 1); + heights->InsertSpace(lineDoc, 1); + heights->SetValueAt(lineDoc, 1); + int lineDisplay = DisplayFromDoc(lineDoc); + displayLines->InsertPartition(lineDoc, lineDisplay); + displayLines->InsertText(lineDoc, 1); + } +} + +void ContractionState::InsertLines(int lineDoc, int lineCount) { + for (int l = 0; l < lineCount; l++) { + InsertLine(lineDoc + l); + } + Check(); +} + +void ContractionState::DeleteLine(int lineDoc) { + if (OneToOne()) { + linesInDocument--; + } else { + if (GetVisible(lineDoc)) { + displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc)); + } + displayLines->RemovePartition(lineDoc); + visible->DeleteRange(lineDoc, 1); + expanded->DeleteRange(lineDoc, 1); + heights->DeleteRange(lineDoc, 1); + } +} + +void ContractionState::DeleteLines(int lineDoc, int lineCount) { + for (int l = 0; l < lineCount; l++) { + DeleteLine(lineDoc); + } + Check(); +} + +bool ContractionState::GetVisible(int lineDoc) const { + if (OneToOne()) { + return true; + } else { + if (lineDoc >= visible->Length()) + return true; + return visible->ValueAt(lineDoc) == 1; + } +} + +bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) { + if (OneToOne() && visible_) { + return false; + } else { + EnsureData(); + int delta = 0; + Check(); + if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) { + for (int line = lineDocStart; line <= lineDocEnd; line++) { + if (GetVisible(line) != visible_) { + int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line); + visible->SetValueAt(line, visible_ ? 1 : 0); + displayLines->InsertText(line, difference); + delta += difference; + } + } + } else { + return false; + } + Check(); + return delta != 0; + } +} + +bool ContractionState::GetExpanded(int lineDoc) const { + if (OneToOne()) { + return true; + } else { + Check(); + return expanded->ValueAt(lineDoc) == 1; + } +} + +bool ContractionState::SetExpanded(int lineDoc, bool expanded_) { + if (OneToOne() && expanded_) { + return false; + } else { + EnsureData(); + if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) { + expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0); + Check(); + return true; + } else { + Check(); + return false; + } + } +} + +int ContractionState::GetHeight(int lineDoc) const { + if (OneToOne()) { + return 1; + } else { + return heights->ValueAt(lineDoc); + } +} + +// Set the number of display lines needed for this line. +// Return true if this is a change. +bool ContractionState::SetHeight(int lineDoc, int height) { + if (OneToOne() && (height == 1)) { + return false; + } else { + EnsureData(); + if (GetHeight(lineDoc) != height) { + if (GetVisible(lineDoc)) { + displayLines->InsertText(lineDoc, height - GetHeight(lineDoc)); + } + heights->SetValueAt(lineDoc, height); + Check(); + return true; + } else { + Check(); + return false; + } + } +} + +void ContractionState::ShowAll() { + int lines = LinesInDoc(); + Clear(); + linesInDocument = lines; +} + +// Debugging checks + +void ContractionState::Check() const { +#ifdef CHECK_CORRECTNESS + for (int vline = 0;vline < LinesDisplayed(); vline++) { + const int lineDoc = DocFromDisplay(vline); + PLATFORM_ASSERT(GetVisible(lineDoc)); + } + for (int lineDoc = 0;lineDoc < LinesInDoc(); lineDoc++) { + const int displayThis = DisplayFromDoc(lineDoc); + const int displayNext = DisplayFromDoc(lineDoc + 1); + const int height = displayNext - displayThis; + PLATFORM_ASSERT(height >= 0); + if (GetVisible(lineDoc)) { + PLATFORM_ASSERT(GetHeight(lineDoc) == height); + } else { + PLATFORM_ASSERT(0 == height); + } + } +#endif +} diff --git a/harbour/contrib/hbide/qscintilla/ContractionState.h b/harbour/contrib/hbide/qscintilla/ContractionState.h new file mode 100644 index 0000000000..ba62975128 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ContractionState.h @@ -0,0 +1,66 @@ +// Scintilla source code edit control +/** @file ContractionState.h + ** Manages visibility of lines for folding and wrapping. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CONTRACTIONSTATE_H +#define CONTRACTIONSTATE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class ContractionState { + // These contain 1 element for every document line. + RunStyles *visible; + RunStyles *expanded; + RunStyles *heights; + Partitioning *displayLines; + int linesInDocument; + + void EnsureData(); + + bool OneToOne() const { + // True when each document line is exactly one display line so need for + // complex data structures. + return visible == 0; + } + +public: + ContractionState(); + virtual ~ContractionState(); + + void Clear(); + + int LinesInDoc() const; + int LinesDisplayed() const; + int DisplayFromDoc(int lineDoc) const; + int DocFromDisplay(int lineDisplay) const; + + void InsertLine(int lineDoc); + void InsertLines(int lineDoc, int lineCount); + void DeleteLine(int lineDoc); + void DeleteLines(int lineDoc, int lineCount); + + bool GetVisible(int lineDoc) const; + bool SetVisible(int lineDocStart, int lineDocEnd, bool visible); + + bool GetExpanded(int lineDoc) const; + bool SetExpanded(int lineDoc, bool expanded); + + int GetHeight(int lineDoc) const; + bool SetHeight(int lineDoc, int height); + + void ShowAll(); + void Check() const; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Decoration.cpp b/harbour/contrib/hbide/qscintilla/Decoration.cpp new file mode 100644 index 0000000000..f551c7d707 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Decoration.cpp @@ -0,0 +1,188 @@ +/** @file Decoration.cxx + ** Visual elements added over text. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "Decoration.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +Decoration::Decoration(int indicator_) : next(0), indicator(indicator_) { +} + +Decoration::~Decoration() { +} + +bool Decoration::Empty() { + return rs.starts->Partitions() == 1; +} + +DecorationList::DecorationList() : currentIndicator(0), currentValue(1), current(0), + lengthDocument(0), root(0), clickNotified(false) { +} + +DecorationList::~DecorationList() { + Decoration *deco = root; + while (deco) { + Decoration *decoNext = deco->next; + delete deco; + deco = decoNext; + } + root = 0; + current = 0; +} + +Decoration *DecorationList::DecorationFromIndicator(int indicator) { + for (Decoration *deco=root; deco; deco = deco->next) { + if (deco->indicator == indicator) { + return deco; + } + } + return 0; +} + +Decoration *DecorationList::Create(int indicator, int length) { + currentIndicator = indicator; + Decoration *decoNew = new Decoration(indicator); + decoNew->rs.InsertSpace(0, length); + + Decoration *decoPrev = 0; + Decoration *deco = root; + + while (deco && (deco->indicator < indicator)) { + decoPrev = deco; + deco = deco->next; + } + if (decoPrev == 0) { + decoNew->next = root; + root = decoNew; + } else { + decoNew->next = deco; + decoPrev->next = decoNew; + } + return decoNew; +} + +void DecorationList::Delete(int indicator) { + Decoration *decoToDelete = 0; + if (root) { + if (root->indicator == indicator) { + decoToDelete = root; + root = root->next; + } else { + Decoration *deco=root; + while (deco->next && !decoToDelete) { + if (deco->next && deco->next->indicator == indicator) { + decoToDelete = deco->next; + deco->next = decoToDelete->next; + } else { + deco = deco->next; + } + } + } + } + if (decoToDelete) { + delete decoToDelete; + current = 0; + } +} + +void DecorationList::SetCurrentIndicator(int indicator) { + currentIndicator = indicator; + current = DecorationFromIndicator(indicator); + currentValue = 1; +} + +void DecorationList::SetCurrentValue(int value) { + currentValue = value ? value : 1; +} + +bool DecorationList::FillRange(int &position, int value, int &fillLength) { + if (!current) { + current = DecorationFromIndicator(currentIndicator); + if (!current) { + current = Create(currentIndicator, lengthDocument); + } + } + bool changed = current->rs.FillRange(position, value, fillLength); + if (current->Empty()) { + Delete(currentIndicator); + } + return changed; +} + +void DecorationList::InsertSpace(int position, int insertLength) { + lengthDocument += insertLength; + for (Decoration *deco=root; deco; deco = deco->next) { + deco->rs.InsertSpace(position, insertLength); + } +} + +void DecorationList::DeleteRange(int position, int deleteLength) { + lengthDocument -= deleteLength; + Decoration *deco; + for (deco=root; deco; deco = deco->next) { + deco->rs.DeleteRange(position, deleteLength); + } + DeleteAnyEmpty(); +} + +void DecorationList::DeleteAnyEmpty() { + Decoration *deco = root; + while (deco) { + if (deco->Empty()) { + Delete(deco->indicator); + deco = root; + } else { + deco = deco->next; + } + } +} + +int DecorationList::AllOnFor(int position) { + int mask = 0; + for (Decoration *deco=root; deco; deco = deco->next) { + if (deco->rs.ValueAt(position)) { + mask |= 1 << deco->indicator; + } + } + return mask; +} + +int DecorationList::ValueAt(int indicator, int position) { + Decoration *deco = DecorationFromIndicator(indicator); + if (deco) { + return deco->rs.ValueAt(position); + } + return 0; +} + +int DecorationList::Start(int indicator, int position) { + Decoration *deco = DecorationFromIndicator(indicator); + if (deco) { + return deco->rs.StartRun(position); + } + return 0; +} + +int DecorationList::End(int indicator, int position) { + Decoration *deco = DecorationFromIndicator(indicator); + if (deco) { + return deco->rs.EndRun(position); + } + return 0; +} diff --git a/harbour/contrib/hbide/qscintilla/Decoration.h b/harbour/contrib/hbide/qscintilla/Decoration.h new file mode 100644 index 0000000000..2809641afd --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Decoration.h @@ -0,0 +1,64 @@ +/** @file Decoration.h + ** Visual elements added over text. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef DECORATION_H +#define DECORATION_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class Decoration { +public: + Decoration *next; + RunStyles rs; + int indicator; + + Decoration(int indicator_); + ~Decoration(); + + bool Empty(); +}; + +class DecorationList { + int currentIndicator; + int currentValue; + Decoration *current; + int lengthDocument; + Decoration *DecorationFromIndicator(int indicator); + Decoration *Create(int indicator, int length); + void Delete(int indicator); + void DeleteAnyEmpty(); +public: + Decoration *root; + bool clickNotified; + + DecorationList(); + ~DecorationList(); + + void SetCurrentIndicator(int indicator); + int GetCurrentIndicator() { return currentIndicator; } + + void SetCurrentValue(int value); + int GetCurrentValue() { return currentValue; } + + // Returns true if some values may have changed + bool FillRange(int &position, int value, int &fillLength); + + void InsertSpace(int position, int insertLength); + void DeleteRange(int position, int deleteLength); + + int AllOnFor(int position); + int ValueAt(int indicator, int position); + int Start(int indicator, int position); + int End(int indicator, int position); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Document.cpp b/harbour/contrib/hbide/qscintilla/Document.cpp new file mode 100644 index 0000000000..3c1537d9e9 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Document.cpp @@ -0,0 +1,1820 @@ +// Scintilla source code edit control +/** @file Document.cxx + ** Text document that handles notifications, DBCS, styling, words and end of line. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "CellBuffer.h" +#include "PerLine.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "Document.h" +#include "RESearch.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +// This is ASCII specific but is safe with chars >= 0x80 +static inline bool isspacechar(unsigned char ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +static inline bool IsPunctuation(char ch) { + return isascii(ch) && ispunct(ch); +} + +static inline bool IsADigit(char ch) { + return isascii(ch) && isdigit(ch); +} + +static inline bool IsLowerCase(char ch) { + return isascii(ch) && islower(ch); +} + +static inline bool IsUpperCase(char ch) { + return isascii(ch) && isupper(ch); +} + +Document::Document() { + refCount = 0; +#ifdef unix + eolMode = SC_EOL_LF; +#else + eolMode = SC_EOL_CRLF; +#endif + dbcsCodePage = 0; + stylingBits = 5; + stylingBitsMask = 0x1F; + stylingMask = 0; + endStyled = 0; + styleClock = 0; + enteredModification = 0; + enteredStyling = 0; + enteredReadOnlyCount = 0; + tabInChars = 8; + indentInChars = 0; + actualIndentInChars = 8; + useTabs = true; + tabIndents = true; + backspaceUnindents = false; + watchers = 0; + lenWatchers = 0; + + matchesValid = false; + regex = 0; + + perLineData[ldMarkers] = new LineMarkers(); + perLineData[ldLevels] = new LineLevels(); + perLineData[ldState] = new LineState(); + perLineData[ldMargin] = new LineAnnotation(); + perLineData[ldAnnotation] = new LineAnnotation(); + + cb.SetPerLine(this); +} + +Document::~Document() { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyDeleted(this, watchers[i].userData); + } + delete []watchers; + for (int j=0; jInsertLine(line); + } +} + +void Document::RemoveLine(int line) { + for (int j=0; jRemoveLine(line); + } +} + +// Increase reference count and return its previous value. +int Document::AddRef() { + return refCount++; +} + +// Decrease reference count and return its previous value. +// Delete the document if reference count reaches zero. +int Document::Release() { + int curRefCount = --refCount; + if (curRefCount == 0) + delete this; + return curRefCount; +} + +void Document::SetSavePoint() { + cb.SetSavePoint(); + NotifySavePoint(true); +} + +int Document::GetMark(int line) { + return static_cast(perLineData[ldMarkers])->MarkValue(line); +} + +int Document::AddMark(int line, int markerNum) { + if (line <= LinesTotal()) { + int prev = static_cast(perLineData[ldMarkers])-> + AddMark(line, markerNum, LinesTotal()); + DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); + NotifyModified(mh); + return prev; + } else { + return 0; + } +} + +void Document::AddMarkSet(int line, int valueSet) { + unsigned int m = valueSet; + for (int i = 0; m; i++, m >>= 1) + if (m & 1) + static_cast(perLineData[ldMarkers])-> + AddMark(line, i, LinesTotal()); + DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); + NotifyModified(mh); +} + +void Document::DeleteMark(int line, int markerNum) { + static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, false); + DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); + NotifyModified(mh); +} + +void Document::DeleteMarkFromHandle(int markerHandle) { + static_cast(perLineData[ldMarkers])->DeleteMarkFromHandle(markerHandle); + DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); + mh.line = -1; + NotifyModified(mh); +} + +void Document::DeleteAllMarks(int markerNum) { + for (int line = 0; line < LinesTotal(); line++) { + static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, true); + } + DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); + mh.line = -1; + NotifyModified(mh); +} + +int Document::LineFromHandle(int markerHandle) { + return static_cast(perLineData[ldMarkers])->LineFromHandle(markerHandle); +} + +int Document::LineStart(int line) const { + return cb.LineStart(line); +} + +int Document::LineEnd(int line) const { + if (line == LinesTotal() - 1) { + return LineStart(line + 1); + } else { + int position = LineStart(line + 1) - 1; + // When line terminator is CR+LF, may need to go back one more + if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) { + position--; + } + return position; + } +} + +int Document::LineFromPosition(int pos) { + return cb.LineFromPosition(pos); +} + +int Document::LineEndPosition(int position) { + return LineEnd(LineFromPosition(position)); +} + +int Document::VCHomePosition(int position) { + int line = LineFromPosition(position); + int startPosition = LineStart(line); + int endLine = LineEnd(line); + int startText = startPosition; + while (startText < endLine && (cb.CharAt(startText) == ' ' || cb.CharAt(startText) == '\t' ) ) + startText++; + if (position == startText) + return startPosition; + else + return startText; +} + +int Document::SetLevel(int line, int level) { + int prev = static_cast(perLineData[ldLevels])->SetLevel(line, level, LinesTotal()); + if (prev != level) { + DocModification mh(SC_MOD_CHANGEFOLD | SC_MOD_CHANGEMARKER, + LineStart(line), 0, 0, 0, line); + mh.foldLevelNow = level; + mh.foldLevelPrev = prev; + NotifyModified(mh); + } + return prev; +} + +int Document::GetLevel(int line) { + return static_cast(perLineData[ldLevels])->GetLevel(line); +} + +void Document::ClearLevels() { + static_cast(perLineData[ldLevels])->ClearLevels(); +} + +static bool IsSubordinate(int levelStart, int levelTry) { + if (levelTry & SC_FOLDLEVELWHITEFLAG) + return true; + else + return (levelStart & SC_FOLDLEVELNUMBERMASK) < (levelTry & SC_FOLDLEVELNUMBERMASK); +} + +int Document::GetLastChild(int lineParent, int level) { + if (level == -1) + level = GetLevel(lineParent) & SC_FOLDLEVELNUMBERMASK; + int maxLine = LinesTotal(); + int lineMaxSubord = lineParent; + while (lineMaxSubord < maxLine - 1) { + EnsureStyledTo(LineStart(lineMaxSubord + 2)); + if (!IsSubordinate(level, GetLevel(lineMaxSubord + 1))) + break; + lineMaxSubord++; + } + if (lineMaxSubord > lineParent) { + if (level > (GetLevel(lineMaxSubord + 1) & SC_FOLDLEVELNUMBERMASK)) { + // Have chewed up some whitespace that belongs to a parent so seek back + if (GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG) { + lineMaxSubord--; + } + } + } + return lineMaxSubord; +} + +int Document::GetFoldParent(int line) { + int level = GetLevel(line) & SC_FOLDLEVELNUMBERMASK; + int lineLook = line - 1; + while ((lineLook > 0) && ( + (!(GetLevel(lineLook) & SC_FOLDLEVELHEADERFLAG)) || + ((GetLevel(lineLook) & SC_FOLDLEVELNUMBERMASK) >= level)) + ) { + lineLook--; + } + if ((GetLevel(lineLook) & SC_FOLDLEVELHEADERFLAG) && + ((GetLevel(lineLook) & SC_FOLDLEVELNUMBERMASK) < level)) { + return lineLook; + } else { + return -1; + } +} + +int Document::ClampPositionIntoDocument(int pos) { + return Platform::Clamp(pos, 0, Length()); +} + +bool Document::IsCrLf(int pos) { + if (pos < 0) + return false; + if (pos >= (Length() - 1)) + return false; + return (cb.CharAt(pos) == '\r') && (cb.CharAt(pos + 1) == '\n'); +} + +static const int maxBytesInDBCSCharacter=5; + +int Document::LenChar(int pos) { + if (pos < 0) { + return 1; + } else if (IsCrLf(pos)) { + return 2; + } else if (SC_CP_UTF8 == dbcsCodePage) { + unsigned char ch = static_cast(cb.CharAt(pos)); + if (ch < 0x80) + return 1; + int len = 2; + if (ch >= (0x80 + 0x40 + 0x20 + 0x10)) + len = 4; + else if (ch >= (0x80 + 0x40 + 0x20)) + len = 3; + int lengthDoc = Length(); + if ((pos + len) > lengthDoc) + return lengthDoc -pos; + else + return len; + } else if (dbcsCodePage) { + char mbstr[maxBytesInDBCSCharacter+1]; + int i; + for (i=0; i= 0x80) && (ch < (0x80 + 0x40)); +} + +static int BytesFromLead(int leadByte) { + if (leadByte > 0xF4) { + // Characters longer than 4 bytes not possible in current UTF-8 + return 0; + } else if (leadByte >= 0xF0) { + return 4; + } else if (leadByte >= 0xE0) { + return 3; + } else if (leadByte >= 0xC2) { + return 2; + } + return 0; +} + +bool Document::InGoodUTF8(int pos, int &start, int &end) { + int lead = pos; + while ((lead>0) && (pos-lead < 4) && IsTrailByte(static_cast(cb.CharAt(lead-1)))) + lead--; + start = 0; + if (lead > 0) { + start = lead-1; + } + int leadByte = static_cast(cb.CharAt(start)); + int bytes = BytesFromLead(leadByte); + if (bytes == 0) { + return false; + } else { + int trailBytes = bytes - 1; + int len = pos - lead + 1; + if (len > trailBytes) + // pos too far from lead + return false; + // Check that there are enough trails for this lead + int trail = pos + 1; + while ((trail-lead(cb.CharAt(trail)))) { + return false; + } + trail++; + } + end = start + bytes; + return true; + } +} + +// Normalise a position so that it is not halfway through a two byte character. +// This can occur in two situations - +// When lines are terminated with \r\n pairs which should be treated as one character. +// When displaying DBCS text such as Japanese. +// If moving, move the position in the indicated direction. +int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { + //Platform::DebugPrintf("NoCRLF %d %d\n", pos, moveDir); + // If out of range, just return minimum/maximum value. + if (pos <= 0) + return 0; + if (pos >= Length()) + return Length(); + + // PLATFORM_ASSERT(pos > 0 && pos < Length()); + if (checkLineEnd && IsCrLf(pos - 1)) { + if (moveDir > 0) + return pos + 1; + else + return pos - 1; + } + + // Not between CR and LF + + if (dbcsCodePage) { + if (SC_CP_UTF8 == dbcsCodePage) { + unsigned char ch = static_cast(cb.CharAt(pos)); + int startUTF = pos; + int endUTF = pos; + if (IsTrailByte(ch) && InGoodUTF8(pos, startUTF, endUTF)) { + // ch is a trail byte within a UTF-8 character + if (moveDir > 0) + pos = endUTF; + else + pos = startUTF; + } + } else { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int posCheck = LineStart(LineFromPosition(pos)); + while (posCheck < pos) { + char mbstr[maxBytesInDBCSCharacter+1]; + int i; + for(i=0;i pos) { + if (moveDir > 0) { + return posCheck + mbsize; + } else { + return posCheck; + } + } + posCheck += mbsize; + } + } + } + + return pos; +} + +void Document::ModifiedAt(int pos) { + if (endStyled > pos) + endStyled = pos; +} + +void Document::CheckReadOnly() { + if (cb.IsReadOnly() && enteredReadOnlyCount == 0) { + enteredReadOnlyCount++; + NotifyModifyAttempt(); + enteredReadOnlyCount--; + } +} + +// Document only modified by gateways DeleteChars, InsertString, Undo, Redo, and SetStyleAt. +// SetStyleAt does not change the persistent state of a document + +bool Document::DeleteChars(int pos, int len) { + if (len == 0) + return false; + if ((pos + len) > Length()) + return false; + CheckReadOnly(); + if (enteredModification != 0) { + return false; + } else { + enteredModification++; + if (!cb.IsReadOnly()) { + NotifyModified( + DocModification( + SC_MOD_BEFOREDELETE | SC_PERFORMED_USER, + pos, len, + 0, 0)); + int prevLinesTotal = LinesTotal(); + bool startSavePoint = cb.IsSavePoint(); + bool startSequence = false; + const char *text = cb.DeleteChars(pos, len, startSequence); + if (startSavePoint && cb.IsCollectingUndo()) + NotifySavePoint(!startSavePoint); + if ((pos < Length()) || (pos == 0)) + ModifiedAt(pos); + else + ModifiedAt(pos-1); + NotifyModified( + DocModification( + SC_MOD_DELETETEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0), + pos, len, + LinesTotal() - prevLinesTotal, text)); + } + enteredModification--; + } + return !cb.IsReadOnly(); +} + +/** + * Insert a string with a length. + */ +bool Document::InsertString(int position, const char *s, int insertLength) { + if (insertLength <= 0) { + return false; + } + CheckReadOnly(); + if (enteredModification != 0) { + return false; + } else { + enteredModification++; + if (!cb.IsReadOnly()) { + NotifyModified( + DocModification( + SC_MOD_BEFOREINSERT | SC_PERFORMED_USER, + position, insertLength, + 0, s)); + int prevLinesTotal = LinesTotal(); + bool startSavePoint = cb.IsSavePoint(); + bool startSequence = false; + const char *text = cb.InsertString(position, s, insertLength, startSequence); + if (startSavePoint && cb.IsCollectingUndo()) + NotifySavePoint(!startSavePoint); + ModifiedAt(position); + NotifyModified( + DocModification( + SC_MOD_INSERTTEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0), + position, insertLength, + LinesTotal() - prevLinesTotal, text)); + } + enteredModification--; + } + return !cb.IsReadOnly(); +} + +int Document::Undo() { + int newPos = -1; + CheckReadOnly(); + if (enteredModification == 0) { + enteredModification++; + if (!cb.IsReadOnly()) { + bool startSavePoint = cb.IsSavePoint(); + bool multiLine = false; + int steps = cb.StartUndo(); + //Platform::DebugPrintf("Steps=%d\n", steps); + for (int step = 0; step < steps; step++) { + const int prevLinesTotal = LinesTotal(); + const Action &action = cb.GetUndoStep(); + if (action.at == removeAction) { + NotifyModified(DocModification( + SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); + } else if (action.at == containerAction) { + DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); + dm.token = action.position; + NotifyModified(dm); + } else { + NotifyModified(DocModification( + SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); + } + cb.PerformUndoStep(); + int cellPosition = action.position; + if (action.at != containerAction) { + ModifiedAt(cellPosition); + newPos = cellPosition; + } + + int modFlags = SC_PERFORMED_UNDO; + // With undo, an insertion action becomes a deletion notification + if (action.at == removeAction) { + newPos += action.lenData; + modFlags |= SC_MOD_INSERTTEXT; + } else if (action.at == insertAction) { + modFlags |= SC_MOD_DELETETEXT; + } + if (steps > 1) + modFlags |= SC_MULTISTEPUNDOREDO; + const int linesAdded = LinesTotal() - prevLinesTotal; + if (linesAdded != 0) + multiLine = true; + if (step == steps - 1) { + modFlags |= SC_LASTSTEPINUNDOREDO; + if (multiLine) + modFlags |= SC_MULTILINEUNDOREDO; + } + NotifyModified(DocModification(modFlags, cellPosition, action.lenData, + linesAdded, action.data)); + } + + bool endSavePoint = cb.IsSavePoint(); + if (startSavePoint != endSavePoint) + NotifySavePoint(endSavePoint); + } + enteredModification--; + } + return newPos; +} + +int Document::Redo() { + int newPos = -1; + CheckReadOnly(); + if (enteredModification == 0) { + enteredModification++; + if (!cb.IsReadOnly()) { + bool startSavePoint = cb.IsSavePoint(); + bool multiLine = false; + int steps = cb.StartRedo(); + for (int step = 0; step < steps; step++) { + const int prevLinesTotal = LinesTotal(); + const Action &action = cb.GetRedoStep(); + if (action.at == insertAction) { + NotifyModified(DocModification( + SC_MOD_BEFOREINSERT | SC_PERFORMED_REDO, action)); + } else if (action.at == containerAction) { + DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_REDO); + dm.token = action.position; + NotifyModified(dm); + } else { + NotifyModified(DocModification( + SC_MOD_BEFOREDELETE | SC_PERFORMED_REDO, action)); + } + cb.PerformRedoStep(); + if (action.at != containerAction) { + ModifiedAt(action.position); + newPos = action.position; + } + + int modFlags = SC_PERFORMED_REDO; + if (action.at == insertAction) { + newPos += action.lenData; + modFlags |= SC_MOD_INSERTTEXT; + } else if (action.at == removeAction) { + modFlags |= SC_MOD_DELETETEXT; + } + if (steps > 1) + modFlags |= SC_MULTISTEPUNDOREDO; + const int linesAdded = LinesTotal() - prevLinesTotal; + if (linesAdded != 0) + multiLine = true; + if (step == steps - 1) { + modFlags |= SC_LASTSTEPINUNDOREDO; + if (multiLine) + modFlags |= SC_MULTILINEUNDOREDO; + } + NotifyModified( + DocModification(modFlags, action.position, action.lenData, + linesAdded, action.data)); + } + + bool endSavePoint = cb.IsSavePoint(); + if (startSavePoint != endSavePoint) + NotifySavePoint(endSavePoint); + } + enteredModification--; + } + return newPos; +} + +/** + * Insert a single character. + */ +bool Document::InsertChar(int pos, char ch) { + char chs[1]; + chs[0] = ch; + return InsertString(pos, chs, 1); +} + +/** + * Insert a null terminated string. + */ +bool Document::InsertCString(int position, const char *s) { + return InsertString(position, s, strlen(s)); +} + +void Document::ChangeChar(int pos, char ch) { + DeleteChars(pos, 1); + InsertChar(pos, ch); +} + +void Document::DelChar(int pos) { + DeleteChars(pos, LenChar(pos)); +} + +void Document::DelCharBack(int pos) { + if (pos <= 0) { + return; + } else if (IsCrLf(pos - 2)) { + DeleteChars(pos - 2, 2); + } else if (dbcsCodePage) { + int startChar = MovePositionOutsideChar(pos - 1, -1, false); + DeleteChars(startChar, pos - startChar); + } else { + DeleteChars(pos - 1, 1); + } +} + +static bool isindentchar(char ch) { + return (ch == ' ') || (ch == '\t'); +} + +static int NextTab(int pos, int tabSize) { + return ((pos / tabSize) + 1) * tabSize; +} + +static void CreateIndentation(char *linebuf, int length, int indent, int tabSize, bool insertSpaces) { + length--; // ensure space for \0 + if (!insertSpaces) { + while ((indent >= tabSize) && (length > 0)) { + *linebuf++ = '\t'; + indent -= tabSize; + length--; + } + } + while ((indent > 0) && (length > 0)) { + *linebuf++ = ' '; + indent--; + length--; + } + *linebuf = '\0'; +} + +int Document::GetLineIndentation(int line) { + int indent = 0; + if ((line >= 0) && (line < LinesTotal())) { + int lineStart = LineStart(line); + int length = Length(); + for (int i = lineStart;i < length;i++) { + char ch = cb.CharAt(i); + if (ch == ' ') + indent++; + else if (ch == '\t') + indent = NextTab(indent, tabInChars); + else + return indent; + } + } + return indent; +} + +void Document::SetLineIndentation(int line, int indent) { + int indentOfLine = GetLineIndentation(line); + if (indent < 0) + indent = 0; + if (indent != indentOfLine) { + char linebuf[1000]; + CreateIndentation(linebuf, sizeof(linebuf), indent, tabInChars, !useTabs); + int thisLineStart = LineStart(line); + int indentPos = GetLineIndentPosition(line); + BeginUndoAction(); + DeleteChars(thisLineStart, indentPos - thisLineStart); + InsertCString(thisLineStart, linebuf); + EndUndoAction(); + } +} + +int Document::GetLineIndentPosition(int line) const { + if (line < 0) + return 0; + int pos = LineStart(line); + int length = Length(); + while ((pos < length) && isindentchar(cb.CharAt(pos))) { + pos++; + } + return pos; +} + +int Document::GetColumn(int pos) { + int column = 0; + int line = LineFromPosition(pos); + if ((line >= 0) && (line < LinesTotal())) { + for (int i = LineStart(line);i < pos;) { + char ch = cb.CharAt(i); + if (ch == '\t') { + column = NextTab(column, tabInChars); + i++; + } else if (ch == '\r') { + return column; + } else if (ch == '\n') { + return column; + } else if (i >= Length()) { + return column; + } else { + column++; + i = MovePositionOutsideChar(i + 1, 1, false); + } + } + } + return column; +} + +int Document::FindColumn(int line, int column) { + int position = LineStart(line); + int columnCurrent = 0; + if ((line >= 0) && (line < LinesTotal())) { + while ((columnCurrent < column) && (position < Length())) { + char ch = cb.CharAt(position); + if (ch == '\t') { + columnCurrent = NextTab(columnCurrent, tabInChars); + position++; + } else if (ch == '\r') { + return position; + } else if (ch == '\n') { + return position; + } else { + columnCurrent++; + position = MovePositionOutsideChar(position + 1, 1, false); + } + } + } + return position; +} + +void Document::Indent(bool forwards, int lineBottom, int lineTop) { + // Dedent - suck white space off the front of the line to dedent by equivalent of a tab + for (int line = lineBottom; line >= lineTop; line--) { + int indentOfLine = GetLineIndentation(line); + if (forwards) { + if (LineStart(line) < LineEnd(line)) { + SetLineIndentation(line, indentOfLine + IndentSize()); + } + } else { + SetLineIndentation(line, indentOfLine - IndentSize()); + } + } +} + +// Convert line endings for a piece of text to a particular mode. +// Stop at len or when a NUL is found. +// Caller must delete the returned pointer. +char *Document::TransformLineEnds(int *pLenOut, const char *s, size_t len, int eolMode) { + char *dest = new char[2 * len + 1]; + const char *sptr = s; + char *dptr = dest; + for (size_t i = 0; (i < len) && (*sptr != '\0'); i++) { + if (*sptr == '\n' || *sptr == '\r') { + if (eolMode == SC_EOL_CR) { + *dptr++ = '\r'; + } else if (eolMode == SC_EOL_LF) { + *dptr++ = '\n'; + } else { // eolMode == SC_EOL_CRLF + *dptr++ = '\r'; + *dptr++ = '\n'; + } + if ((*sptr == '\r') && (i+1 < len) && (*(sptr+1) == '\n')) { + i++; + sptr++; + } + sptr++; + } else { + *dptr++ = *sptr++; + } + } + *dptr++ = '\0'; + *pLenOut = (dptr - dest) - 1; + return dest; +} + +void Document::ConvertLineEnds(int eolModeSet) { + BeginUndoAction(); + + for (int pos = 0; pos < Length(); pos++) { + if (cb.CharAt(pos) == '\r') { + if (cb.CharAt(pos + 1) == '\n') { + // CRLF + if (eolModeSet == SC_EOL_CR) { + DeleteChars(pos + 1, 1); // Delete the LF + } else if (eolModeSet == SC_EOL_LF) { + DeleteChars(pos, 1); // Delete the CR + } else { + pos++; + } + } else { + // CR + if (eolModeSet == SC_EOL_CRLF) { + InsertString(pos + 1, "\n", 1); // Insert LF + pos++; + } else if (eolModeSet == SC_EOL_LF) { + InsertString(pos, "\n", 1); // Insert LF + DeleteChars(pos + 1, 1); // Delete CR + } + } + } else if (cb.CharAt(pos) == '\n') { + // LF + if (eolModeSet == SC_EOL_CRLF) { + InsertString(pos, "\r", 1); // Insert CR + pos++; + } else if (eolModeSet == SC_EOL_CR) { + InsertString(pos, "\r", 1); // Insert CR + DeleteChars(pos + 1, 1); // Delete LF + } + } + } + + EndUndoAction(); +} + +bool Document::IsWhiteLine(int line) const { + int currentChar = LineStart(line); + int endLine = LineEnd(line); + while (currentChar < endLine) { + if (cb.CharAt(currentChar) != ' ' && cb.CharAt(currentChar) != '\t') { + return false; + } + ++currentChar; + } + return true; +} + +int Document::ParaUp(int pos) { + int line = LineFromPosition(pos); + line--; + while (line >= 0 && IsWhiteLine(line)) { // skip empty lines + line--; + } + while (line >= 0 && !IsWhiteLine(line)) { // skip non-empty lines + line--; + } + line++; + return LineStart(line); +} + +int Document::ParaDown(int pos) { + int line = LineFromPosition(pos); + while (line < LinesTotal() && !IsWhiteLine(line)) { // skip non-empty lines + line++; + } + while (line < LinesTotal() && IsWhiteLine(line)) { // skip empty lines + line++; + } + if (line < LinesTotal()) + return LineStart(line); + else // end of a document + return LineEnd(line-1); +} + +CharClassify::cc Document::WordCharClass(unsigned char ch) { + if ((SC_CP_UTF8 == dbcsCodePage) && (ch >= 0x80)) + return CharClassify::ccWord; + return charClass.GetClass(ch); +} + +/** + * Used by commmands that want to select whole words. + * Finds the start of word at pos when delta < 0 or the end of the word when delta >= 0. + */ +int Document::ExtendWordSelect(int pos, int delta, bool onlyWordCharacters) { + CharClassify::cc ccStart = CharClassify::ccWord; + if (delta < 0) { + if (!onlyWordCharacters) + ccStart = WordCharClass(cb.CharAt(pos-1)); + while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart)) + pos--; + } else { + if (!onlyWordCharacters && pos < Length()) + ccStart = WordCharClass(cb.CharAt(pos)); + while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart)) + pos++; + } + return MovePositionOutsideChar(pos, delta); +} + +/** + * Find the start of the next word in either a forward (delta >= 0) or backwards direction + * (delta < 0). + * This is looking for a transition between character classes although there is also some + * additional movement to transit white space. + * Used by cursor movement by word commands. + */ +int Document::NextWordStart(int pos, int delta) { + if (delta < 0) { + while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == CharClassify::ccSpace)) + pos--; + if (pos > 0) { + CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos-1)); + while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart)) { + pos--; + } + } + } else { + CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos)); + while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart)) + pos++; + while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == CharClassify::ccSpace)) + pos++; + } + return pos; +} + +/** + * Find the end of the next word in either a forward (delta >= 0) or backwards direction + * (delta < 0). + * This is looking for a transition between character classes although there is also some + * additional movement to transit white space. + * Used by cursor movement by word commands. + */ +int Document::NextWordEnd(int pos, int delta) { + if (delta < 0) { + if (pos > 0) { + CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos-1)); + if (ccStart != CharClassify::ccSpace) { + while (pos > 0 && WordCharClass(cb.CharAt(pos - 1)) == ccStart) { + pos--; + } + } + while (pos > 0 && WordCharClass(cb.CharAt(pos - 1)) == CharClassify::ccSpace) { + pos--; + } + } + } else { + while (pos < Length() && WordCharClass(cb.CharAt(pos)) == CharClassify::ccSpace) { + pos++; + } + if (pos < Length()) { + CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos)); + while (pos < Length() && WordCharClass(cb.CharAt(pos)) == ccStart) { + pos++; + } + } + } + return pos; +} + +/** + * Check that the character at the given position is a word or punctuation character and that + * the previous character is of a different character class. + */ +bool Document::IsWordStartAt(int pos) { + if (pos > 0) { + CharClassify::cc ccPos = WordCharClass(CharAt(pos)); + return (ccPos == CharClassify::ccWord || ccPos == CharClassify::ccPunctuation) && + (ccPos != WordCharClass(CharAt(pos - 1))); + } + return true; +} + +/** + * Check that the character at the given position is a word or punctuation character and that + * the next character is of a different character class. + */ +bool Document::IsWordEndAt(int pos) { + if (pos < Length()) { + CharClassify::cc ccPrev = WordCharClass(CharAt(pos-1)); + return (ccPrev == CharClassify::ccWord || ccPrev == CharClassify::ccPunctuation) && + (ccPrev != WordCharClass(CharAt(pos))); + } + return true; +} + +/** + * Check that the given range is has transitions between character classes at both + * ends and where the characters on the inside are word or punctuation characters. + */ +bool Document::IsWordAt(int start, int end) { + return IsWordStartAt(start) && IsWordEndAt(end); +} + +// The comparison and case changing functions here assume ASCII +// or extended ASCII such as the normal Windows code page. + +static inline char MakeUpperCase(char ch) { + if (ch < 'a' || ch > 'z') + return ch; + else + return static_cast(ch - 'a' + 'A'); +} + +static inline char MakeLowerCase(char ch) { + if (ch < 'A' || ch > 'Z') + return ch; + else + return static_cast(ch - 'A' + 'a'); +} + +/** + * Find text in document, supporting both forward and backward + * searches (just pass minPos > maxPos to do a backward search) + * Has not been tested with backwards DBCS searches yet. + */ +long Document::FindText(int minPos, int maxPos, const char *s, + bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, + int *length) { + if (regExp) { + if (!regex) + regex = CreateRegexSearch(&charClass); + return regex->FindText(this, minPos, maxPos, s, caseSensitive, word, wordStart, flags, length); + } else { + + bool forward = minPos <= maxPos; + int increment = forward ? 1 : -1; + + // Range endpoints should not be inside DBCS characters, but just in case, move them. + int startPos = MovePositionOutsideChar(minPos, increment, false); + int endPos = MovePositionOutsideChar(maxPos, increment, false); + + // Compute actual search ranges needed + int lengthFind = *length; + if (lengthFind == -1) + lengthFind = static_cast(strlen(s)); + int endSearch = endPos; + if (startPos <= endPos) { + endSearch = endPos - lengthFind + 1; + } + //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); + char firstChar = s[0]; + if (!caseSensitive) + firstChar = static_cast(MakeUpperCase(firstChar)); + int pos = forward ? startPos : (startPos - 1); + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + char ch = CharAt(pos); + if (caseSensitive) { + if (ch == firstChar) { + bool found = true; + if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false; + for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { + ch = CharAt(pos + posMatch); + if (ch != s[posMatch]) + found = false; + } + if (found) { + if ((!word && !wordStart) || + (word && IsWordAt(pos, pos + lengthFind)) || + (wordStart && IsWordStartAt(pos))) + return pos; + } + } + } else { + if (MakeUpperCase(ch) == firstChar) { + bool found = true; + if (pos + lengthFind > Platform::Maximum(startPos, endPos)) found = false; + for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { + ch = CharAt(pos + posMatch); + if (MakeUpperCase(ch) != MakeUpperCase(s[posMatch])) + found = false; + } + if (found) { + if ((!word && !wordStart) || + (word && IsWordAt(pos, pos + lengthFind)) || + (wordStart && IsWordStartAt(pos))) + return pos; + } + } + } + pos += increment; + if (dbcsCodePage && (pos >= 0)) { + // Ensure trying to match from start of character + pos = MovePositionOutsideChar(pos, increment, false); + } + } + } + //Platform::DebugPrintf("Not found\n"); + return -1; +} + +const char *Document::SubstituteByPosition(const char *text, int *length) { + return regex->SubstituteByPosition(this, text, length); +} + +int Document::LinesTotal() const { + return cb.Lines(); +} + +void Document::ChangeCase(Range r, bool makeUpperCase) { + for (int pos = r.start; pos < r.end;) { + int len = LenChar(pos); + if (len == 1) { + char ch = CharAt(pos); + if (makeUpperCase) { + if (IsLowerCase(ch)) { + ChangeChar(pos, static_cast(MakeUpperCase(ch))); + } + } else { + if (IsUpperCase(ch)) { + ChangeChar(pos, static_cast(MakeLowerCase(ch))); + } + } + } + pos += len; + } +} + +void Document::SetDefaultCharClasses(bool includeWordClass) { + charClass.SetDefaultCharClasses(includeWordClass); +} + +void Document::SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass) { + charClass.SetCharClasses(chars, newCharClass); +} + +void Document::SetStylingBits(int bits) { + stylingBits = bits; + stylingBitsMask = (1 << stylingBits) - 1; +} + +void Document::StartStyling(int position, char mask) { + stylingMask = mask; + endStyled = position; +} + +bool Document::SetStyleFor(int length, char style) { + if (enteredStyling != 0) { + return false; + } else { + enteredStyling++; + style &= stylingMask; + int prevEndStyled = endStyled; + if (cb.SetStyleFor(endStyled, length, style, stylingMask)) { + DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER, + prevEndStyled, length); + NotifyModified(mh); + } + endStyled += length; + enteredStyling--; + return true; + } +} + +bool Document::SetStyles(int length, const char *styles) { + if (enteredStyling != 0) { + return false; + } else { + enteredStyling++; + bool didChange = false; + int startMod = 0; + int endMod = 0; + for (int iPos = 0; iPos < length; iPos++, endStyled++) { + PLATFORM_ASSERT(endStyled < Length()); + if (cb.SetStyleAt(endStyled, styles[iPos], stylingMask)) { + if (!didChange) { + startMod = endStyled; + } + didChange = true; + endMod = endStyled; + } + } + if (didChange) { + DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER, + startMod, endMod - startMod + 1); + NotifyModified(mh); + } + enteredStyling--; + return true; + } +} + +void Document::EnsureStyledTo(int pos) { + if ((enteredStyling == 0) && (pos > GetEndStyled())) { + IncrementStyleClock(); + // Ask the watchers to style, and stop as soon as one responds. + for (int i = 0; pos > GetEndStyled() && i < lenWatchers; i++) { + watchers[i].watcher->NotifyStyleNeeded(this, watchers[i].userData, pos); + } + } +} + +int Document::SetLineState(int line, int state) { + int statePrevious = static_cast(perLineData[ldState])->SetLineState(line, state); + if (state != statePrevious) { + DocModification mh(SC_MOD_CHANGELINESTATE, 0, 0, 0, 0, line); + NotifyModified(mh); + } + return statePrevious; +} + +int Document::GetLineState(int line) { + return static_cast(perLineData[ldState])->GetLineState(line); +} + +int Document::GetMaxLineState() { + return static_cast(perLineData[ldState])->GetMaxLineState(); +} + +StyledText Document::MarginStyledText(int line) { + LineAnnotation *pla = static_cast(perLineData[ldMargin]); + return StyledText(pla->Length(line), pla->Text(line), + pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); +} + +void Document::MarginSetText(int line, const char *text) { + static_cast(perLineData[ldMargin])->SetText(line, text); + DocModification mh(SC_MOD_CHANGEMARGIN, LineStart(line), 0, 0, 0, line); + NotifyModified(mh); +} + +void Document::MarginSetStyle(int line, int style) { + static_cast(perLineData[ldMargin])->SetStyle(line, style); +} + +void Document::MarginSetStyles(int line, const unsigned char *styles) { + static_cast(perLineData[ldMargin])->SetStyles(line, styles); +} + +int Document::MarginLength(int line) const { + return static_cast(perLineData[ldMargin])->Length(line); +} + +void Document::MarginClearAll() { + int maxEditorLine = LinesTotal(); + for (int l=0;l(perLineData[ldMargin])->ClearAll(); +} + +bool Document::AnnotationAny() const { + return static_cast(perLineData[ldAnnotation])->AnySet(); +} + +StyledText Document::AnnotationStyledText(int line) { + LineAnnotation *pla = static_cast(perLineData[ldAnnotation]); + return StyledText(pla->Length(line), pla->Text(line), + pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); +} + +void Document::AnnotationSetText(int line, const char *text) { + const int linesBefore = AnnotationLines(line); + static_cast(perLineData[ldAnnotation])->SetText(line, text); + const int linesAfter = AnnotationLines(line); + DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); + mh.annotationLinesAdded = linesAfter - linesBefore; + NotifyModified(mh); +} + +void Document::AnnotationSetStyle(int line, int style) { + static_cast(perLineData[ldAnnotation])->SetStyle(line, style); +} + +void Document::AnnotationSetStyles(int line, const unsigned char *styles) { + static_cast(perLineData[ldAnnotation])->SetStyles(line, styles); +} + +int Document::AnnotationLength(int line) const { + return static_cast(perLineData[ldAnnotation])->Length(line); +} + +int Document::AnnotationLines(int line) const { + return static_cast(perLineData[ldAnnotation])->Lines(line); +} + +void Document::AnnotationClearAll() { + int maxEditorLine = LinesTotal(); + for (int l=0;l(perLineData[ldAnnotation])->ClearAll(); +} + +void Document::IncrementStyleClock() { + styleClock = (styleClock + 1) % 0x100000; +} + +void Document::DecorationFillRange(int position, int value, int fillLength) { + if (decorations.FillRange(position, value, fillLength)) { + DocModification mh(SC_MOD_CHANGEINDICATOR | SC_PERFORMED_USER, + position, fillLength); + NotifyModified(mh); + } +} + +bool Document::AddWatcher(DocWatcher *watcher, void *userData) { + for (int i = 0; i < lenWatchers; i++) { + if ((watchers[i].watcher == watcher) && + (watchers[i].userData == userData)) + return false; + } + WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers + 1]; + if (!pwNew) + return false; + for (int j = 0; j < lenWatchers; j++) + pwNew[j] = watchers[j]; + pwNew[lenWatchers].watcher = watcher; + pwNew[lenWatchers].userData = userData; + delete []watchers; + watchers = pwNew; + lenWatchers++; + return true; +} + +bool Document::RemoveWatcher(DocWatcher *watcher, void *userData) { + for (int i = 0; i < lenWatchers; i++) { + if ((watchers[i].watcher == watcher) && + (watchers[i].userData == userData)) { + if (lenWatchers == 1) { + delete []watchers; + watchers = 0; + lenWatchers = 0; + } else { + WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers]; + if (!pwNew) + return false; + for (int j = 0; j < lenWatchers - 1; j++) { + pwNew[j] = (j < i) ? watchers[j] : watchers[j + 1]; + } + delete []watchers; + watchers = pwNew; + lenWatchers--; + } + return true; + } + } + return false; +} + +void Document::NotifyModifyAttempt() { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyModifyAttempt(this, watchers[i].userData); + } +} + +void Document::NotifySavePoint(bool atSavePoint) { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifySavePoint(this, watchers[i].userData, atSavePoint); + } +} + +void Document::NotifyModified(DocModification mh) { + if (mh.modificationType & SC_MOD_INSERTTEXT) { + decorations.InsertSpace(mh.position, mh.length); + } else if (mh.modificationType & SC_MOD_DELETETEXT) { + decorations.DeleteRange(mh.position, mh.length); + } + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyModified(this, mh, watchers[i].userData); + } +} + +bool Document::IsWordPartSeparator(char ch) { + return (WordCharClass(ch) == CharClassify::ccWord) && IsPunctuation(ch); +} + +int Document::WordPartLeft(int pos) { + if (pos > 0) { + --pos; + char startChar = cb.CharAt(pos); + if (IsWordPartSeparator(startChar)) { + while (pos > 0 && IsWordPartSeparator(cb.CharAt(pos))) { + --pos; + } + } + if (pos > 0) { + startChar = cb.CharAt(pos); + --pos; + if (IsLowerCase(startChar)) { + while (pos > 0 && IsLowerCase(cb.CharAt(pos))) + --pos; + if (!IsUpperCase(cb.CharAt(pos)) && !IsLowerCase(cb.CharAt(pos))) + ++pos; + } else if (IsUpperCase(startChar)) { + while (pos > 0 && IsUpperCase(cb.CharAt(pos))) + --pos; + if (!IsUpperCase(cb.CharAt(pos))) + ++pos; + } else if (IsADigit(startChar)) { + while (pos > 0 && IsADigit(cb.CharAt(pos))) + --pos; + if (!IsADigit(cb.CharAt(pos))) + ++pos; + } else if (IsPunctuation(startChar)) { + while (pos > 0 && IsPunctuation(cb.CharAt(pos))) + --pos; + if (!IsPunctuation(cb.CharAt(pos))) + ++pos; + } else if (isspacechar(startChar)) { + while (pos > 0 && isspacechar(cb.CharAt(pos))) + --pos; + if (!isspacechar(cb.CharAt(pos))) + ++pos; + } else if (!isascii(startChar)) { + while (pos > 0 && !isascii(cb.CharAt(pos))) + --pos; + if (isascii(cb.CharAt(pos))) + ++pos; + } else { + ++pos; + } + } + } + return pos; +} + +int Document::WordPartRight(int pos) { + char startChar = cb.CharAt(pos); + int length = Length(); + if (IsWordPartSeparator(startChar)) { + while (pos < length && IsWordPartSeparator(cb.CharAt(pos))) + ++pos; + startChar = cb.CharAt(pos); + } + if (!isascii(startChar)) { + while (pos < length && !isascii(cb.CharAt(pos))) + ++pos; + } else if (IsLowerCase(startChar)) { + while (pos < length && IsLowerCase(cb.CharAt(pos))) + ++pos; + } else if (IsUpperCase(startChar)) { + if (IsLowerCase(cb.CharAt(pos + 1))) { + ++pos; + while (pos < length && IsLowerCase(cb.CharAt(pos))) + ++pos; + } else { + while (pos < length && IsUpperCase(cb.CharAt(pos))) + ++pos; + } + if (IsLowerCase(cb.CharAt(pos)) && IsUpperCase(cb.CharAt(pos - 1))) + --pos; + } else if (IsADigit(startChar)) { + while (pos < length && IsADigit(cb.CharAt(pos))) + ++pos; + } else if (IsPunctuation(startChar)) { + while (pos < length && IsPunctuation(cb.CharAt(pos))) + ++pos; + } else if (isspacechar(startChar)) { + while (pos < length && isspacechar(cb.CharAt(pos))) + ++pos; + } else { + ++pos; + } + return pos; +} + +bool IsLineEndChar(char c) { + return (c == '\n' || c == '\r'); +} + +int Document::ExtendStyleRange(int pos, int delta, bool singleLine) { + int sStart = cb.StyleAt(pos); + if (delta < 0) { + while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos))) ) + pos--; + pos++; + } else { + while (pos < (Length()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos))) ) + pos++; + } + return pos; +} + +static char BraceOpposite(char ch) { + switch (ch) { + case '(': + return ')'; + case ')': + return '('; + case '[': + return ']'; + case ']': + return '['; + case '{': + return '}'; + case '}': + return '{'; + case '<': + return '>'; + case '>': + return '<'; + default: + return '\0'; + } +} + +// TODO: should be able to extend styled region to find matching brace +int Document::BraceMatch(int position, int /*maxReStyle*/) { + char chBrace = CharAt(position); + char chSeek = BraceOpposite(chBrace); + if (chSeek == '\0') + return - 1; + char styBrace = static_cast(StyleAt(position) & stylingBitsMask); + int direction = -1; + if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') + direction = 1; + int depth = 1; + position = position + direction; + while ((position >= 0) && (position < Length())) { + position = MovePositionOutsideChar(position, direction); + char chAtPos = CharAt(position); + char styAtPos = static_cast(StyleAt(position) & stylingBitsMask); + if ((position > GetEndStyled()) || (styAtPos == styBrace)) { + if (chAtPos == chBrace) + depth++; + if (chAtPos == chSeek) + depth--; + if (depth == 0) + return position; + } + position = position + direction; + } + return - 1; +} + +/** + * Implementation of RegexSearchBase for the default built-in regular expression engine + */ +class BuiltinRegex : public RegexSearchBase { +public: + BuiltinRegex(CharClassify *charClassTable) : search(charClassTable), substituted(NULL) {} + + virtual ~BuiltinRegex() { + delete substituted; + } + + virtual long FindText(Document *doc, int minPos, int maxPos, const char *s, + bool caseSensitive, bool word, bool wordStart, int flags, + int *length); + + virtual const char *SubstituteByPosition(Document* doc, const char *text, int *length); + +private: + RESearch search; + char *substituted; +}; + +// Define a way for the Regular Expression code to access the document +class DocumentIndexer : public CharacterIndexer { + Document *pdoc; + int end; +public: + DocumentIndexer(Document *pdoc_, int end_) : + pdoc(pdoc_), end(end_) { + } + + virtual ~DocumentIndexer() { + } + + virtual char CharAt(int index) { + if (index < 0 || index >= end) + return 0; + else + return pdoc->CharAt(index); + } +}; + +long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s, + bool caseSensitive, bool, bool, int flags, + int *length) { + bool posix = (flags & SCFIND_POSIX) != 0; + int increment = (minPos <= maxPos) ? 1 : -1; + + int startPos = minPos; + int endPos = maxPos; + + // Range endpoints should not be inside DBCS characters, but just in case, move them. + startPos = doc->MovePositionOutsideChar(startPos, 1, false); + endPos = doc->MovePositionOutsideChar(endPos, 1, false); + + const char *errmsg = search.Compile(s, *length, caseSensitive, posix); + if (errmsg) { + return -1; + } + // Find a variable in a property file: \$(\([A-Za-z0-9_.]+\)) + // Replace first '.' with '-' in each property file variable reference: + // Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\)) + // Replace: $(\1-\2) + int lineRangeStart = doc->LineFromPosition(startPos); + int lineRangeEnd = doc->LineFromPosition(endPos); + if ((increment == 1) && + (startPos >= doc->LineEnd(lineRangeStart)) && + (lineRangeStart < lineRangeEnd)) { + // the start position is at end of line or between line end characters. + lineRangeStart++; + startPos = doc->LineStart(lineRangeStart); + } + int pos = -1; + int lenRet = 0; + char searchEnd = s[*length - 1]; + int lineRangeBreak = lineRangeEnd + increment; + for (int line = lineRangeStart; line != lineRangeBreak; line += increment) { + int startOfLine = doc->LineStart(line); + int endOfLine = doc->LineEnd(line); + if (increment == 1) { + if (line == lineRangeStart) { + if ((startPos != startOfLine) && (s[0] == '^')) + continue; // Can't match start of line if start position after start of line + startOfLine = startPos; + } + if (line == lineRangeEnd) { + if ((endPos != endOfLine) && (searchEnd == '$')) + continue; // Can't match end of line if end position before end of line + endOfLine = endPos; + } + } else { + if (line == lineRangeEnd) { + if ((endPos != startOfLine) && (s[0] == '^')) + continue; // Can't match start of line if end position after start of line + startOfLine = endPos; + } + if (line == lineRangeStart) { + if ((startPos != endOfLine) && (searchEnd == '$')) + continue; // Can't match end of line if start position before end of line + endOfLine = startPos; + } + } + + DocumentIndexer di(doc, endOfLine); + int success = search.Execute(di, startOfLine, endOfLine); + if (success) { + pos = search.bopat[0]; + lenRet = search.eopat[0] - search.bopat[0]; + if (increment == -1) { + // Check for the last match on this line. + int repetitions = 1000; // Break out of infinite loop + while (success && (search.eopat[0] <= endOfLine) && (repetitions--)) { + success = search.Execute(di, pos+1, endOfLine); + if (success) { + if (search.eopat[0] <= minPos) { + pos = search.bopat[0]; + lenRet = search.eopat[0] - search.bopat[0]; + } else { + success = 0; + } + } + } + } + break; + } + } + *length = lenRet; + return pos; +} + +const char *BuiltinRegex::SubstituteByPosition(Document* doc, const char *text, int *length) { + delete []substituted; + substituted = 0; + DocumentIndexer di(doc, doc->Length()); + if (!search.GrabMatches(di)) + return 0; + unsigned int lenResult = 0; + for (int i = 0; i < *length; i++) { + if (text[i] == '\\') { + if (text[i + 1] >= '1' && text[i + 1] <= '9') { + unsigned int patNum = text[i + 1] - '0'; + lenResult += search.eopat[patNum] - search.bopat[patNum]; + i++; + } else { + switch (text[i + 1]) { + case 'a': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + i++; + } + lenResult++; + } + } else { + lenResult++; + } + } + substituted = new char[lenResult + 1]; + if (!substituted) + return 0; + char *o = substituted; + for (int j = 0; j < *length; j++) { + if (text[j] == '\\') { + if (text[j + 1] >= '1' && text[j + 1] <= '9') { + unsigned int patNum = text[j + 1] - '0'; + unsigned int len = search.eopat[patNum] - search.bopat[patNum]; + if (search.pat[patNum]) // Will be null if try for a match that did not occur + memcpy(o, search.pat[patNum], len); + o += len; + j++; + } else { + j++; + switch (text[j]) { + case 'a': + *o++ = '\a'; + break; + case 'b': + *o++ = '\b'; + break; + case 'f': + *o++ = '\f'; + break; + case 'n': + *o++ = '\n'; + break; + case 'r': + *o++ = '\r'; + break; + case 't': + *o++ = '\t'; + break; + case 'v': + *o++ = '\v'; + break; + default: + *o++ = '\\'; + j--; + } + } + } else { + *o++ = text[j]; + } + } + *o = '\0'; + *length = lenResult; + return substituted; +} + +#ifndef SCI_OWNREGEX + +#ifdef SCI_NAMESPACE + +RegexSearchBase *Scintilla::CreateRegexSearch(CharClassify *charClassTable) { + return new BuiltinRegex(charClassTable); +} + +#else + +RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable) { + return new BuiltinRegex(charClassTable); +} + +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Document.h b/harbour/contrib/hbide/qscintilla/Document.h new file mode 100644 index 0000000000..6ff6c2d719 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Document.h @@ -0,0 +1,384 @@ +// Scintilla source code edit control +/** @file Document.h + ** Text document that handles notifications, DBCS, styling, words and end of line. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef DOCUMENT_H +#define DOCUMENT_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + * A Position is a position within a document between two characters or at the beginning or end. + * Sometimes used as a character index where it identifies the character after the position. + */ +typedef int Position; +const Position invalidPosition = -1; + +/** + * The range class represents a range of text in a document. + * The two values are not sorted as one end may be more significant than the other + * as is the case for the selection where the end position is the position of the caret. + * If either position is invalidPosition then the range is invalid and most operations will fail. + */ +class Range { +public: + Position start; + Position end; + + Range(Position pos=0) : + start(pos), end(pos) { + }; + Range(Position start_, Position end_) : + start(start_), end(end_) { + }; + + bool Valid() const { + return (start != invalidPosition) && (end != invalidPosition); + } + + // Is the position within the range? + bool Contains(Position pos) const { + if (start < end) { + return (pos >= start && pos <= end); + } else { + return (pos <= start && pos >= end); + } + } + + // Is the character after pos within the range? + bool ContainsCharacter(Position pos) const { + if (start < end) { + return (pos >= start && pos < end); + } else { + return (pos < start && pos >= end); + } + } + + bool Contains(Range other) const { + return Contains(other.start) && Contains(other.end); + } + + bool Overlaps(Range other) const { + return + Contains(other.start) || + Contains(other.end) || + other.Contains(start) || + other.Contains(end); + } +}; + +class DocWatcher; +class DocModification; +class Document; + +/** + * Interface class for regular expression searching + */ +class RegexSearchBase { +public: + virtual ~RegexSearchBase(){} + + virtual long FindText(Document* doc, int minPos, int maxPos, const char *s, + bool caseSensitive, bool word, bool wordStart, int flags, int *length) = 0; + + ///@return String with the substitutions, must remain valid until the next call or destruction + virtual const char *SubstituteByPosition(Document* doc, const char *text, int *length) = 0; +}; + +/// Factory function for RegexSearchBase +extern RegexSearchBase* CreateRegexSearch(CharClassify *charClassTable); + +struct StyledText { + size_t length; + const char *text; + bool multipleStyles; + size_t style; + const unsigned char *styles; + StyledText( size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) : + length(length_), text(text_), multipleStyles(multipleStyles_), style(style_), styles(styles_) { + } + // Return number of bytes from start to before '\n' or end of text. + // Return 1 when start is outside text + size_t LineLength(size_t start) const { + size_t cur = start; + while ((cur < length) && (text[cur] != '\n')) + cur++; + return cur-start; + } + size_t StyleAt(size_t i) const { + return multipleStyles ? styles[i] : style; + } +}; + +/** + */ +class Document : PerLine { + +public: + /** Used to pair watcher pointer with user data. */ + class WatcherWithUserData { + public: + DocWatcher *watcher; + void *userData; + WatcherWithUserData() { + watcher = 0; + userData = 0; + } + }; + + enum charClassification { ccSpace, ccNewLine, ccWord, ccPunctuation }; +private: + int refCount; + CellBuffer cb; + CharClassify charClass; + char stylingMask; + int endStyled; + int styleClock; + int enteredModification; + int enteredStyling; + int enteredReadOnlyCount; + + WatcherWithUserData *watchers; + int lenWatchers; + + // ldSize is not real data - it is for dimensions and loops + enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; + PerLine *perLineData[ldSize]; + + bool matchesValid; + RegexSearchBase* regex; + +public: + int stylingBits; + int stylingBitsMask; + + int eolMode; + /// Can also be SC_CP_UTF8 to enable UTF-8 mode + int dbcsCodePage; + int tabInChars; + int indentInChars; + int actualIndentInChars; + bool useTabs; + bool tabIndents; + bool backspaceUnindents; + + DecorationList decorations; + + Document(); + virtual ~Document(); + + int AddRef(); + int Release(); + + virtual void InsertLine(int line); + virtual void RemoveLine(int line); + + int LineFromPosition(int pos); + int ClampPositionIntoDocument(int pos); + bool IsCrLf(int pos); + int LenChar(int pos); + bool InGoodUTF8(int pos, int &start, int &end); + int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); + + // Gateways to modifying document + void ModifiedAt(int pos); + void CheckReadOnly(); + bool DeleteChars(int pos, int len); + bool InsertString(int position, const char *s, int insertLength); + int Undo(); + int Redo(); + bool CanUndo() { return cb.CanUndo(); } + bool CanRedo() { return cb.CanRedo(); } + void DeleteUndoHistory() { cb.DeleteUndoHistory(); } + bool SetUndoCollection(bool collectUndo) { + return cb.SetUndoCollection(collectUndo); + } + bool IsCollectingUndo() { return cb.IsCollectingUndo(); } + void BeginUndoAction() { cb.BeginUndoAction(); } + void EndUndoAction() { cb.EndUndoAction(); } + void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } + void SetSavePoint(); + bool IsSavePoint() { return cb.IsSavePoint(); } + const char *BufferPointer() { return cb.BufferPointer(); } + + int GetLineIndentation(int line); + void SetLineIndentation(int line, int indent); + int GetLineIndentPosition(int line) const; + int GetColumn(int position); + int FindColumn(int line, int column); + void Indent(bool forwards, int lineBottom, int lineTop); + static char *TransformLineEnds(int *pLenOut, const char *s, size_t len, int eolMode); + void ConvertLineEnds(int eolModeSet); + void SetReadOnly(bool set) { cb.SetReadOnly(set); } + bool IsReadOnly() { return cb.IsReadOnly(); } + + bool InsertChar(int pos, char ch); + bool InsertCString(int position, const char *s); + void ChangeChar(int pos, char ch); + void DelChar(int pos); + void DelCharBack(int pos); + + char CharAt(int position) { return cb.CharAt(position); } + void GetCharRange(char *buffer, int position, int lengthRetrieve) { + cb.GetCharRange(buffer, position, lengthRetrieve); + } + char StyleAt(int position) { return cb.StyleAt(position); } + int GetMark(int line); + int AddMark(int line, int markerNum); + void AddMarkSet(int line, int valueSet); + void DeleteMark(int line, int markerNum); + void DeleteMarkFromHandle(int markerHandle); + void DeleteAllMarks(int markerNum); + int LineFromHandle(int markerHandle); + int LineStart(int line) const; + int LineEnd(int line) const; + int LineEndPosition(int position); + int VCHomePosition(int position); + + int SetLevel(int line, int level); + int GetLevel(int line); + void ClearLevels(); + int GetLastChild(int lineParent, int level=-1); + int GetFoldParent(int line); + + void Indent(bool forwards); + int ExtendWordSelect(int pos, int delta, bool onlyWordCharacters=false); + int NextWordStart(int pos, int delta); + int NextWordEnd(int pos, int delta); + int Length() const { return cb.Length(); } + void Allocate(int newSize) { cb.Allocate(newSize); } + long FindText(int minPos, int maxPos, const char *s, + bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, int *length); + long FindText(int iMessage, unsigned long wParam, long lParam); + const char *SubstituteByPosition(const char *text, int *length); + int LinesTotal() const; + + void ChangeCase(Range r, bool makeUpperCase); + + void SetDefaultCharClasses(bool includeWordClass); + void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); + void SetStylingBits(int bits); + void StartStyling(int position, char mask); + bool SetStyleFor(int length, char style); + bool SetStyles(int length, const char *styles); + int GetEndStyled() { return endStyled; } + void EnsureStyledTo(int pos); + int GetStyleClock() { return styleClock; } + void IncrementStyleClock(); + void DecorationFillRange(int position, int value, int fillLength); + + int SetLineState(int line, int state); + int GetLineState(int line); + int GetMaxLineState(); + + StyledText MarginStyledText(int line); + void MarginSetStyle(int line, int style); + void MarginSetStyles(int line, const unsigned char *styles); + void MarginSetText(int line, const char *text); + int MarginLength(int line) const; + void MarginClearAll(); + + bool AnnotationAny() const; + StyledText AnnotationStyledText(int line); + void AnnotationSetText(int line, const char *text); + void AnnotationSetStyle(int line, int style); + void AnnotationSetStyles(int line, const unsigned char *styles); + int AnnotationLength(int line) const; + int AnnotationLines(int line) const; + void AnnotationClearAll(); + + bool AddWatcher(DocWatcher *watcher, void *userData); + bool RemoveWatcher(DocWatcher *watcher, void *userData); + const WatcherWithUserData *GetWatchers() const { return watchers; } + int GetLenWatchers() const { return lenWatchers; } + + bool IsWordPartSeparator(char ch); + int WordPartLeft(int pos); + int WordPartRight(int pos); + int ExtendStyleRange(int pos, int delta, bool singleLine = false); + bool IsWhiteLine(int line) const; + int ParaUp(int pos); + int ParaDown(int pos); + int IndentSize() { return actualIndentInChars; } + int BraceMatch(int position, int maxReStyle); + +private: + CharClassify::cc WordCharClass(unsigned char ch); + bool IsWordStartAt(int pos); + bool IsWordEndAt(int pos); + bool IsWordAt(int start, int end); + + void NotifyModifyAttempt(); + void NotifySavePoint(bool atSavePoint); + void NotifyModified(DocModification mh); +}; + +/** + * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the + * scope of the change. + * If the DocWatcher is a document view then this can be used to optimise screen updating. + */ +class DocModification { +public: + int modificationType; + int position; + int length; + int linesAdded; /**< Negative if lines deleted. */ + const char *text; /**< Only valid for changes to text, not for changes to style. */ + int line; + int foldLevelNow; + int foldLevelPrev; + int annotationLinesAdded; + int token; + + DocModification(int modificationType_, int position_=0, int length_=0, + int linesAdded_=0, const char *text_=0, int line_=0) : + modificationType(modificationType_), + position(position_), + length(length_), + linesAdded(linesAdded_), + text(text_), + line(line_), + foldLevelNow(0), + foldLevelPrev(0), + annotationLinesAdded(0), + token(0) {} + + DocModification(int modificationType_, const Action &act, int linesAdded_=0) : + modificationType(modificationType_), + position(act.position), + length(act.lenData), + linesAdded(linesAdded_), + text(act.data), + line(0), + foldLevelNow(0), + foldLevelPrev(0), + annotationLinesAdded(0), + token(0) {} +}; + +/** + * A class that wants to receive notifications from a Document must be derived from DocWatcher + * and implement the notification methods. It can then be added to the watcher list with AddWatcher. + */ +class DocWatcher { +public: + virtual ~DocWatcher() {} + + virtual void NotifyModifyAttempt(Document *doc, void *userData) = 0; + virtual void NotifySavePoint(Document *doc, void *userData, bool atSavePoint) = 0; + virtual void NotifyModified(Document *doc, DocModification mh, void *userData) = 0; + virtual void NotifyDeleted(Document *doc, void *userData) = 0; + virtual void NotifyStyleNeeded(Document *doc, void *userData, int endPos) = 0; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/DocumentAccessor.cpp b/harbour/contrib/hbide/qscintilla/DocumentAccessor.cpp new file mode 100644 index 0000000000..a25979dc2c --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/DocumentAccessor.cpp @@ -0,0 +1,199 @@ +// Scintilla source code edit control +/** @file DocumentAccessor.cxx + ** Rapid easy access to contents of a Scintilla. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "DocumentAccessor.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "CellBuffer.h" +#include "Scintilla.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "Document.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +DocumentAccessor::~DocumentAccessor() { +} + +bool DocumentAccessor::InternalIsLeadByte(char ch) { + if (SC_CP_UTF8 == codePage) + // For lexing, all characters >= 0x80 are treated the + // same so none is considered a lead byte. + return false; + else + return Platform::IsDBCSLeadByte(codePage, ch); +} + +void DocumentAccessor::Fill(int position) { + if (lenDoc == -1) + lenDoc = pdoc->Length(); + startPos = position - slopSize; + if (startPos + bufferSize > lenDoc) + startPos = lenDoc - bufferSize; + if (startPos < 0) + startPos = 0; + endPos = startPos + bufferSize; + if (endPos > lenDoc) + endPos = lenDoc; + + pdoc->GetCharRange(buf, startPos, endPos-startPos); + buf[endPos-startPos] = '\0'; +} + +bool DocumentAccessor::Match(int pos, const char *s) { + for (int i=0; *s; i++) { + if (*s != SafeGetCharAt(pos+i)) + return false; + s++; + } + return true; +} + +char DocumentAccessor::StyleAt(int position) { + // Mask off all bits which aren't in the 'mask'. + return static_cast(pdoc->StyleAt(position) & mask); +} + +int DocumentAccessor::GetLine(int position) { + return pdoc->LineFromPosition(position); +} + +int DocumentAccessor::LineStart(int line) { + return pdoc->LineStart(line); +} + +int DocumentAccessor::LevelAt(int line) { + return pdoc->GetLevel(line); +} + +int DocumentAccessor::Length() { + if (lenDoc == -1) + lenDoc = pdoc->Length(); + return lenDoc; +} + +int DocumentAccessor::GetLineState(int line) { + return pdoc->GetLineState(line); +} + +int DocumentAccessor::SetLineState(int line, int state) { + return pdoc->SetLineState(line, state); +} + +void DocumentAccessor::StartAt(unsigned int start, char chMask) { + // Store the mask specified for use with StyleAt. + mask = chMask; + pdoc->StartStyling(start, chMask); + startPosStyling = start; +} + +void DocumentAccessor::StartSegment(unsigned int pos) { + startSeg = pos; +} + +void DocumentAccessor::ColourTo(unsigned int pos, int chAttr) { + // Only perform styling if non empty range + if (pos != startSeg - 1) { + PLATFORM_ASSERT(pos >= startSeg); + if (pos < startSeg) { + return; + } + + if (validLen + (pos - startSeg + 1) >= bufferSize) + Flush(); + if (validLen + (pos - startSeg + 1) >= bufferSize) { + // Too big for buffer so send directly + pdoc->SetStyleFor(pos - startSeg + 1, static_cast(chAttr)); + } else { + if (chAttr != chWhile) + chFlags = 0; + chAttr |= chFlags; + for (unsigned int i = startSeg; i <= pos; i++) { + PLATFORM_ASSERT((startPosStyling + validLen) < Length()); + styleBuf[validLen++] = static_cast(chAttr); + } + } + } + startSeg = pos+1; +} + +void DocumentAccessor::SetLevel(int line, int level) { + pdoc->SetLevel(line, level); +} + +void DocumentAccessor::Flush() { + startPos = extremePosition; + lenDoc = -1; + if (validLen > 0) { + pdoc->SetStyles(validLen, styleBuf); + startPosStyling += validLen; + validLen = 0; + } +} + +int DocumentAccessor::IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader) { + int end = Length(); + int spaceFlags = 0; + + // Determines the indentation level of the current line and also checks for consistent + // indentation compared to the previous line. + // Indentation is judged consistent when the indentation whitespace of each line lines + // the same or the indentation of one line is a prefix of the other. + + int pos = LineStart(line); + char ch = (*this)[pos]; + int indent = 0; + bool inPrevPrefix = line > 0; + int posPrev = inPrevPrefix ? LineStart(line-1) : 0; + while ((ch == ' ' || ch == '\t') && (pos < end)) { + if (inPrevPrefix) { + char chPrev = (*this)[posPrev++]; + if (chPrev == ' ' || chPrev == '\t') { + if (chPrev != ch) + spaceFlags |= wsInconsistent; + } else { + inPrevPrefix = false; + } + } + if (ch == ' ') { + spaceFlags |= wsSpace; + indent++; + } else { // Tab + spaceFlags |= wsTab; + if (spaceFlags & wsSpace) + spaceFlags |= wsSpaceTab; + indent = (indent / 8 + 1) * 8; + } + ch = (*this)[++pos]; + } + + *flags = spaceFlags; + indent += SC_FOLDLEVELBASE; + // if completely empty line or the start of a comment... + if ((ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') || + (pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos)) ) + return indent | SC_FOLDLEVELWHITEFLAG; + else + return indent; +} + +void DocumentAccessor::IndicatorFill(int start, int end, int indicator, int value) { + pdoc->decorations.SetCurrentIndicator(indicator); + pdoc->DecorationFillRange(start, value, end - start); +} diff --git a/harbour/contrib/hbide/qscintilla/DocumentAccessor.h b/harbour/contrib/hbide/qscintilla/DocumentAccessor.h new file mode 100644 index 0000000000..a3a939d0d3 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/DocumentAccessor.h @@ -0,0 +1,76 @@ +// Scintilla source code edit control +/** @file DocumentAccessor.h + ** Implementation of BufferAccess and StylingAccess on a Scintilla + ** rapid easy access to contents of a Scintilla. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class Document; + +/** + */ +class DocumentAccessor : public Accessor { + // Private so DocumentAccessor objects can not be copied + DocumentAccessor(const DocumentAccessor &source) : Accessor(), props(source.props) {} + DocumentAccessor &operator=(const DocumentAccessor &) { return *this; } + +protected: + Document *pdoc; + PropSet &props; + WindowID id; + int lenDoc; + + char styleBuf[bufferSize]; + int validLen; + char chFlags; + char chWhile; + unsigned int startSeg; + int startPosStyling; + int mask; + + bool InternalIsLeadByte(char ch); + void Fill(int position); + +public: + DocumentAccessor(Document *pdoc_, PropSet &props_, WindowID id_=0) : + Accessor(), pdoc(pdoc_), props(props_), id(id_), + lenDoc(-1), validLen(0), chFlags(0), chWhile(0), + startSeg(0), startPosStyling(0), + mask(127) { // Initialize the mask to be big enough for any lexer. + } + ~DocumentAccessor(); + bool Match(int pos, const char *s); + char StyleAt(int position); + int GetLine(int position); + int LineStart(int line); + int LevelAt(int line); + int Length(); + void Flush(); + int GetLineState(int line); + int SetLineState(int line, int state); + int GetPropertyInt(const char *key, int defaultValue=0) { + return props.GetInt(key, defaultValue); + } + char *GetProperties() { + return props.ToString(); + } + WindowID GetWindow() { return id; } + + void StartAt(unsigned int start, char chMask=31); + void SetFlags(char chFlags_, char chWhile_) {chFlags = chFlags_; chWhile = chWhile_; }; + unsigned int GetStartSegment() { return startSeg; } + void StartSegment(unsigned int pos); + void ColourTo(unsigned int pos, int chAttr); + void SetLevel(int line, int level); + int IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); + void IndicatorFill(int start, int end, int indicator, int value); +}; + +#ifdef SCI_NAMESPACE +} +#endif diff --git a/harbour/contrib/hbide/qscintilla/Editor.cpp b/harbour/contrib/hbide/qscintilla/Editor.cpp new file mode 100644 index 0000000000..6216681147 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Editor.cpp @@ -0,0 +1,7990 @@ +// Scintilla source code edit control +/** @file Editor.cxx + ** Main code for the edit control. + **/ +// Copyright 1998-2004 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#ifndef PLAT_QT +#define INCLUDE_DEPRECATED_FEATURES +#endif +#include "Scintilla.h" + +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "Document.h" +#include "PositionCache.h" +#include "Editor.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +/* + return whether this modification represents an operation that + may reasonably be deferred (not done now OR [possibly] at all) +*/ +static bool CanDeferToLastStep(const DocModification& mh) { + if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) + return true; // CAN skip + if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO))) + return false; // MUST do + if (mh.modificationType & SC_MULTISTEPUNDOREDO) + return true; // CAN skip + return false; // PRESUMABLY must do +} + +static bool CanEliminate(const DocModification& mh) { + return + (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0; +} + +/* + return whether this modification represents the FINAL step + in a [possibly lengthy] multi-step Undo/Redo sequence +*/ +static bool IsLastStep(const DocModification& mh) { + return + (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0 + && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0 + && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0 + && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0; +} + +Caret::Caret() : + active(false), on(false), period(500) {} + +Timer::Timer() : + ticking(false), ticksToWait(0), tickerID(0) {} + +Idler::Idler() : + state(false), idlerID(0) {} + +static inline bool IsControlCharacter(int ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +Editor::Editor() { + ctrlID = 0; + + stylesValid = false; + + printMagnification = 0; + printColourMode = SC_PRINT_NORMAL; + printWrapState = eWrapWord; + cursorMode = SC_CURSORNORMAL; + controlCharSymbol = 0; /* Draw the control characters */ + + hasFocus = false; + hideSelection = false; + inOverstrike = false; + errorStatus = 0; + mouseDownCaptures = true; + + bufferedDraw = true; + twoPhaseDraw = true; + + lastClickTime = 0; + dwellDelay = SC_TIME_FOREVER; + ticksToDwell = SC_TIME_FOREVER; + dwelling = false; + ptMouseLast.x = 0; + ptMouseLast.y = 0; + inDragDrop = ddNone; + dropWentOutside = false; + posDrag = invalidPosition; + posDrop = invalidPosition; + selectionType = selChar; + + lastXChosen = 0; + lineAnchor = 0; + originalAnchorPos = 0; + + selType = selStream; + moveExtendsSelection = false; + xStartSelect = 0; + xEndSelect = 0; + primarySelection = true; + + caretXPolicy = CARET_SLOP | CARET_EVEN; + caretXSlop = 50; + + caretYPolicy = CARET_EVEN; + caretYSlop = 0; + + searchAnchor = 0; + + xOffset = 0; + xCaretMargin = 50; + horizontalScrollBarVisible = true; + scrollWidth = 2000; + trackLineWidth = false; + lineWidthMaxSeen = 0; + verticalScrollBarVisible = true; + endAtLastLine = true; + caretSticky = false; + + pixmapLine = Surface::Allocate(); + pixmapSelMargin = Surface::Allocate(); + pixmapSelPattern = Surface::Allocate(); + pixmapIndentGuide = Surface::Allocate(); + pixmapIndentGuideHighlight = Surface::Allocate(); + + currentPos = 0; + anchor = 0; + + targetStart = 0; + targetEnd = 0; + searchFlags = 0; + + topLine = 0; + posTopLine = 0; + + lengthForEncode = -1; + + needUpdateUI = true; + braces[0] = invalidPosition; + braces[1] = invalidPosition; + bracesMatchStyle = STYLE_BRACEBAD; + highlightGuideColumn = 0; + + theEdge = 0; + + paintState = notPainting; + + modEventMask = SC_MODEVENTMASKALL; + + pdoc = new Document(); + pdoc->AddRef(); + pdoc->AddWatcher(this, 0); + + recordingMacro = false; + foldFlags = 0; + + wrapState = eWrapNone; + wrapWidth = LineLayout::wrapWidthInfinite; + wrapStart = wrapLineLarge; + wrapEnd = wrapLineLarge; + wrapVisualFlags = 0; + wrapVisualFlagsLocation = 0; + wrapVisualStartIndent = 0; + actualWrapVisualStartIndent = 0; + + convertPastes = true; + + hsStart = -1; + hsEnd = -1; + + llc.SetLevel(LineLayoutCache::llcCaret); + posCache.SetSize(0x400); +} + +Editor::~Editor() { + pdoc->RemoveWatcher(this, 0); + pdoc->Release(); + pdoc = 0; + DropGraphics(); + delete pixmapLine; + delete pixmapSelMargin; + delete pixmapSelPattern; + delete pixmapIndentGuide; + delete pixmapIndentGuideHighlight; +} + +void Editor::Finalise() { + SetIdle(false); + CancelModes(); +} + +void Editor::DropGraphics() { + pixmapLine->Release(); + pixmapSelMargin->Release(); + pixmapSelPattern->Release(); + pixmapIndentGuide->Release(); + pixmapIndentGuideHighlight->Release(); +} + +void Editor::InvalidateStyleData() { + stylesValid = false; + DropGraphics(); + palette.Release(); + llc.Invalidate(LineLayout::llInvalid); + posCache.Clear(); + if (selType == selRectangle) { + xStartSelect = XFromPosition(anchor); + xEndSelect = XFromPosition(currentPos); + } +} + +void Editor::InvalidateStyleRedraw() { + NeedWrapping(); + InvalidateStyleData(); + Redraw(); +} + +void Editor::RefreshColourPalette(Palette &pal, bool want) { + vs.RefreshColourPalette(pal, want); +} + +void Editor::RefreshStyleData() { + if (!stylesValid) { + stylesValid = true; + AutoSurface surface(this); + if (surface) { + vs.Refresh(*surface); + RefreshColourPalette(palette, true); + palette.Allocate(wMain); + RefreshColourPalette(palette, false); + } + SetScrollBars(); + } +} + +PRectangle Editor::GetClientRectangle() { + return wMain.GetClientPosition(); +} + +PRectangle Editor::GetTextRectangle() { + PRectangle rc = GetClientRectangle(); + rc.left += vs.fixedColumnWidth; + rc.right -= vs.rightMarginWidth; + return rc; +} + +int Editor::LinesOnScreen() { + PRectangle rcClient = GetClientRectangle(); + int htClient = rcClient.bottom - rcClient.top; + //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1); + return htClient / vs.lineHeight; +} + +int Editor::LinesToScroll() { + int retVal = LinesOnScreen() - 1; + if (retVal < 1) + return 1; + else + return retVal; +} + +int Editor::MaxScrollPos() { + //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n", + //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1); + int retVal = cs.LinesDisplayed(); + if (endAtLastLine) { + retVal -= LinesOnScreen(); + } else { + retVal--; + } + if (retVal < 0) { + return 0; + } else { + return retVal; + } +} + +const char *ControlCharacterString(unsigned char ch) { + const char *reps[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" + }; + if (ch < (sizeof(reps) / sizeof(reps[0]))) { + return reps[ch]; + } else { + return "BAD"; + } +} + +/** + * Convenience class to ensure LineLayout objects are always disposed. + */ +class AutoLineLayout { + LineLayoutCache &llc; + LineLayout *ll; + AutoLineLayout &operator=(const AutoLineLayout &) { return * this; } +public: + AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {} + ~AutoLineLayout() { + llc.Dispose(ll); + ll = 0; + } + LineLayout *operator->() const { + return ll; + } + operator LineLayout *() const { + return ll; + } + void Set(LineLayout *ll_) { + llc.Dispose(ll); + ll = ll_; + } +}; + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + * Allows to iterate through the lines of a selection. + * Althought it can be called for a stream selection, in most cases + * it is inefficient and it should be used only for + * a rectangular or a line selection. + */ +class SelectionLineIterator { +private: + Editor *ed; + int line; ///< Current line within the iteration. + bool forward; ///< True if iterating by increasing line number, false otherwise. + int selStart, selEnd; ///< Positions of the start and end of the selection relative to the start of the document. + int minX, maxX; ///< Left and right of selection rectangle. + +public: + int lineStart, lineEnd; ///< Line numbers, first and last lines of the selection. + int startPos, endPos; ///< Positions of the beginning and end of the selection on the current line. + + void Reset() { + if (forward) { + line = lineStart; + } else { + line = lineEnd; + } + } + + SelectionLineIterator(Editor *ed_, bool forward_ = true) : line(0), startPos(0), endPos(0) { + ed = ed_; + forward = forward_; + selStart = ed->SelectionStart(); + selEnd = ed->SelectionEnd(); + lineStart = ed->pdoc->LineFromPosition(selStart); + lineEnd = ed->pdoc->LineFromPosition(selEnd); + // Left of rectangle + minX = Platform::Minimum(ed->xStartSelect, ed->xEndSelect); + // Right of rectangle + maxX = Platform::Maximum(ed->xStartSelect, ed->xEndSelect); + Reset(); + } + ~SelectionLineIterator() {} + + void SetAt(int line) { + if (line < lineStart || line > lineEnd) { + startPos = endPos = INVALID_POSITION; + } else { + if (ed->selType == ed->selRectangle) { + // Measure line and return character closest to minX + startPos = ed->PositionFromLineX(line, minX); + // Measure line and return character closest to maxX + endPos = ed->PositionFromLineX(line, maxX); + } else if (ed->selType == ed->selLines) { + startPos = ed->pdoc->LineStart(line); + endPos = ed->pdoc->LineStart(line + 1); + } else { // Stream selection, here only for completion + if (line == lineStart) { + startPos = selStart; + } else { + startPos = ed->pdoc->LineStart(line); + } + if (line == lineEnd) { + endPos = selEnd; + } else { + endPos = ed->pdoc->LineStart(line + 1); + } + } + } + } + bool Iterate() { + SetAt(line); + if (forward) { + line++; + } else { + line--; + } + return startPos != INVALID_POSITION; + } +}; + +#ifdef SCI_NAMESPACE +} +#endif + +Point Editor::LocationFromPosition(int pos) { + Point pt; + RefreshStyleData(); + if (pos == INVALID_POSITION) + return pt; + int line = pdoc->LineFromPosition(pos); + int lineVisible = cs.DisplayFromDoc(line); + //Platform::DebugPrintf("line=%d\n", line); + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(line)); + if (surface && ll) { + // -1 because of adding in for visible lines in following loop. + pt.y = (lineVisible - topLine - 1) * vs.lineHeight; + pt.x = 0; + unsigned int posLineStart = pdoc->LineStart(line); + LayoutLine(line, surface, vs, ll, wrapWidth); + int posInLine = pos - posLineStart; + // In case of very long line put x at arbitrary large position + if (posInLine > ll->maxLineLength) { + pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)]; + } + + for (int subLine = 0; subLine < ll->lines; subLine++) { + if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { + pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)]; + if (actualWrapVisualStartIndent != 0) { + int lineStart = ll->LineStart(subLine); + if (lineStart != 0) // Wrapped + pt.x += actualWrapVisualStartIndent * vs.aveCharWidth; + } + } + if (posInLine >= ll->LineStart(subLine)) { + pt.y += vs.lineHeight; + } + } + pt.x += vs.fixedColumnWidth - xOffset; + } + return pt; +} + +int Editor::XFromPosition(int pos) { + Point pt = LocationFromPosition(pos); + return pt.x - vs.fixedColumnWidth + xOffset; +} + +int Editor::LineFromLocation(Point pt) { + return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); +} + +void Editor::SetTopLine(int topLineNew) { + topLine = topLineNew; + posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine)); +} + +int Editor::PositionFromLocation(Point pt) { + RefreshStyleData(); + pt.x = pt.x - vs.fixedColumnWidth + xOffset; + int visibleLine = pt.y / vs.lineHeight + topLine; + if (pt.y < 0) { // Division rounds towards 0 + visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine; + } + if (visibleLine < 0) + visibleLine = 0; + int lineDoc = cs.DocFromDisplay(visibleLine); + if (lineDoc >= pdoc->LinesTotal()) + return pdoc->Length(); + unsigned int posLineStart = pdoc->LineStart(lineDoc); + int retVal = posLineStart; + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); + if (surface && ll) { + LayoutLine(lineDoc, surface, vs, ll, wrapWidth); + int lineStartSet = cs.DisplayFromDoc(lineDoc); + int subLine = visibleLine - lineStartSet; + if (subLine < ll->lines) { + int lineStart = ll->LineStart(subLine); + int lineEnd = ll->LineLastVisible(subLine); + int subLineStart = ll->positions[lineStart]; + + if (actualWrapVisualStartIndent != 0) { + if (lineStart != 0) // Wrapped + pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth; + } + int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd); + while (i < lineEnd) { + if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { + return pdoc->MovePositionOutsideChar(i + posLineStart, 1); + } + i++; + } + return lineEnd + posLineStart; + } + retVal = ll->numCharsInLine + posLineStart; + } + return retVal; +} + +// Like PositionFromLocation but INVALID_POSITION returned when not near any text. +int Editor::PositionFromLocationClose(Point pt) { + RefreshStyleData(); + PRectangle rcClient = GetTextRectangle(); + if (!rcClient.Contains(pt)) + return INVALID_POSITION; + if (pt.x < vs.fixedColumnWidth) + return INVALID_POSITION; + if (pt.y < 0) + return INVALID_POSITION; + pt.x = pt.x - vs.fixedColumnWidth + xOffset; + int visibleLine = pt.y / vs.lineHeight + topLine; + if (pt.y < 0) { // Division rounds towards 0 + visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine; + } + int lineDoc = cs.DocFromDisplay(visibleLine); + if (lineDoc < 0) + return INVALID_POSITION; + if (lineDoc >= pdoc->LinesTotal()) + return INVALID_POSITION; + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); + if (surface && ll) { + LayoutLine(lineDoc, surface, vs, ll, wrapWidth); + unsigned int posLineStart = pdoc->LineStart(lineDoc); + int lineStartSet = cs.DisplayFromDoc(lineDoc); + int subLine = visibleLine - lineStartSet; + if (subLine < ll->lines) { + int lineStart = ll->LineStart(subLine); + int lineEnd = ll->LineLastVisible(subLine); + int subLineStart = ll->positions[lineStart]; + + if (actualWrapVisualStartIndent != 0) { + if (lineStart != 0) // Wrapped + pt.x -= actualWrapVisualStartIndent * vs.aveCharWidth; + } + int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd); + while (i < lineEnd) { + if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { + return pdoc->MovePositionOutsideChar(i + posLineStart, 1); + } + i++; + } + if (pt.x < (ll->positions[lineEnd] - subLineStart)) { + return pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1); + } + } + } + + return INVALID_POSITION; +} + +/** + * Find the document position corresponding to an x coordinate on a particular document line. + * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. + */ +int Editor::PositionFromLineX(int lineDoc, int x) { + RefreshStyleData(); + if (lineDoc >= pdoc->LinesTotal()) + return pdoc->Length(); + //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); + int retVal = 0; + if (surface && ll) { + unsigned int posLineStart = pdoc->LineStart(lineDoc); + LayoutLine(lineDoc, surface, vs, ll, wrapWidth); + retVal = ll->numCharsInLine + posLineStart; + int subLine = 0; + int lineStart = ll->LineStart(subLine); + int lineEnd = ll->LineLastVisible(subLine); + int subLineStart = ll->positions[lineStart]; + + if (actualWrapVisualStartIndent != 0) { + if (lineStart != 0) // Wrapped + x -= actualWrapVisualStartIndent * vs.aveCharWidth; + } + int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd); + while (i < lineEnd) { + if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { + retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1); + break; + } + i++; + } + } + return retVal; +} + +/** + * If painting then abandon the painting because a wider redraw is needed. + * @return true if calling code should stop drawing. + */ +bool Editor::AbandonPaint() { + if ((paintState == painting) && !paintingAllText) { + paintState = paintAbandoned; + } + return paintState == paintAbandoned; +} + +void Editor::RedrawRect(PRectangle rc) { + //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom); + + // Clip the redraw rectangle into the client area + PRectangle rcClient = GetClientRectangle(); + if (rc.top < rcClient.top) + rc.top = rcClient.top; + if (rc.bottom > rcClient.bottom) + rc.bottom = rcClient.bottom; + if (rc.left < rcClient.left) + rc.left = rcClient.left; + if (rc.right > rcClient.right) + rc.right = rcClient.right; + + if ((rc.bottom > rc.top) && (rc.right > rc.left)) { + wMain.InvalidateRectangle(rc); + } +} + +void Editor::Redraw() { + //Platform::DebugPrintf("Redraw all\n"); + PRectangle rcClient = GetClientRectangle(); + wMain.InvalidateRectangle(rcClient); + //wMain.InvalidateAll(); +} + +void Editor::RedrawSelMargin(int line) { + if (!AbandonPaint()) { + if (vs.maskInLine) { + Redraw(); + } else { + PRectangle rcSelMargin = GetClientRectangle(); + rcSelMargin.right = vs.fixedColumnWidth; + if (line != -1) { + int position = pdoc->LineStart(line); + PRectangle rcLine = RectangleFromRange(position, position); + rcSelMargin.top = rcLine.top; + rcSelMargin.bottom = rcLine.bottom; + } + wMain.InvalidateRectangle(rcSelMargin); + } + } +} + +PRectangle Editor::RectangleFromRange(int start, int end) { + int minPos = start; + if (minPos > end) + minPos = end; + int maxPos = start; + if (maxPos < end) + maxPos = end; + int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos)); + int lineDocMax = pdoc->LineFromPosition(maxPos); + int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1; + PRectangle rcClient = GetTextRectangle(); + PRectangle rc; + rc.left = vs.fixedColumnWidth; + rc.top = (minLine - topLine) * vs.lineHeight; + if (rc.top < 0) + rc.top = 0; + rc.right = rcClient.right; + rc.bottom = (maxLine - topLine + 1) * vs.lineHeight; + // Ensure PRectangle is within 16 bit space + rc.top = Platform::Clamp(rc.top, -32000, 32000); + rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000); + + return rc; +} + +void Editor::InvalidateRange(int start, int end) { + RedrawRect(RectangleFromRange(start, end)); +} + +int Editor::CurrentPosition() { + return currentPos; +} + +bool Editor::SelectionEmpty() { + return anchor == currentPos; +} + +int Editor::SelectionStart() { + return Platform::Minimum(currentPos, anchor); +} + +int Editor::SelectionEnd() { + return Platform::Maximum(currentPos, anchor); +} + +void Editor::SetRectangularRange() { + if (selType == selRectangle) { + xStartSelect = XFromPosition(anchor); + xEndSelect = XFromPosition(currentPos); + } +} + +void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) { + if (anchor != anchor_ || selType == selRectangle) { + invalidateWholeSelection = true; + } + int firstAffected = currentPos; + if (invalidateWholeSelection) { + if (firstAffected > anchor) + firstAffected = anchor; + if (firstAffected > anchor_) + firstAffected = anchor_; + } + if (firstAffected > currentPos_) + firstAffected = currentPos_; + int lastAffected = currentPos; + if (invalidateWholeSelection) { + if (lastAffected < anchor) + lastAffected = anchor; + if (lastAffected < anchor_) + lastAffected = anchor_; + } + if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted + lastAffected = (currentPos_ + 1); + needUpdateUI = true; + InvalidateRange(firstAffected, lastAffected); +} + +void Editor::SetSelection(int currentPos_, int anchor_) { + currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); + anchor_ = pdoc->ClampPositionIntoDocument(anchor_); + if ((currentPos != currentPos_) || (anchor != anchor_)) { + InvalidateSelection(currentPos_, anchor_, true); + currentPos = currentPos_; + anchor = anchor_; + } + SetRectangularRange(); + ClaimSelection(); +} + +void Editor::SetSelection(int currentPos_) { + currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); + if (currentPos != currentPos_) { + InvalidateSelection(currentPos_, anchor, false); + currentPos = currentPos_; + } + SetRectangularRange(); + ClaimSelection(); +} + +void Editor::SetEmptySelection(int currentPos_) { + selType = selStream; + moveExtendsSelection = false; + SetSelection(currentPos_, currentPos_); +} + +bool Editor::RangeContainsProtected(int start, int end) const { + if (vs.ProtectionActive()) { + if (start > end) { + int t = start; + start = end; + end = t; + } + int mask = pdoc->stylingBitsMask; + for (int pos = start; pos < end; pos++) { + if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) + return true; + } + } + return false; +} + +bool Editor::SelectionContainsProtected() { + // DONE, but untested...: make support rectangular selection + bool scp = false; + if (selType == selStream) { + scp = RangeContainsProtected(anchor, currentPos); + } else { + SelectionLineIterator lineIterator(this); + while (lineIterator.Iterate()) { + if (RangeContainsProtected(lineIterator.startPos, lineIterator.endPos)) { + scp = true; + break; + } + } + } + return scp; +} + +/** + * Asks document to find a good position and then moves out of any invisible positions. + */ +int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { + pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd); + if (vs.ProtectionActive()) { + int mask = pdoc->stylingBitsMask; + if (moveDir > 0) { + if ((pos > 0) && vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()) { + while ((pos < pdoc->Length()) && + (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())) + pos++; + } + } else if (moveDir < 0) { + if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) { + while ((pos > 0) && + (vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected())) + pos--; + } + } + } + return pos; +} + +int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) { + int delta = newPos - currentPos; + newPos = pdoc->ClampPositionIntoDocument(newPos); + newPos = MovePositionOutsideChar(newPos, delta); + if (sel != noSel) { + selType = sel; + } + if (sel != noSel || moveExtendsSelection) { + SetSelection(newPos); + } else { + SetEmptySelection(newPos); + } + ShowCaretAtCurrentPosition(); + if (ensureVisible) { + EnsureCaretVisible(); + } + NotifyMove(newPos); + return 0; +} + +int Editor::MovePositionSoVisible(int pos, int moveDir) { + pos = pdoc->ClampPositionIntoDocument(pos); + pos = MovePositionOutsideChar(pos, moveDir); + int lineDoc = pdoc->LineFromPosition(pos); + if (cs.GetVisible(lineDoc)) { + return pos; + } else { + int lineDisplay = cs.DisplayFromDoc(lineDoc); + if (moveDir > 0) { + // lineDisplay is already line before fold as lines in fold use display line of line after fold + lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); + return pdoc->LineStart(cs.DocFromDisplay(lineDisplay)); + } else { + lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed()); + return pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)); + } + } +} + +/** + * Choose the x position that the caret will try to stick to + * as it moves up and down. + */ +void Editor::SetLastXChosen() { + Point pt = LocationFromPosition(currentPos); + lastXChosen = pt.x; +} + +void Editor::ScrollTo(int line, bool moveThumb) { + int topLineNew = Platform::Clamp(line, 0, MaxScrollPos()); + if (topLineNew != topLine) { + // Try to optimise small scrolls + int linesToMove = topLine - topLineNew; + SetTopLine(topLineNew); + ShowCaretAtCurrentPosition(); + // Perform redraw rather than scroll if many lines would be redrawn anyway. +#ifndef UNDER_CE + if ((abs(linesToMove) <= 10) && (paintState == notPainting)) { + ScrollText(linesToMove); + } else { + Redraw(); + } +#else + Redraw(); +#endif + if (moveThumb) { + SetVerticalScrollPos(); + } + } +} + +void Editor::ScrollText(int /* linesToMove */) { + //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove); + Redraw(); +} + +void Editor::HorizontalScrollTo(int xPos) { + //Platform::DebugPrintf("HorizontalScroll %d\n", xPos); + if (xPos < 0) + xPos = 0; + if ((wrapState == eWrapNone) && (xOffset != xPos)) { + xOffset = xPos; + SetHorizontalScrollPos(); + RedrawRect(GetClientRectangle()); + } +} + +void Editor::MoveCaretInsideView(bool ensureVisible) { + PRectangle rcClient = GetTextRectangle(); + Point pt = LocationFromPosition(currentPos); + if (pt.y < rcClient.top) { + MovePositionTo(PositionFromLocation( + Point(lastXChosen, rcClient.top)), + noSel, ensureVisible); + } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) { + int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight; + MovePositionTo(PositionFromLocation( + Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)), + noSel, ensureVisible); + } +} + +int Editor::DisplayFromPosition(int pos) { + int lineDoc = pdoc->LineFromPosition(pos); + int lineDisplay = cs.DisplayFromDoc(lineDoc); + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); + if (surface && ll) { + LayoutLine(lineDoc, surface, vs, ll, wrapWidth); + unsigned int posLineStart = pdoc->LineStart(lineDoc); + int posInLine = pos - posLineStart; + lineDisplay--; // To make up for first increment ahead. + for (int subLine = 0; subLine < ll->lines; subLine++) { + if (posInLine >= ll->LineStart(subLine)) { + lineDisplay++; + } + } + } + return lineDisplay; +} + +/** + * Ensure the caret is reasonably visible in context. + * +Caret policy in SciTE + +If slop is set, we can define a slop value. +This value defines an unwanted zone (UZ) where the caret is... unwanted. +This zone is defined as a number of pixels near the vertical margins, +and as a number of lines near the horizontal margins. +By keeping the caret away from the edges, it is seen within its context, +so it is likely that the identifier that the caret is on can be completely seen, +and that the current line is seen with some of the lines following it which are +often dependent on that line. + +If strict is set, the policy is enforced... strictly. +The caret is centred on the display if slop is not set, +and cannot go in the UZ if slop is set. + +If jumps is set, the display is moved more energetically +so the caret can move in the same direction longer before the policy is applied again. +'3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin. + +If even is not set, instead of having symmetrical UZs, +the left and bottom UZs are extended up to right and top UZs respectively. +This way, we favour the displaying of useful information: the begining of lines, +where most code reside, and the lines after the caret, eg. the body of a function. + + | | | | | +slop | strict | jumps | even | Caret can go to the margin | When reaching limitÝ(caret going out of + | | | | | visibility or going into the UZ) display is... +-----+--------+-------+------+--------------------------------------------+-------------------------------------------------------------- + 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right + 0 | 0 | 0 | 1 | Yes | moved by one position + 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right + 0 | 0 | 1 | 1 | Yes | centred on the caret + 0 | 1 | - | 0 | Caret is always on top/on right of display | - + 0 | 1 | - | 1 | No, caret is always centred | - + 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ + 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ + 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin + 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin + 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | - + 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position + 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin +*/ +void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { + //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " "); + PRectangle rcClient = GetTextRectangle(); + //int rcClientFullWidth = rcClient.Width(); + int posCaret = currentPos; + if (posDrag >= 0) { + posCaret = posDrag; + } + Point pt = LocationFromPosition(posCaret); + Point ptBottomCaret = pt; + ptBottomCaret.y += vs.lineHeight - 1; + int lineCaret = DisplayFromPosition(posCaret); + bool bSlop, bStrict, bJump, bEven; + + // Vertical positioning + if (vert && (pt.y < rcClient.top || ptBottomCaret.y > rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { + int linesOnScreen = LinesOnScreen(); + int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2; + int newTopLine = topLine; + bSlop = (caretYPolicy & CARET_SLOP) != 0; + bStrict = (caretYPolicy & CARET_STRICT) != 0; + bJump = (caretYPolicy & CARET_JUMPS) != 0; + bEven = (caretYPolicy & CARET_EVEN) != 0; + + // It should be possible to scroll the window to show the caret, + // but this fails to remove the caret on GTK+ + if (bSlop) { // A margin is defined + int yMoveT, yMoveB; + if (bStrict) { + int yMarginT, yMarginB; + if (!useMargin) { + // In drag mode, avoid moves + // otherwise, a double click will select several lines. + yMarginT = yMarginB = 0; + } else { + // yMarginT must equal to caretYSlop, with a minimum of 1 and + // a maximum of slightly less than half the heigth of the text area. + yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen); + if (bEven) { + yMarginB = yMarginT; + } else { + yMarginB = linesOnScreen - yMarginT - 1; + } + } + yMoveT = yMarginT; + if (bEven) { + if (bJump) { + yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen); + } + yMoveB = yMoveT; + } else { + yMoveB = linesOnScreen - yMoveT - 1; + } + if (lineCaret < topLine + yMarginT) { + // Caret goes too high + newTopLine = lineCaret - yMoveT; + } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) { + // Caret goes too low + newTopLine = lineCaret - linesOnScreen + 1 + yMoveB; + } + } else { // Not strict + yMoveT = bJump ? caretYSlop * 3 : caretYSlop; + yMoveT = Platform::Clamp(yMoveT, 1, halfScreen); + if (bEven) { + yMoveB = yMoveT; + } else { + yMoveB = linesOnScreen - yMoveT - 1; + } + if (lineCaret < topLine) { + // Caret goes too high + newTopLine = lineCaret - yMoveT; + } else if (lineCaret > topLine + linesOnScreen - 1) { + // Caret goes too low + newTopLine = lineCaret - linesOnScreen + 1 + yMoveB; + } + } + } else { // No slop + if (!bStrict && !bJump) { + // Minimal move + if (lineCaret < topLine) { + // Caret goes too high + newTopLine = lineCaret; + } else if (lineCaret > topLine + linesOnScreen - 1) { + // Caret goes too low + if (bEven) { + newTopLine = lineCaret - linesOnScreen + 1; + } else { + newTopLine = lineCaret; + } + } + } else { // Strict or going out of display + if (bEven) { + // Always center caret + newTopLine = lineCaret - halfScreen; + } else { + // Always put caret on top of display + newTopLine = lineCaret; + } + } + } + newTopLine = Platform::Clamp(newTopLine, 0, MaxScrollPos()); + if (newTopLine != topLine) { + Redraw(); + SetTopLine(newTopLine); + SetVerticalScrollPos(); + } + } + + // Horizontal positioning + if (horiz && (wrapState == eWrapNone)) { + int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2; + int xOffsetNew = xOffset; + bSlop = (caretXPolicy & CARET_SLOP) != 0; + bStrict = (caretXPolicy & CARET_STRICT) != 0; + bJump = (caretXPolicy & CARET_JUMPS) != 0; + bEven = (caretXPolicy & CARET_EVEN) != 0; + + if (bSlop) { // A margin is defined + int xMoveL, xMoveR; + if (bStrict) { + int xMarginL, xMarginR; + if (!useMargin) { + // In drag mode, avoid moves unless very near of the margin + // otherwise, a simple click will select text. + xMarginL = xMarginR = 2; + } else { + // xMargin must equal to caretXSlop, with a minimum of 2 and + // a maximum of slightly less than half the width of the text area. + xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen); + if (bEven) { + xMarginL = xMarginR; + } else { + xMarginL = rcClient.Width() - xMarginR - 4; + } + } + if (bJump && bEven) { + // Jump is used only in even mode + xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen); + } else { + xMoveL = xMoveR = 0; // Not used, avoid a warning + } + if (pt.x < rcClient.left + xMarginL) { + // Caret is on the left of the display + if (bJump && bEven) { + xOffsetNew -= xMoveL; + } else { + // Move just enough to allow to display the caret + xOffsetNew -= (rcClient.left + xMarginL) - pt.x; + } + } else if (pt.x >= rcClient.right - xMarginR) { + // Caret is on the right of the display + if (bJump && bEven) { + xOffsetNew += xMoveR; + } else { + // Move just enough to allow to display the caret + xOffsetNew += pt.x - (rcClient.right - xMarginR) + 1; + } + } + } else { // Not strict + xMoveR = bJump ? caretXSlop * 3 : caretXSlop; + xMoveR = Platform::Clamp(xMoveR, 1, halfScreen); + if (bEven) { + xMoveL = xMoveR; + } else { + xMoveL = rcClient.Width() - xMoveR - 4; + } + if (pt.x < rcClient.left) { + // Caret is on the left of the display + xOffsetNew -= xMoveL; + } else if (pt.x >= rcClient.right) { + // Caret is on the right of the display + xOffsetNew += xMoveR; + } + } + } else { // No slop + if (bStrict || + (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) { + // Strict or going out of display + if (bEven) { + // Center caret + xOffsetNew += pt.x - rcClient.left - halfScreen; + } else { + // Put caret on right + xOffsetNew += pt.x - rcClient.right + 1; + } + } else { + // Move just enough to allow to display the caret + if (pt.x < rcClient.left) { + // Caret is on the left of the display + if (bEven) { + xOffsetNew -= rcClient.left - pt.x; + } else { + xOffsetNew += pt.x - rcClient.right + 1; + } + } else if (pt.x >= rcClient.right) { + // Caret is on the right of the display + xOffsetNew += pt.x - rcClient.right + 1; + } + } + } + // In case of a jump (find result) largely out of display, adjust the offset to display the caret + if (pt.x + xOffset < rcClient.left + xOffsetNew) { + xOffsetNew = pt.x + xOffset - rcClient.left; + } else if (pt.x + xOffset >= rcClient.right + xOffsetNew) { + xOffsetNew = pt.x + xOffset - rcClient.right + 1; + if (vs.caretStyle == CARETSTYLE_BLOCK) { + // Ensure we can see a good portion of the block caret + xOffsetNew += vs.aveCharWidth; + } + } + if (xOffsetNew < 0) { + xOffsetNew = 0; + } + if (xOffset != xOffsetNew) { + xOffset = xOffsetNew; + if (xOffsetNew > 0) { + PRectangle rcText = GetTextRectangle(); + if (horizontalScrollBarVisible && + rcText.Width() + xOffset > scrollWidth) { + scrollWidth = xOffset + rcText.Width(); + SetScrollBars(); + } + } + SetHorizontalScrollPos(); + Redraw(); + } + } + UpdateSystemCaret(); +} + +void Editor::ShowCaretAtCurrentPosition() { + if (hasFocus) { + caret.active = true; + caret.on = true; + SetTicking(true); + } else { + caret.active = false; + caret.on = false; + } + InvalidateCaret(); +} + +void Editor::DropCaret() { + caret.active = false; + InvalidateCaret(); +} + +void Editor::InvalidateCaret() { + if (posDrag >= 0) + InvalidateRange(posDrag, posDrag + 1); + else + InvalidateRange(currentPos, currentPos + 1); + UpdateSystemCaret(); +} + +void Editor::UpdateSystemCaret() { +} + +void Editor::NeedWrapping(int docLineStart, int docLineEnd) { + docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal()); + if (wrapStart > docLineStart) { + wrapStart = docLineStart; + llc.Invalidate(LineLayout::llPositions); + } + if (wrapEnd < docLineEnd) { + wrapEnd = docLineEnd; + } + wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal()); + // Wrap lines during idle. + if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) { + SetIdle(true); + } +} + +bool Editor::WrapOneLine(Surface *surface, int lineToWrap) { + AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap)); + int linesWrapped = 1; + if (ll) { + LayoutLine(lineToWrap, surface, vs, ll, wrapWidth); + linesWrapped = ll->lines; + } + return cs.SetHeight(lineToWrap, linesWrapped + + (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); +} + +// Check if wrapping needed and perform any needed wrapping. +// fullwrap: if true, all lines which need wrapping will be done, +// in this single call. +// priorityWrapLineStart: If greater than zero, all lines starting from +// here to 1 page + 100 lines past will be wrapped (even if there are +// more lines under wrapping process in idle). +// If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be +// wrapped, if there are any wrapping going on in idle. (Generally this +// condition is called only from idler). +// Return true if wrapping occurred. +bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { + // If there are any pending wraps, do them during idle if possible. + int linesInOneCall = LinesOnScreen() + 100; + if (wrapState != eWrapNone) { + if (wrapStart < wrapEnd) { + if (!SetIdle(true)) { + // Idle processing not supported so full wrap required. + fullWrap = true; + } + } + if (!fullWrap && priorityWrapLineStart >= 0 && + // .. and if the paint window is outside pending wraps + (((priorityWrapLineStart + linesInOneCall) < wrapStart) || + (priorityWrapLineStart > wrapEnd))) { + // No priority wrap pending + return false; + } + } + int goodTopLine = topLine; + bool wrapOccurred = false; + if (wrapStart <= pdoc->LinesTotal()) { + if (wrapState == eWrapNone) { + if (wrapWidth != LineLayout::wrapWidthInfinite) { + wrapWidth = LineLayout::wrapWidthInfinite; + for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { + cs.SetHeight(lineDoc, 1 + + (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); + } + wrapOccurred = true; + } + wrapStart = wrapLineLarge; + wrapEnd = wrapLineLarge; + } else { + if (wrapEnd >= pdoc->LinesTotal()) + wrapEnd = pdoc->LinesTotal(); + //ElapsedTime et; + int lineDocTop = cs.DocFromDisplay(topLine); + int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop); + PRectangle rcTextArea = GetClientRectangle(); + rcTextArea.left = vs.fixedColumnWidth; + rcTextArea.right -= vs.rightMarginWidth; + wrapWidth = rcTextArea.Width(); + // Ensure all of the document is styled. + pdoc->EnsureStyledTo(pdoc->Length()); + RefreshStyleData(); + AutoSurface surface(this); + if (surface) { + bool priorityWrap = false; + int lastLineToWrap = wrapEnd; + int lineToWrap = wrapStart; + if (!fullWrap) { + if (priorityWrapLineStart >= 0) { + // This is a priority wrap. + lineToWrap = priorityWrapLineStart; + lastLineToWrap = priorityWrapLineStart + linesInOneCall; + priorityWrap = true; + } else { + // This is idle wrap. + lastLineToWrap = wrapStart + linesInOneCall; + } + if (lastLineToWrap >= wrapEnd) + lastLineToWrap = wrapEnd; + } // else do a fullWrap. + + // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap); + // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd); + while (lineToWrap < lastLineToWrap) { + if (WrapOneLine(surface, lineToWrap)) { + wrapOccurred = true; + } + lineToWrap++; + } + if (!priorityWrap) + wrapStart = lineToWrap; + // If wrapping is done, bring it to resting position + if (wrapStart >= wrapEnd) { + wrapStart = wrapLineLarge; + wrapEnd = wrapLineLarge; + } + } + goodTopLine = cs.DisplayFromDoc(lineDocTop); + if (subLineTop < cs.GetHeight(lineDocTop)) + goodTopLine += subLineTop; + else + goodTopLine += cs.GetHeight(lineDocTop); + //double durWrap = et.Duration(true); + //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap); + } + } + if (wrapOccurred) { + SetScrollBars(); + SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos())); + SetVerticalScrollPos(); + } + return wrapOccurred; +} + +void Editor::LinesJoin() { + if (!RangeContainsProtected(targetStart, targetEnd)) { + pdoc->BeginUndoAction(); + bool prevNonWS = true; + for (int pos = targetStart; pos < targetEnd; pos++) { + if (IsEOLChar(pdoc->CharAt(pos))) { + targetEnd -= pdoc->LenChar(pos); + pdoc->DelChar(pos); + if (prevNonWS) { + // Ensure at least one space separating previous lines + pdoc->InsertChar(pos, ' '); + targetEnd++; + } + } else { + prevNonWS = pdoc->CharAt(pos) != ' '; + } + } + pdoc->EndUndoAction(); + } +} + +const char *Editor::StringFromEOLMode(int eolMode) { + if (eolMode == SC_EOL_CRLF) { + return "\r\n"; + } else if (eolMode == SC_EOL_CR) { + return "\r"; + } else { + return "\n"; + } +} + +void Editor::LinesSplit(int pixelWidth) { + if (!RangeContainsProtected(targetStart, targetEnd)) { + if (pixelWidth == 0) { + PRectangle rcText = GetTextRectangle(); + pixelWidth = rcText.Width(); + } + int lineStart = pdoc->LineFromPosition(targetStart); + int lineEnd = pdoc->LineFromPosition(targetEnd); + const char *eol = StringFromEOLMode(pdoc->eolMode); + pdoc->BeginUndoAction(); + for (int line = lineStart; line <= lineEnd; line++) { + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(line)); + if (surface && ll) { + unsigned int posLineStart = pdoc->LineStart(line); + LayoutLine(line, surface, vs, ll, pixelWidth); + for (int subLine = 1; subLine < ll->lines; subLine++) { + pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) + + ll->LineStart(subLine), eol); + targetEnd += static_cast(strlen(eol)); + } + } + lineEnd = pdoc->LineFromPosition(targetEnd); + } + pdoc->EndUndoAction(); + } +} + +int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) { + if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) + return markerDefault; + return markerCheck; +} + +// Avoid 64 bit compiler warnings. +// Scintilla does not support text buffers larger than 2**31 +static int istrlen(const char *s) { + return static_cast(strlen(s)); +} + +bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) { + if (st.multipleStyles) { + for (size_t iStyle=0;iStyle(styles[endSegment+1]) == style)) + endSegment++; + width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, endSegment - start + 1); + start = endSegment + 1; + } + return width; +} + +static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, const StyledText &st) { + int widthMax = 0; + size_t start = 0; + while (start < st.length) { + size_t lenLine = st.LineLength(start); + int widthSubLine; + if (st.multipleStyles) { + widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); + } else { + widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, st.text + start, lenLine); + } + if (widthSubLine > widthMax) + widthMax = widthSubLine; + start += lenLine + 1; + } + return widthMax; +} + +void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent, + const StyledText &st, size_t start, size_t length) { + + if (st.multipleStyles) { + int x = rcText.left; + size_t i = 0; + while (i < length) { + size_t end = i; + int style = st.styles[i + start]; + while (end < length-1 && st.styles[start+end+1] == style) + end++; + style += styleOffset; + int width = surface->WidthText(vs.styles[style].font, st.text + start + i, end - i + 1); + PRectangle rcSegment = rcText; + rcSegment.left = x; + rcSegment.right = x + width + 1; + surface->DrawTextNoClip(rcSegment, vs.styles[style].font, + ascent, st.text + start + i, end - i + 1, + vs.styles[style].fore.allocated, + vs.styles[style].back.allocated); + x += width; + i = end + 1; + } + } else { + int style = st.style + styleOffset; + surface->DrawTextNoClip(rcText, vs.styles[style].font, + rcText.top + vs.maxAscent, st.text, st.length, + vs.styles[style].fore.allocated, + vs.styles[style].back.allocated); + } +} + +void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { + if (vs.fixedColumnWidth == 0) + return; + + PRectangle rcMargin = GetClientRectangle(); + rcMargin.right = vs.fixedColumnWidth; + + if (!rc.Intersects(rcMargin)) + return; + + Surface *surface; + if (bufferedDraw) { + surface = pixmapSelMargin; + } else { + surface = surfWindow; + } + + PRectangle rcSelMargin = rcMargin; + rcSelMargin.right = rcMargin.left; + + for (int margin = 0; margin < vs.margins; margin++) { + if (vs.ms[margin].width > 0) { + + rcSelMargin.left = rcSelMargin.right; + rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; + + if (vs.ms[margin].style != SC_MARGIN_NUMBER) { + /* alternate scheme: + if (vs.ms[margin].mask & SC_MASK_FOLDERS) + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_DEFAULT].back.allocated); + else + // Required because of special way brush is created for selection margin + surface->FillRectangle(rcSelMargin, pixmapSelPattern); + */ + if (vs.ms[margin].mask & SC_MASK_FOLDERS) + // Required because of special way brush is created for selection margin + surface->FillRectangle(rcSelMargin, *pixmapSelPattern); + else { + ColourAllocated colour; + switch (vs.ms[margin].style) { + case SC_MARGIN_BACK: + colour = vs.styles[STYLE_DEFAULT].back.allocated; + break; + case SC_MARGIN_FORE: + colour = vs.styles[STYLE_DEFAULT].fore.allocated; + break; + default: + colour = vs.styles[STYLE_LINENUMBER].back.allocated; + break; + } + surface->FillRectangle(rcSelMargin, colour); + } + } else { + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); + } + + int visibleLine = topLine; + int yposScreen = 0; + + // Work out whether the top line is whitespace located after a + // lessening of fold level which implies a 'fold tail' but which should not + // be displayed until the last of a sequence of whitespace. + bool needWhiteClosure = false; + int level = pdoc->GetLevel(cs.DocFromDisplay(topLine)); + if (level & SC_FOLDLEVELWHITEFLAG) { + int lineBack = cs.DocFromDisplay(topLine); + int levelPrev = level; + while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { + lineBack--; + levelPrev = pdoc->GetLevel(lineBack); + } + if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { + if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK)) + needWhiteClosure = true; + } + } + + // Old code does not know about new markers needed to distinguish all cases + int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, + SC_MARKNUM_FOLDEROPEN); + int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND, + SC_MARKNUM_FOLDER); + + while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) { + + PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed()); + + int lineDoc = cs.DocFromDisplay(visibleLine); + PLATFORM_ASSERT(cs.GetVisible(lineDoc)); + bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc); + + // Decide which fold indicator should be displayed + level = pdoc->GetLevel(lineDoc); + int levelNext = pdoc->GetLevel(lineDoc + 1); + int marks = pdoc->GetMark(lineDoc); + if (!firstSubLine) + marks = 0; + int levelNum = level & SC_FOLDLEVELNUMBERMASK; + int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK; + if (level & SC_FOLDLEVELHEADERFLAG) { + if (firstSubLine) { + if (cs.GetExpanded(lineDoc)) { + if (levelNum == SC_FOLDLEVELBASE) + marks |= 1 << SC_MARKNUM_FOLDEROPEN; + else + marks |= 1 << folderOpenMid; + } else { + if (levelNum == SC_FOLDLEVELBASE) + marks |= 1 << SC_MARKNUM_FOLDER; + else + marks |= 1 << folderEnd; + } + } else { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + needWhiteClosure = false; + } else if (level & SC_FOLDLEVELWHITEFLAG) { + if (needWhiteClosure) { + if (levelNext & SC_FOLDLEVELWHITEFLAG) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } else if (levelNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + needWhiteClosure = false; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + needWhiteClosure = false; + } + } else if (levelNum > SC_FOLDLEVELBASE) { + if (levelNextNum < levelNum) { + if (levelNextNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + } + } else { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + } + } else if (levelNum > SC_FOLDLEVELBASE) { + if (levelNextNum < levelNum) { + needWhiteClosure = false; + if (levelNext & SC_FOLDLEVELWHITEFLAG) { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + needWhiteClosure = true; + } else if (levelNextNum > SC_FOLDLEVELBASE) { + marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; + } else { + marks |= 1 << SC_MARKNUM_FOLDERTAIL; + } + } else { + marks |= 1 << SC_MARKNUM_FOLDERSUB; + } + } + + marks &= vs.ms[margin].mask; + PRectangle rcMarker = rcSelMargin; + rcMarker.top = yposScreen; + rcMarker.bottom = yposScreen + vs.lineHeight; + if (vs.ms[margin].style == SC_MARGIN_NUMBER) { + char number[100]; + number[0] = '\0'; + if (firstSubLine) + sprintf(number, "%d", lineDoc + 1); + if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) { + int lev = pdoc->GetLevel(lineDoc); + sprintf(number, "%c%c %03X %03X", + (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_', + (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_', + lev & SC_FOLDLEVELNUMBERMASK, + lev >> 16 + ); + } + PRectangle rcNumber = rcMarker; + // Right justify + int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number)); + int xpos = rcNumber.right - width - 3; + rcNumber.left = xpos; + surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font, + rcNumber.top + vs.maxAscent, number, istrlen(number), + vs.styles[STYLE_LINENUMBER].fore.allocated, + vs.styles[STYLE_LINENUMBER].back.allocated); + } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { + if (firstSubLine) { + const StyledText stMargin = pdoc->MarginStyledText(lineDoc); + if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { + surface->FillRectangle(rcMarker, + vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back.allocated); + if (vs.ms[margin].style == SC_MARGIN_RTEXT) { + int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); + rcMarker.left = rcMarker.right - width - 3; + } + DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent, + stMargin, 0, stMargin.length); + } + } + } + + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font); + } + marks >>= 1; + } + } + + visibleLine++; + yposScreen += vs.lineHeight; + } + } + } + + PRectangle rcBlankMargin = rcMargin; + rcBlankMargin.left = rcSelMargin.right; + surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated); + + if (bufferedDraw) { + surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin); + } +} + +void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { + int ydiff = (rcTab.bottom - rcTab.top) / 2; + int xhead = rcTab.right - 1 - ydiff; + if (xhead <= rcTab.left) { + ydiff -= rcTab.left - xhead - 1; + xhead = rcTab.left - 1; + } + if ((rcTab.left + 2) < (rcTab.right - 1)) + surface->MoveTo(rcTab.left + 2, ymid); + else + surface->MoveTo(rcTab.right - 1, ymid); + surface->LineTo(rcTab.right - 1, ymid); + surface->LineTo(xhead, ymid - ydiff); + surface->MoveTo(rcTab.right - 1, ymid); + surface->LineTo(xhead, ymid + ydiff); +} + +LineLayout *Editor::RetrieveLineLayout(int lineNumber) { + int posLineStart = pdoc->LineStart(lineNumber); + int posLineEnd = pdoc->LineStart(lineNumber + 1); + PLATFORM_ASSERT(posLineEnd >= posLineStart); + int lineCaret = pdoc->LineFromPosition(currentPos); + return llc.Retrieve(lineNumber, lineCaret, + posLineEnd - posLineStart, pdoc->GetStyleClock(), + LinesOnScreen() + 1, pdoc->LinesTotal()); +} + +static bool GoodTrailByte(int v) { + return (v >= 0x80) && (v < 0xc0); +} + +bool BadUTF(const char *s, int len, int &trailBytes) { + if (trailBytes) { + trailBytes--; + return false; + } + const unsigned char *us = reinterpret_cast(s); + if (*us < 0x80) { + // Single bytes easy + return false; + } else if (*us > 0xF4) { + // Characters longer than 4 bytes not possible in current UTF-8 + return true; + } else if (*us >= 0xF0) { + // 4 bytes + if (len < 4) + return true; + if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) { + trailBytes = 3; + return false; + } else { + return true; + } + } else if (*us >= 0xE0) { + // 3 bytes + if (len < 3) + return true; + if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) { + trailBytes = 2; + return false; + } else { + return true; + } + } else if (*us >= 0xC2) { + // 2 bytes + if (len < 2) + return true; + if (GoodTrailByte(us[1])) { + trailBytes = 1; + return false; + } else { + return true; + } + } else if (*us >= 0xC0) { + // Overlong encoding + return true; + } else { + // Trail byte + return true; + } +} + +/** + * Fill in the LineLayout data for the given line. + * Copy the given @a line and its styles from the document into local arrays. + * Also determine the x position at which each character starts. + */ +void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) { + if (!ll) + return; + + PLATFORM_ASSERT(line < pdoc->LinesTotal()); + PLATFORM_ASSERT(ll->chars != NULL); + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + // If the line is very long, limit the treatment to a length that should fit in the viewport + if (posLineEnd > (posLineStart + ll->maxLineLength)) { + posLineEnd = posLineStart + ll->maxLineLength; + } + if (ll->validity == LineLayout::llCheckTextAndStyle) { + int lineLength = posLineEnd - posLineStart; + if (!vstyle.viewEOL) { + int cid = posLineEnd - 1; + while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) { + cid--; + lineLength--; + } + } + if (lineLength == ll->numCharsInLine) { + // See if chars, styles, indicators, are all the same + bool allSame = true; + const int styleMask = pdoc->stylingBitsMask; + // Check base line layout + char styleByte = 0; + int numCharsInLine = 0; + while (numCharsInLine < lineLength) { + int charInDoc = numCharsInLine + posLineStart; + char chDoc = pdoc->CharAt(charInDoc); + styleByte = pdoc->StyleAt(charInDoc); + allSame = allSame && + (ll->styles[numCharsInLine] == static_cast(styleByte & styleMask)); + allSame = allSame && + (ll->indicators[numCharsInLine] == static_cast(styleByte & ~styleMask)); + if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) + allSame = allSame && + (ll->chars[numCharsInLine] == chDoc); + else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast(tolower(chDoc))); + else // Style::caseUpper + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast(toupper(chDoc))); + numCharsInLine++; + } + allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled + if (allSame) { + ll->validity = LineLayout::llPositions; + } else { + ll->validity = LineLayout::llInvalid; + } + } else { + ll->validity = LineLayout::llInvalid; + } + } + if (ll->validity == LineLayout::llInvalid) { + ll->widthLine = LineLayout::wrapWidthInfinite; + ll->lines = 1; + int numCharsInLine = 0; + if (vstyle.edgeState == EDGE_BACKGROUND) { + ll->edgeColumn = pdoc->FindColumn(line, theEdge); + if (ll->edgeColumn >= posLineStart) { + ll->edgeColumn -= posLineStart; + } + } else { + ll->edgeColumn = -1; + } + + char styleByte = 0; + int styleMask = pdoc->stylingBitsMask; + ll->styleBitsSet = 0; + // Fill base line layout + for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) { + char chDoc = pdoc->CharAt(charInDoc); + styleByte = pdoc->StyleAt(charInDoc); + ll->styleBitsSet |= styleByte; + if (vstyle.viewEOL || (!IsEOLChar(chDoc))) { + ll->chars[numCharsInLine] = chDoc; + ll->styles[numCharsInLine] = static_cast(styleByte & styleMask); + ll->indicators[numCharsInLine] = static_cast(styleByte & ~styleMask); + if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper) + ll->chars[numCharsInLine] = static_cast(toupper(chDoc)); + else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) + ll->chars[numCharsInLine] = static_cast(tolower(chDoc)); + numCharsInLine++; + } + } + ll->xHighlightGuide = 0; + // Extra element at the end of the line to hold end x position and act as + ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character + ll->styles[numCharsInLine] = styleByte; // For eolFilled + ll->indicators[numCharsInLine] = 0; + + // Layout the line, determining the position of each character, + // with an extra element at the end for the end of the line. + int startseg = 0; // Start of the current segment, in char. number + int startsegx = 0; // Start of the current segment, in pixels + ll->positions[0] = 0; + unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars; + bool lastSegItalics = false; + Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; + + int ctrlCharWidth[32] = {0}; + bool isControlNext = IsControlCharacter(ll->chars[0]); + int trailBytes = 0; + bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes); + for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { + bool isControl = isControlNext; + isControlNext = IsControlCharacter(ll->chars[charInLine + 1]); + bool isBadUTF = isBadUTFNext; + isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes); + if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) || + isControl || isControlNext || isBadUTF || isBadUTFNext) { + ll->positions[startseg] = 0; + if (vstyle.styles[ll->styles[charInLine]].visible) { + if (isControl) { + if (ll->chars[charInLine] == '\t') { + ll->positions[charInLine + 1] = ((((startsegx + 2) / + tabWidth) + 1) * tabWidth) - startsegx; + } else if (controlCharSymbol < 32) { + int iCharInChars = ll->chars[charInLine]; // Pritpal + if (ctrlCharWidth[ iCharInChars ] == 0) { + //const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]); + const char *ctrlChar = ControlCharacterString( iCharInChars ); + // +3 For a blank on front and rounded edge each side: + //ctrlCharWidth[ll->chars[charInLine]] = + ctrlCharWidth[ iCharInChars ] = + surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3; + } + //ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]]; + ll->positions[charInLine + 1] = ctrlCharWidth[ iCharInChars ]; + } else { + char cc[2] = { static_cast(controlCharSymbol), '\0' }; + surface->MeasureWidths(ctrlCharsFont, cc, 1, + ll->positions + startseg + 1); + } + lastSegItalics = false; + } else if (isBadUTF) { + char hexits[3]; + sprintf(hexits, "%2X", ll->chars[charInLine] & 0xff); + ll->positions[charInLine + 1] = + surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3; + } else { // Regular character + int lenSeg = charInLine - startseg + 1; + if ((lenSeg == 1) && (' ' == ll->chars[startseg])) { + lastSegItalics = false; + // Over half the segments are single characters and of these about half are space characters. + ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth; + } else { + lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic; + posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg, + lenSeg, ll->positions + startseg + 1); + } + } + } else { // invisible + for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) { + ll->positions[posToZero] = 0; + } + } + for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { + ll->positions[posToIncrease] += startsegx; + } + startsegx = ll->positions[charInLine + 1]; + startseg = charInLine + 1; + } + } + // Small hack to make lines that end with italics not cut off the edge of the last character + if ((startseg > 0) && lastSegItalics) { + ll->positions[startseg] += 2; + } + ll->numCharsInLine = numCharsInLine; + ll->validity = LineLayout::llPositions; + } + // Hard to cope when too narrow, so just assume there is space + if (width < 20) { + width = 20; + } + if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { + ll->widthLine = width; + if (width == LineLayout::wrapWidthInfinite) { + ll->lines = 1; + } else if (width > ll->positions[ll->numCharsInLine]) { + // Simple common case where line does not need wrapping. + ll->lines = 1; + } else { + if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + width -= vstyle.aveCharWidth; // take into account the space for end wrap mark + } + ll->lines = 0; + // Calculate line start positions based upon width. + int lastGoodBreak = 0; + int lastLineStart = 0; + int startOffset = 0; + int p = 0; + while (p < ll->numCharsInLine) { + if ((ll->positions[p + 1] - startOffset) >= width) { + if (lastGoodBreak == lastLineStart) { + // Try moving to start of last character + if (p > 0) { + lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + } + if (lastGoodBreak == lastLineStart) { + // Ensure at least one character on line. + lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) + - posLineStart; + } + } + lastLineStart = lastGoodBreak; + ll->lines++; + ll->SetLineStart(ll->lines, lastGoodBreak); + startOffset = ll->positions[lastGoodBreak]; + // take into account the space for start wrap mark and indent + startOffset -= actualWrapVisualStartIndent * vstyle.aveCharWidth; + p = lastGoodBreak + 1; + continue; + } + if (p > 0) { + if (wrapState == eWrapChar) { + lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; + continue; + } else if (ll->styles[p] != ll->styles[p - 1]) { + lastGoodBreak = p; + } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { + lastGoodBreak = p; + } + } + p++; + } + ll->lines++; + } + ll->validity = LineLayout::llLines; + } +} + +ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw) { + return primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated; +} + +ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground, + ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) { + if (inSelection) { + if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw); + } + } else { + if ((vsDraw.edgeState == EDGE_BACKGROUND) && + (i >= ll->edgeColumn) && + !IsEOLChar(ll->chars[i])) + return vsDraw.edgecolour.allocated; + if (inHotspot && vsDraw.hotspotBackgroundSet) + return vsDraw.hotspotBackground.allocated; + if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) + return background; + } + return vsDraw.styles[styleMain].back.allocated; +} + +void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { + Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); + PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom); + surface->Copy(rcCopyArea, from, + highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); +} + +void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace, + bool isEndMarker, ColourAllocated wrapColour) { + surface->PenColour(wrapColour); + + enum { xa = 1 }; // gap before start + int w = rcPlace.right - rcPlace.left - xa - 1; + + bool xStraight = isEndMarker; // x-mirrored symbol for start marker + bool yStraight = true; + //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed + + int x0 = xStraight ? rcPlace.left : rcPlace.right - 1; + int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1; + + int dy = (rcPlace.bottom - rcPlace.top) / 5; + int y = (rcPlace.bottom - rcPlace.top) / 2 + dy; + + struct Relative { + Surface *surface; + int xBase; + int xDir; + int yBase; + int yDir; + void MoveTo(int xRelative, int yRelative) { + surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); + } + void LineTo(int xRelative, int yRelative) { + surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); + } + }; + Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1}; + + // arrow head + rel.MoveTo(xa, y); + rel.LineTo(xa + 2*w / 3, y - dy); + rel.MoveTo(xa, y); + rel.LineTo(xa + 2*w / 3, y + dy); + + // arrow body + rel.MoveTo(xa, y); + rel.LineTo(xa + w, y); + rel.LineTo(xa + w, y - 2 * dy); + rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... + y - 2 * dy); +} + +static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) { + if (alpha != SC_ALPHA_NOALPHA) { + surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); + } +} + +void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, + int line, int lineEnd, int xStart, int subLine, int subLineStart, + bool overrideBackground, ColourAllocated background, + bool drawWrapMarkEnd, ColourAllocated wrapColour) { + + int styleMask = pdoc->stylingBitsMask; + PRectangle rcSegment = rcLine; + + // Fill in a PRectangle representing the end of line characters + int xEol = ll->positions[lineEnd] - subLineStart; + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + vsDraw.aveCharWidth + xStart; + int posLineEnd = pdoc->LineStart(line + 1); + bool eolInSelection = (subLine == (ll->lines - 1)) && + (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd); + + if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw)); + } else { + if (overrideBackground) { + surface->FillRectangle(rcSegment, background); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); + } + if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); + } + } + + rcSegment.left = xEol + vsDraw.aveCharWidth + xStart; + rcSegment.right = rcLine.right; + + if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw)); + } else { + if (overrideBackground) { + surface->FillRectangle(rcSegment, background); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated); + } + if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); + } + } + + if (drawWrapMarkEnd) { + PRectangle rcPlace = rcSegment; + + if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { + rcPlace.left = xEol + xStart; + rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; + } else { + // draw left of the right text margin, to avoid clipping by the current clip rect + rcPlace.right = rcLine.right - vs.rightMarginWidth; + rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; + } + DrawWrapMarker(surface, rcPlace, true, wrapColour); + } +} + +void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) { + // Draw decorators + const int posLineStart = pdoc->LineStart(line); + const int lineStart = ll->LineStart(subLine); + const int subLineStart = ll->positions[lineStart]; + const int posLineEnd = posLineStart + lineEnd; + + if (!under) { + // Draw indicators + // foreach indicator... + for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) { + if (!(mask & ll->styleBitsSet)) { + mask <<= 1; + continue; + } + int startPos = -1; + // foreach style pos in line... + for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) { + // look for starts... + if (startPos < 0) { + // NOT in indicator run, looking for START + if (indicPos < lineEnd && (ll->indicators[indicPos] & mask)) + startPos = indicPos; + } + // ... or ends + if (startPos >= 0) { + // IN indicator run, looking for END + if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) { + // AT end of indicator run, DRAW it! + PRectangle rcIndic( + ll->positions[startPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent, + ll->positions[indicPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine); + // RESET control var + startPos = -1; + } + } + } + mask <<= 1; + } + } + + for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) { + if (under == vsDraw.indicators[deco->indicator].under) { + int startPos = posLineStart + lineStart; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { + int endPos = deco->rs.EndRun(startPos); + if (endPos > posLineEnd) + endPos = posLineEnd; + PRectangle rcIndic( + ll->positions[startPos - posLineStart] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent, + ll->positions[endPos - posLineStart] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine); + startPos = deco->rs.EndRun(endPos); + } + } + } +} + +void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment, + const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) { + if (!twoPhaseDraw) { + surface->FillRectangle(rcSegment, textBack); + } + Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; + int normalCharHeight = surface->Ascent(ctrlCharsFont) - + surface->InternalLeading(ctrlCharsFont); + PRectangle rcCChar = rcSegment; + rcCChar.left = rcCChar.left + 1; + rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; + rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; + PRectangle rcCentral = rcCChar; + rcCentral.top++; + rcCentral.bottom--; + surface->FillRectangle(rcCentral, textFore); + PRectangle rcChar = rcCChar; + rcChar.left++; + rcChar.right--; + surface->DrawTextClipped(rcChar, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, s, istrlen(s), + textBack, textFore); +} + +void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine) { + int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth; + PRectangle rcSegment = rcLine; + int annotationLine = subLine - ll->lines; + const StyledText stAnnotation = pdoc->AnnotationStyledText(line); + if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { + surface->FillRectangle(rcSegment, vsDraw.styles[0].back.allocated); + if (vs.annotationVisible == ANNOTATION_BOXED) { + // Only care about calculating width if need to draw box + int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); + widthAnnotation += vsDraw.spaceWidth * 2; // Margins + rcSegment.left = xStart + indent; + rcSegment.right = rcSegment.left + widthAnnotation; + surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore.allocated); + } else { + rcSegment.left = xStart; + } + const int annotationLines = pdoc->AnnotationLines(line); + size_t start = 0; + size_t lengthAnnotation = stAnnotation.LineLength(start); + int lineInAnnotation = 0; + while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { + start += lengthAnnotation + 1; + lengthAnnotation = stAnnotation.LineLength(start); + lineInAnnotation++; + } + PRectangle rcText = rcSegment; + if (vs.annotationVisible == ANNOTATION_BOXED) { + surface->FillRectangle(rcText, + vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back.allocated); + rcText.left += vsDraw.spaceWidth; + } + DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent, + stAnnotation, start, lengthAnnotation); + if (vs.annotationVisible == ANNOTATION_BOXED) { + surface->MoveTo(rcSegment.left, rcSegment.top); + surface->LineTo(rcSegment.left, rcSegment.bottom); + surface->MoveTo(rcSegment.right, rcSegment.top); + surface->LineTo(rcSegment.right, rcSegment.bottom); + if (subLine == ll->lines){ + surface->MoveTo(rcSegment.left, rcSegment.top); + surface->LineTo(rcSegment.right, rcSegment.top); + } + if (subLine == ll->lines+annotationLines-1) { + surface->MoveTo(rcSegment.left, rcSegment.bottom - 1); + surface->LineTo(rcSegment.right, rcSegment.bottom - 1); + } + } + } +} + +void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine) { + + PRectangle rcSegment = rcLine; + + // Using one font for all control characters so it can be controlled independently to ensure + // the box goes around the characters tightly. Seems to be no way to work out what height + // is taken by an individual character - internal leading gives varying results. + Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; + + // See if something overrides the line background color: Either if caret is on the line + // and background color is set for that, or if a marker is defined that forces its background + // color onto the line, or if a marker is defined but has no selection margin in which to + // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order + // with the earlier taking precedence. When multiple markers cause background override, + // the color for the highest numbered one is used. + bool overrideBackground = false; + ColourAllocated background; + if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) { + overrideBackground = true; + background = vsDraw.caretLineBackground.allocated; + } + if (!overrideBackground) { + int marks = pdoc->GetMark(line); + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) && + (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { + background = vsDraw.markers[markBit].back.allocated; + overrideBackground = true; + } + marks >>= 1; + } + } + if (!overrideBackground) { + if (vsDraw.maskInLine) { + int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; + if (marksMasked) { + for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) { + if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) && + (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { + overrideBackground = true; + background = vsDraw.markers[markBit].back.allocated; + } + marksMasked >>= 1; + } + } + } + } + + bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) && + (!overrideBackground) && (vsDraw.whitespaceBackgroundSet); + + bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. + int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth; + + int posLineStart = pdoc->LineStart(line); + + int startseg = ll->LineStart(subLine); + int subLineStart = ll->positions[startseg]; + if (subLine >= ll->lines) { + DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine); + return; // No further drawing + } + int lineStart = 0; + int lineEnd = 0; + if (subLine < ll->lines) { + lineStart = ll->LineStart(subLine); + lineEnd = ll->LineStart(subLine + 1); + } + + ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated; + if (vsDraw.whitespaceForegroundSet) + wrapColour = vsDraw.whitespaceForeground.allocated; + + bool drawWrapMarkEnd = false; + + if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + if (subLine + 1 < ll->lines) { + drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; + } + } + + if (actualWrapVisualStartIndent != 0) { + + bool continuedWrapLine = false; + if (subLine < ll->lines) { + continuedWrapLine = ll->LineStart(subLine) != 0; + } + + if (continuedWrapLine) { + // draw continuation rect + PRectangle rcPlace = rcSegment; + + rcPlace.left = ll->positions[startseg] + xStart - subLineStart; + rcPlace.right = rcPlace.left + actualWrapVisualStartIndent * vsDraw.aveCharWidth; + + // default bgnd here.. + surface->FillRectangle(rcSegment, overrideBackground ? background : + vsDraw.styles[STYLE_DEFAULT].back.allocated); + + // main line style would be below but this would be inconsistent with end markers + // also would possibly not be the style at wrap point + //int styleMain = ll->styles[lineStart]; + //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back.allocated); + + if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) { + + if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT) + rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; + else + rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; + + DrawWrapMarker(surface, rcPlace, false, wrapColour); + } + + xStart += actualWrapVisualStartIndent * vsDraw.aveCharWidth; + } + } + + // Does not take margin into account but not significant + int xStartVisible = subLineStart - xStart; + + BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible); + int next = bfBack.First(); + + // Background drawing loop + while (twoPhaseDraw && (next < lineEnd)) { + + startseg = next; + next = bfBack.Next(); + int i = next - 1; + int iDoc = i + posLineStart; + + rcSegment.left = ll->positions[startseg] + xStart - subLineStart; + rcSegment.right = ll->positions[i + 1] + xStart - subLineStart; + // Only try to draw if really visible - enhances performance by not calling environment to + // draw strings that are completely past the right side of the window. + if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { + // Clip to line rectangle, since may have a huge position which will not work with some platforms + rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left); + rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right); + + int styleMain = ll->styles[i]; + bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd); + bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); + ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); + if (ll->chars[i] == '\t') { + // Tab display + if (drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) + textBack = vsDraw.whitespaceBackground.allocated; + surface->FillRectangle(rcSegment, textBack); + } else if (IsControlCharacter(ll->chars[i])) { + // Control character display + inIndentation = false; + surface->FillRectangle(rcSegment, textBack); + } else { + // Normal text display + surface->FillRectangle(rcSegment, textBack); + if (vsDraw.viewWhitespace != wsInvisible || + (inIndentation && vsDraw.viewIndentationGuides == ivReal)) { + for (int cpos = 0; cpos <= i - startseg; cpos++) { + if (ll->chars[cpos + startseg] == ' ') { + if (drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { + PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, + rcSegment.top, + ll->positions[cpos + startseg + 1] + xStart - subLineStart, + rcSegment.bottom); + surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated); + } + } else { + inIndentation = false; + } + } + } + } + } else if (rcSegment.left > rcLine.right) { + break; + } + } + + if (twoPhaseDraw) { + DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, + xStart, subLine, subLineStart, overrideBackground, background, + drawWrapMarkEnd, wrapColour); + } + + DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true); + + if (vsDraw.edgeState == EDGE_LINE) { + int edgeX = theEdge * vsDraw.spaceWidth; + rcSegment.left = edgeX + xStart; + rcSegment.right = rcSegment.left + 1; + surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated); + } + + inIndentation = subLine == 0; // Do not handle indentation except on first subline. + // Foreground drawing loop + BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible); + next = bfFore.First(); + + while (next < lineEnd) { + + startseg = next; + next = bfFore.Next(); + int i = next - 1; + + int iDoc = i + posLineStart; + + rcSegment.left = ll->positions[startseg] + xStart - subLineStart; + rcSegment.right = ll->positions[i + 1] + xStart - subLineStart; + // Only try to draw if really visible - enhances performance by not calling environment to + // draw strings that are completely past the right side of the window. + if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { + int styleMain = ll->styles[i]; + ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated; + Font &textFont = vsDraw.styles[styleMain].font; + //hotspot foreground + if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) { + if (vsDraw.hotspotForegroundSet) + textFore = vsDraw.hotspotForeground.allocated; + } + bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd); + if (inSelection && (vsDraw.selforeset)) { + textFore = vsDraw.selforeground.allocated; + } + bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); + ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); + if (ll->chars[i] == '\t') { + // Tab display + if (!twoPhaseDraw) { + if (drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) + textBack = vsDraw.whitespaceBackground.allocated; + surface->FillRectangle(rcSegment, textBack); + } + if ((vsDraw.viewWhitespace != wsInvisible) || + (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { + if (vsDraw.whitespaceForegroundSet) + textFore = vsDraw.whitespaceForeground.allocated; + surface->PenColour(textFore); + } + if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { + for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) { + if (xIG >= ll->positions[i] && xIG > 0) { + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment, + (ll->xHighlightGuide == xIG)); + } + } + } + if (vsDraw.viewWhitespace != wsInvisible) { + if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { + PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, + rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); + DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); + } + } + } else if (IsControlCharacter(ll->chars[i])) { + // Control character display + inIndentation = false; + if (controlCharSymbol < 32) { + // Draw the character + const char *ctrlChar = ControlCharacterString(ll->chars[i]); + DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); + } else { + char cc[2] = { static_cast(controlCharSymbol), '\0' }; + surface->DrawTextNoClip(rcSegment, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, + cc, 1, textBack, textFore); + } + } else if ((i == startseg) && (static_cast(ll->chars[i]) >= 0x80) && IsUnicodeMode()) { + char hexits[3]; + sprintf(hexits, "%2X", ll->chars[i] & 0xff); + DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw); + } else { + // Normal text display + if (vsDraw.styles[styleMain].visible) { + if (twoPhaseDraw) { + surface->DrawTextTransparent(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, + i - startseg + 1, textFore); + } else { + surface->DrawTextNoClip(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, + i - startseg + 1, textFore, textBack); + } + } + if (vsDraw.viewWhitespace != wsInvisible || + (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { + for (int cpos = 0; cpos <= i - startseg; cpos++) { + if (ll->chars[cpos + startseg] == ' ') { + if (vsDraw.viewWhitespace != wsInvisible) { + if (vsDraw.whitespaceForegroundSet) + textFore = vsDraw.whitespaceForeground.allocated; + if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { + int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2; + if (!twoPhaseDraw && drawWhitespaceBackground && + (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { + textBack = vsDraw.whitespaceBackground.allocated; + PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, + rcSegment.top, + ll->positions[cpos + startseg + 1] + xStart - subLineStart, + rcSegment.bottom); + surface->FillRectangle(rcSpace, textBack); + } + PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); + rcDot.right = rcDot.left + 1; + rcDot.bottom = rcDot.top + 1; + surface->FillRectangle(rcDot, textFore); + } + } + if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { + int startSpace = ll->positions[cpos + startseg]; + if (startSpace > 0 && (startSpace % indentWidth == 0)) { + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment, + (ll->xHighlightGuide == ll->positions[cpos + startseg])); + } + } + } else { + inIndentation = false; + } + } + } + } + if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) { + PRectangle rcUL = rcSegment; + rcUL.top = rcUL.top + vsDraw.maxAscent + 1; + rcUL.bottom = rcUL.top + 1; + if (vsDraw.hotspotForegroundSet) + surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated); + else + surface->FillRectangle(rcUL, textFore); + } else if (vsDraw.styles[styleMain].underline) { + PRectangle rcUL = rcSegment; + rcUL.top = rcUL.top + vsDraw.maxAscent + 1; + rcUL.bottom = rcUL.top + 1; + surface->FillRectangle(rcUL, textFore); + } + } else if (rcSegment.left > rcLine.right) { + break; + } + } + if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) + && (subLine == 0)) { + int indentSpace = pdoc->GetLineIndentation(line); + // Find the most recent line with some text + + int lineLastWithText = line; + while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) { + lineLastWithText--; + } + if (lineLastWithText < line) { + // This line is empty, so use indentation of last line with text + int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText); + int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; + if (isFoldHeader) { + // Level is one more level than parent + indentLastWithText += pdoc->IndentSize(); + } + if (vsDraw.viewIndentationGuides == ivLookForward) { + // In viLookForward mode, previous line only used if it is a fold header + if (isFoldHeader) { + indentSpace = Platform::Maximum(indentSpace, indentLastWithText); + } + } else { // viLookBoth + indentSpace = Platform::Maximum(indentSpace, indentLastWithText); + } + } + + int lineNextWithText = line; + while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) { + lineNextWithText++; + } + if (lineNextWithText > line) { + // This line is empty, so use indentation of last line with text + indentSpace = Platform::Maximum(indentSpace, + pdoc->GetLineIndentation(lineNextWithText)); + } + + for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) { + int xIndent = indentPos * vsDraw.spaceWidth; + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, + (ll->xHighlightGuide == xIndent)); + } + } + + DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false); + + // End of the drawing of the current line + if (!twoPhaseDraw) { + DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, + xStart, subLine, subLineStart, overrideBackground, background, + drawWrapMarkEnd, wrapColour); + } + if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) && (ll->selStart >= 0) && (ll->selEnd >= 0)) { + int startPosSel = (ll->selStart < posLineStart) ? posLineStart : ll->selStart; + int endPosSel = (ll->selEnd < (lineEnd + posLineStart)) ? ll->selEnd : (lineEnd + posLineStart); + if (startPosSel < endPosSel) { + rcSegment.left = xStart + ll->positions[startPosSel - posLineStart] - subLineStart; + rcSegment.right = xStart + ll->positions[endPosSel - posLineStart] - subLineStart; + rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left); + rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right); + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); + } + } + + // Draw any translucent whole line states + rcSegment.left = xStart; + rcSegment.right = rcLine.right - 1; + if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) { + SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha); + } + int marks = pdoc->GetMark(line); + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) { + SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha); + } + marks >>= 1; + } + if (vsDraw.maskInLine) { + int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; + if (marksMasked) { + for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) { + if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) { + SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha); + } + marksMasked >>= 1; + } + } + } +} + +void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret) { + + int lineStart = ll->LineStart(subLine); + int posBefore = posCaret; + int posAfter = MovePositionOutsideChar(posCaret + 1, 1); + int numCharsToDraw = posAfter - posCaret; + + // Work out where the starting and ending offsets are. We need to + // see if the previous character shares horizontal space, such as a + // glyph / combining character. If so we'll need to draw that too. + int offsetFirstChar = offset; + int offsetLastChar = offset + (posAfter - posCaret); + while ((offsetLastChar - numCharsToDraw) >= lineStart) { + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + // Update posBefore to point to the prev char + posBefore = MovePositionOutsideChar(posBefore - 1, -1); + numCharsToDraw = posAfter - posBefore; + offsetFirstChar = offset - (posCaret - posBefore); + } + + // See if the next character shares horizontal space, if so we'll + // need to draw that too. + numCharsToDraw = offsetLastChar - offsetFirstChar; + while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { + // Update posAfter to point to the 2nd next char, this is where + // the next character ends, and 2nd next begins. We'll need + // to compare these two + posBefore = posAfter; + posAfter = MovePositionOutsideChar(posAfter + 1, 1); + offsetLastChar = offset + (posAfter - posCaret); + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + numCharsToDraw = offsetLastChar - offsetFirstChar; + } + + // We now know what to draw, update the caret drawing rectangle + rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; + rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart; + + // Adjust caret position to take into account any word wrapping symbols. + if ((actualWrapVisualStartIndent != 0) && (lineStart != 0)) { + int wordWrapCharWidth = actualWrapVisualStartIndent * vs.aveCharWidth; + rcCaret.left += wordWrapCharWidth; + rcCaret.right += wordWrapCharWidth; + } + + // This character is where the caret block is, we override the colours + // (inversed) for drawing the caret here. + int styleMain = ll->styles[offsetFirstChar]; + surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font, + rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, + numCharsToDraw, vsDraw.styles[styleMain].back.allocated, + vsDraw.caretcolour.allocated); +} + +void Editor::RefreshPixMaps(Surface *surfaceWindow) { + if (!pixmapSelPattern->Initialised()) { + const int patternSize = 8; + pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID()); + // This complex procedure is to reproduce the checkerboard dithered pattern used by windows + // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half + // way between the chrome colour and the chrome highlight colour making a nice transition + // between the window chrome and the content area. And it works in low colour depths. + PRectangle rcPattern(0, 0, patternSize, patternSize); + + // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. + ColourAllocated colourFMFill = vs.selbar.allocated; + ColourAllocated colourFMStripes = vs.selbarlight.allocated; + + if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) { + // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. + // (Typically, the highlight colour is white.) + colourFMFill = vs.selbarlight.allocated; + } + + if (vs.foldmarginColourSet) { + // override default fold margin colour + colourFMFill = vs.foldmarginColour.allocated; + } + if (vs.foldmarginHighlightColourSet) { + // override default fold margin highlight colour + colourFMStripes = vs.foldmarginHighlightColour.allocated; + } + + pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); + pixmapSelPattern->PenColour(colourFMStripes); + for (int stripe = 0; stripe < patternSize; stripe++) { + // Alternating 1 pixel stripes is same as checkerboard. + pixmapSelPattern->MoveTo(0, stripe * 2); + pixmapSelPattern->LineTo(patternSize, stripe * 2 - patternSize); + } + } + + if (!pixmapIndentGuide->Initialised()) { + // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line + pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); + pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); + PRectangle rcIG(0, 0, 1, vs.lineHeight); + pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated); + pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated); + pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated); + pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated); + for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) { + pixmapIndentGuide->MoveTo(0, stripe); + pixmapIndentGuide->LineTo(2, stripe); + pixmapIndentGuideHighlight->MoveTo(0, stripe); + pixmapIndentGuideHighlight->LineTo(2, stripe); + } + } + + if (bufferedDraw) { + if (!pixmapLine->Initialised()) { + PRectangle rcClient = GetClientRectangle(); + pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight, + surfaceWindow, wMain.GetID()); + pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, + rcClient.Height(), surfaceWindow, wMain.GetID()); + } + } +} + +void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { + //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", + // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + + pixmapLine->Release(); + RefreshStyleData(); + RefreshPixMaps(surfaceWindow); + + PRectangle rcClient = GetClientRectangle(); + //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", + // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); + + surfaceWindow->SetPalette(&palette, true); + pixmapLine->SetPalette(&palette, !hasFocus); + + int screenLinePaintFirst = rcArea.top / vs.lineHeight; + // The area to be painted plus one extra line is styled. + // The extra line is to determine when a style change, such as starting a comment flows on to other lines. + int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1; + //Platform::DebugPrintf("Paint lines = %d .. %d\n", topLine + screenLinePaintFirst, lineStyleLast); + int endPosPaint = pdoc->Length(); + if (lineStyleLast < cs.LinesDisplayed()) + endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast) + 1); + + int xStart = vs.fixedColumnWidth - xOffset; + int ypos = 0; + if (!bufferedDraw) + ypos += screenLinePaintFirst * vs.lineHeight; + int yposScreen = screenLinePaintFirst * vs.lineHeight; + + // Ensure we are styled as far as we are painting. + pdoc->EnsureStyledTo(endPosPaint); + bool paintAbandonedByStyling = paintState == paintAbandoned; + if (needUpdateUI) { + // Deselect palette by selecting a temporary palette + Palette palTemp; + surfaceWindow->SetPalette(&palTemp, true); + + NotifyUpdateUI(); + needUpdateUI = false; + + RefreshStyleData(); + RefreshPixMaps(surfaceWindow); + surfaceWindow->SetPalette(&palette, true); + pixmapLine->SetPalette(&palette, !hasFocus); + } + + // Call priority lines wrap on a window of lines which are likely + // to rendered with the following paint (that is wrap the visible + // lines first). + int startLineToWrap = cs.DocFromDisplay(topLine) - 5; + if (startLineToWrap < 0) + startLineToWrap = -1; + if (WrapLines(false, startLineToWrap)) { + // The wrapping process has changed the height of some lines so + // abandon this paint for a complete repaint. + if (AbandonPaint()) { + return; + } + RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change + } + PLATFORM_ASSERT(pixmapSelPattern->Initialised()); + + PaintSelMargin(surfaceWindow, rcArea); + + PRectangle rcRightMargin = rcClient; + rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; + if (rcArea.Intersects(rcRightMargin)) { + surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated); + } + + if (paintState == paintAbandoned) { + // Either styling or NotifyUpdateUI noticed that painting is needed + // outside the current painting rectangle + //Platform::DebugPrintf("Abandoning paint\n"); + if (wrapState != eWrapNone) { + if (paintAbandonedByStyling) { + // Styling has spilled over a line end, such as occurs by starting a multiline + // comment. The width of subsequent text may have changed, so rewrap. + NeedWrapping(cs.DocFromDisplay(topLine)); + } + } + return; + } + //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); + + // Do the painting + if (rcArea.right > vs.fixedColumnWidth) { + + Surface *surface = surfaceWindow; + if (bufferedDraw) { + surface = pixmapLine; + PLATFORM_ASSERT(pixmapLine->Initialised()); + } + surface->SetUnicodeMode(IsUnicodeMode()); + surface->SetDBCSMode(CodePage()); + + int visibleLine = topLine + screenLinePaintFirst; + + int posCaret = currentPos; + if (posDrag >= 0) + posCaret = posDrag; + int lineCaret = pdoc->LineFromPosition(posCaret); + + // Remove selection margin from drawing area so text will not be drawn + // on it in unbuffered mode. + PRectangle rcTextArea = rcClient; + rcTextArea.left = vs.fixedColumnWidth; + rcTextArea.right -= vs.rightMarginWidth; + surfaceWindow->SetClip(rcTextArea); + + // Loop on visible lines + //double durLayout = 0.0; + //double durPaint = 0.0; + //double durCopy = 0.0; + //ElapsedTime etWhole; + int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times + AutoLineLayout ll(llc, 0); + SelectionLineIterator lineIterator(this); + while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) { + + int lineDoc = cs.DocFromDisplay(visibleLine); + // Only visible lines should be handled by the code within the loop + PLATFORM_ASSERT(cs.GetVisible(lineDoc)); + int lineStartSet = cs.DisplayFromDoc(lineDoc); + int subLine = visibleLine - lineStartSet; + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + //ElapsedTime et; + if (lineDoc != lineDocPrevious) { + ll.Set(0); + // For rectangular selection this accesses the layout cache so should be after layout returned. + lineIterator.SetAt(lineDoc); + ll.Set(RetrieveLineLayout(lineDoc)); + LayoutLine(lineDoc, surface, vs, ll, wrapWidth); + lineDocPrevious = lineDoc; + } + //durLayout += et.Duration(true); + + if (ll) { + if (selType == selStream) { + ll->selStart = SelectionStart(); + ll->selEnd = SelectionEnd(); + } else { + ll->selStart = lineIterator.startPos; + ll->selEnd = lineIterator.endPos; + } + ll->containsCaret = lineDoc == lineCaret; + if (hideSelection) { + ll->selStart = -1; + ll->selEnd = -1; + ll->containsCaret = false; + } + + GetHotSpotRange(ll->hsStart, ll->hsEnd); + + PRectangle rcLine = rcClient; + rcLine.top = ypos; + rcLine.bottom = ypos + vs.lineHeight; + + Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1)); + // Highlight the current braces if any + ll->SetBracesHighlight(rangeLine, braces, static_cast(bracesMatchStyle), + highlightGuideColumn * vs.spaceWidth); + + // Draw the line + DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine); + //durPaint += et.Duration(true); + + // Restore the previous styles for the brace highlights in case layout is in cache. + ll->RestoreBracesHighlight(rangeLine, braces); + + bool expanded = cs.GetExpanded(lineDoc); +#ifdef INCLUDE_DEPRECATED_FEATURES + if ((foldFlags & SC_FOLDFLAG_BOX) == 0) { +#endif + // Paint the line above the fold + if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { + if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.bottom = rcFoldLine.top + 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } + // Paint the line below the fold + if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { + if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.top = rcFoldLine.bottom - 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } +#ifdef INCLUDE_DEPRECATED_FEATURES + } else { + int FoldLevelCurr = (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE; + int FoldLevelPrev = (pdoc->GetLevel(lineDoc - 1) & SC_FOLDLEVELNUMBERMASK) - SC_FOLDLEVELBASE; + int FoldLevelFlags = (pdoc->GetLevel(lineDoc) & ~SC_FOLDLEVELNUMBERMASK) & ~(0xFFF0000); + int indentationStep = pdoc->IndentSize(); + // Draw line above fold + if ((FoldLevelPrev < FoldLevelCurr) + || + (FoldLevelFlags & SC_FOLDLEVELBOXHEADERFLAG + && + (pdoc->GetLevel(lineDoc - 1) & SC_FOLDLEVELBOXFOOTERFLAG) == 0)) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.bottom = rcFoldLine.top + 1; + rcFoldLine.left += xStart + FoldLevelCurr * vs.spaceWidth * indentationStep - 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + + // Line below the fold (or below a contracted fold) + if (FoldLevelFlags & SC_FOLDLEVELBOXFOOTERFLAG + || + (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.top = rcFoldLine.bottom - 1; + rcFoldLine.left += xStart + (FoldLevelCurr) * vs.spaceWidth * indentationStep - 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + + PRectangle rcBoxLine = rcLine; + // Draw vertical line for every fold level + for (int i = 0; i <= FoldLevelCurr; i++) { + rcBoxLine.left = xStart + i * vs.spaceWidth * indentationStep - 1; + rcBoxLine.right = rcBoxLine.left + 1; + surface->FillRectangle(rcBoxLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } +#endif + + // Draw the Caret + if (lineDoc == lineCaret) { + int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength); + if (ll->InLine(offset, subLine)) { + int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart; + + if (actualWrapVisualStartIndent != 0) { + int lineStart = ll->LineStart(subLine); + if (lineStart != 0) // Wrapped + xposCaret += actualWrapVisualStartIndent * vs.aveCharWidth; + } + if ((xposCaret >= 0) && (vs.caretWidth > 0) && (vs.caretStyle != CARETSTYLE_INVISIBLE) && + ((posDrag >= 0) || (caret.active && caret.on))) { + bool caretAtEOF = false; + bool caretAtEOL = false; + bool drawBlockCaret = false; + int widthOverstrikeCaret; + int caretWidthOffset = 0; + PRectangle rcCaret = rcLine; + + if (posCaret == pdoc->Length()) { // At end of document + caretAtEOF = true; + widthOverstrikeCaret = vs.aveCharWidth; + } else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) { // At end of line + caretAtEOL = true; + widthOverstrikeCaret = vs.aveCharWidth; + } else { + widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset]; + } + if (widthOverstrikeCaret < 3) // Make sure its visible + widthOverstrikeCaret = 3; + + if (offset > ll->LineStart(subLine)) + caretWidthOffset = 1; // Move back so overlaps both character cells. + if (posDrag >= 0) { + /* Dragging text, use a line caret */ + rcCaret.left = xposCaret - caretWidthOffset; + rcCaret.right = rcCaret.left + vs.caretWidth; + } else if (inOverstrike) { + /* Overstrike (insert mode), use a modified bar caret */ + rcCaret.top = rcCaret.bottom - 2; + rcCaret.left = xposCaret + 1; + rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; + } else if (vs.caretStyle == CARETSTYLE_BLOCK) { + /* Block caret */ + rcCaret.left = xposCaret; + if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { + drawBlockCaret = true; + rcCaret.right = xposCaret + widthOverstrikeCaret; + } else { + rcCaret.right = xposCaret + vs.aveCharWidth; + } + } else { + /* Line caret */ + rcCaret.left = xposCaret - caretWidthOffset; + rcCaret.right = rcCaret.left + vs.caretWidth; + } + if (drawBlockCaret) { + DrawBlockCaret(surface, vs, ll, subLine, xStart, offset, posCaret, rcCaret); + } else { + surface->FillRectangle(rcCaret, vs.caretcolour.allocated); + } + } + } + } + + if (bufferedDraw) { + Point from(vs.fixedColumnWidth, 0); + PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen, + rcClient.right, yposScreen + vs.lineHeight); + surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); + } + //durCopy += et.Duration(true); + } + + if (!bufferedDraw) { + ypos += vs.lineHeight; + } + + yposScreen += vs.lineHeight; + visibleLine++; + + lineWidthMaxSeen = Platform::Maximum( + lineWidthMaxSeen, ll->positions[ll->numCharsInLine]); + //gdk_flush(); + } + ll.Set(0); + //if (durPaint < 0.00000001) + // durPaint = 0.00000001; + + // Right column limit indicator + PRectangle rcBeyondEOF = rcClient; + rcBeyondEOF.left = vs.fixedColumnWidth; + rcBeyondEOF.right = rcBeyondEOF.right; + rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight; + if (rcBeyondEOF.top < rcBeyondEOF.bottom) { + surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated); + if (vs.edgeState == EDGE_LINE) { + int edgeX = theEdge * vs.spaceWidth; + rcBeyondEOF.left = edgeX + xStart; + rcBeyondEOF.right = rcBeyondEOF.left + 1; + surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated); + } + } + //Platform::DebugPrintf( + //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n", + //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration()); + NotifyPainted(); + } +} + +// Space (3 space characters) between line numbers and text when printing. +#define lineNumberPrintSpace " " + +ColourDesired InvertedLight(ColourDesired orig) { + unsigned int r = orig.GetRed(); + unsigned int g = orig.GetGreen(); + unsigned int b = orig.GetBlue(); + unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye + unsigned int il = 0xff - l; + if (l == 0) + return ColourDesired(0xff, 0xff, 0xff); + r = r * il / l; + g = g * il / l; + b = b * il / l; + return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff)); +} + +// This is mostly copied from the Paint method but with some things omitted +// such as the margin markers, line numbers, selection and caret +// Should be merged back into a combined Draw method. +long Editor::FormatRange(bool draw, RangeToFormat *pfr) { + if (!pfr) + return 0; + + AutoSurface surface(pfr->hdc, this); + if (!surface) + return 0; + AutoSurface surfaceMeasure(pfr->hdcTarget, this); + if (!surfaceMeasure) { + return 0; + } + + // Can't use measurements cached for screen + posCache.Clear(); + + ViewStyle vsPrint(vs); + + // Modify the view style for printing as do not normally want any of the transient features to be printed + // Printing supports only the line number margin. + int lineNumberIndex = -1; + for (int margin = 0; margin < ViewStyle::margins; margin++) { + if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) { + lineNumberIndex = margin; + } else { + vsPrint.ms[margin].width = 0; + } + } + vsPrint.showMarkedLines = false; + vsPrint.fixedColumnWidth = 0; + vsPrint.zoomLevel = printMagnification; + vsPrint.viewIndentationGuides = ivNone; + // Don't show the selection when printing + vsPrint.selbackset = false; + vsPrint.selforeset = false; + vsPrint.selAlpha = SC_ALPHA_NOALPHA; + vsPrint.whitespaceBackgroundSet = false; + vsPrint.whitespaceForegroundSet = false; + vsPrint.showCaretLineBackground = false; + + // Set colours for printing according to users settings + for (size_t sty = 0;sty < vsPrint.stylesSize;sty++) { + if (printColourMode == SC_PRINT_INVERTLIGHT) { + vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired); + vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired); + } else if (printColourMode == SC_PRINT_BLACKONWHITE) { + vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0); + vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff); + } else if (printColourMode == SC_PRINT_COLOURONWHITE) { + vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff); + } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) { + if (sty <= STYLE_DEFAULT) { + vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff); + } + } + } + // White background for the line numbers + vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff); + + vsPrint.Refresh(*surfaceMeasure); + // Determining width must hapen after fonts have been realised in Refresh + int lineNumberWidth = 0; + if (lineNumberIndex >= 0) { + lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, + "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace)); + vsPrint.ms[lineNumberIndex].width = lineNumberWidth; + vsPrint.Refresh(*surfaceMeasure); // Recalculate fixedColumnWidth + } + // Ensure colours are set up + vsPrint.RefreshColourPalette(palette, true); + vsPrint.RefreshColourPalette(palette, false); + + int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin); + int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; + if (linePrintLast < linePrintStart) + linePrintLast = linePrintStart; + int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax); + if (linePrintLast > linePrintMax) + linePrintLast = linePrintMax; + //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", + // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, + // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); + int endPosPrint = pdoc->Length(); + if (linePrintLast < pdoc->LinesTotal()) + endPosPrint = pdoc->LineStart(linePrintLast + 1); + + // Ensure we are styled to where we are formatting. + pdoc->EnsureStyledTo(endPosPrint); + + int xStart = vsPrint.fixedColumnWidth + pfr->rc.left; + int ypos = pfr->rc.top; + + int lineDoc = linePrintStart; + + int nPrintPos = pfr->chrg.cpMin; + int visibleLine = 0; + int widthPrint = pfr->rc.Width() - vsPrint.fixedColumnWidth; + if (printWrapState == eWrapNone) + widthPrint = LineLayout::wrapWidthInfinite; + + while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) { + + // When printing, the hdc and hdcTarget may be the same, so + // changing the state of surfaceMeasure may change the underlying + // state of surface. Therefore, any cached state is discarded before + // using each surface. + surfaceMeasure->FlushCachedState(); + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + LineLayout ll(8000); + LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); + + ll.selStart = -1; + ll.selEnd = -1; + ll.containsCaret = false; + + PRectangle rcLine; + rcLine.left = pfr->rc.left; + rcLine.top = ypos; + rcLine.right = pfr->rc.right - 1; + rcLine.bottom = ypos + vsPrint.lineHeight; + + // When document line is wrapped over multiple display lines, find where + // to start printing from to ensure a particular position is on the first + // line of the page. + if (visibleLine == 0) { + int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc); + for (int iwl = 0; iwl < ll.lines - 1; iwl++) { + if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) { + visibleLine = -iwl; + } + } + + if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) { + visibleLine = -(ll.lines - 1); + } + } + + if (draw && lineNumberWidth && + (ypos + vsPrint.lineHeight <= pfr->rc.bottom) && + (visibleLine >= 0)) { + char number[100]; + sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1); + PRectangle rcNumber = rcLine; + rcNumber.right = rcNumber.left + lineNumberWidth; + // Right justify + rcNumber.left = rcNumber.right - surfaceMeasure->WidthText( + vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number)); + surface->FlushCachedState(); + surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, + ypos + vsPrint.maxAscent, number, istrlen(number), + vsPrint.styles[STYLE_LINENUMBER].fore.allocated, + vsPrint.styles[STYLE_LINENUMBER].back.allocated); + } + + // Draw the line + surface->FlushCachedState(); + + for (int iwl = 0; iwl < ll.lines; iwl++) { + if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) { + if (visibleLine >= 0) { + if (draw) { + rcLine.top = ypos; + rcLine.bottom = ypos + vsPrint.lineHeight; + DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl); + } + ypos += vsPrint.lineHeight; + } + visibleLine++; + if (iwl == ll.lines - 1) + nPrintPos = pdoc->LineStart(lineDoc + 1); + else + nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl); + } + } + + ++lineDoc; + } + + // Clear cache so measurements are not used for screen + posCache.Clear(); + + return nPrintPos; +} + +int Editor::TextWidth(int style, const char *text) { + RefreshStyleData(); + AutoSurface surface(this); + if (surface) { + return surface->WidthText(vs.styles[style].font, text, istrlen(text)); + } else { + return 1; + } +} + +// Empty method is overridden on GTK+ to show / hide scrollbars +void Editor::ReconfigureScrollBars() {} + +void Editor::SetScrollBars() { + RefreshStyleData(); + + int nMax = MaxScrollPos(); + int nPage = LinesOnScreen(); + bool modified = ModifyScrollBars(nMax + nPage - 1, nPage); + if (modified) { + DwellEnd(true); + } + + // TODO: ensure always showing as many lines as possible + // May not be, if, for example, window made larger + if (topLine > MaxScrollPos()) { + SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + if (modified) { + if (!AbandonPaint()) + Redraw(); + } + //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); +} + +void Editor::ChangeSize() { + DropGraphics(); + SetScrollBars(); + if (wrapState != eWrapNone) { + PRectangle rcTextArea = GetClientRectangle(); + rcTextArea.left = vs.fixedColumnWidth; + rcTextArea.right -= vs.rightMarginWidth; + if (wrapWidth != rcTextArea.Width()) { + NeedWrapping(); + Redraw(); + } + } +} + +void Editor::AddChar(char ch) { + char s[2]; + s[0] = ch; + s[1] = '\0'; + AddCharUTF(s, 1); +} + +// AddCharUTF inserts an array of bytes which may or may not be in UTF-8. +void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { + bool wasSelection = currentPos != anchor; + ClearSelection(); + bool charReplaceAction = false; + if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) { + if (currentPos < (pdoc->Length())) { + if (!IsEOLChar(pdoc->CharAt(currentPos))) { + charReplaceAction = true; + pdoc->BeginUndoAction(); + pdoc->DelChar(currentPos); + } + } + } + if (pdoc->InsertString(currentPos, s, len)) { + SetEmptySelection(currentPos + len); + } + if (charReplaceAction) { + pdoc->EndUndoAction(); + } + // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information + if (wrapState != eWrapNone) { + AutoSurface surface(this); + if (surface) { + WrapOneLine(surface, pdoc->LineFromPosition(currentPos)); + } + SetScrollBars(); + } + EnsureCaretVisible(); + // Avoid blinking during rapid typing: + ShowCaretAtCurrentPosition(); + if (!caretSticky) { + SetLastXChosen(); + } + + if (treatAsDBCS) { + NotifyChar((static_cast(s[0]) << 8) | + static_cast(s[1])); + } else { + int byte = static_cast(s[0]); + if ((byte < 0xC0) || (1 == len)) { + // Handles UTF-8 characters between 0x01 and 0x7F and single byte + // characters when not in UTF-8 mode. + // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid + // characters representing themselves. + } else { + // Unroll 1 to 3 byte UTF-8 sequences. See reference data at: + // http://www.cl.cam.ac.uk/~mgk25/unicode.html + // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + if (byte < 0xE0) { + int byte2 = static_cast(s[1]); + if ((byte2 & 0xC0) == 0x80) { + // Two-byte-character lead-byte followed by a trail-byte. + byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F)); + } + // A two-byte-character lead-byte not followed by trail-byte + // represents itself. + } else if (byte < 0xF0) { + int byte2 = static_cast(s[1]); + int byte3 = static_cast(s[2]); + if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) { + // Three-byte-character lead byte followed by two trail bytes. + byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | + (byte3 & 0x3F)); + } + // A three-byte-character lead-byte not followed by two trail-bytes + // represents itself. + } + } + NotifyChar(byte); + } +} + +void Editor::ClearSelection() { + if (!SelectionContainsProtected()) { + int startPos = SelectionStart(); + if (selType == selStream) { + unsigned int chars = SelectionEnd() - startPos; + if (0 != chars) { + pdoc->BeginUndoAction(); + pdoc->DeleteChars(startPos, chars); + pdoc->EndUndoAction(); + } + } else { + pdoc->BeginUndoAction(); + SelectionLineIterator lineIterator(this, false); + while (lineIterator.Iterate()) { + startPos = lineIterator.startPos; + unsigned int chars = lineIterator.endPos - startPos; + if (0 != chars) { + pdoc->DeleteChars(startPos, chars); + } + } + pdoc->EndUndoAction(); + selType = selStream; + } + SetEmptySelection(startPos); + } +} + +void Editor::ClearAll() { + pdoc->BeginUndoAction(); + if (0 != pdoc->Length()) { + pdoc->DeleteChars(0, pdoc->Length()); + } + if (!pdoc->IsReadOnly()) { + cs.Clear(); + pdoc->AnnotationClearAll(); + pdoc->MarginClearAll(); + } + pdoc->EndUndoAction(); + anchor = 0; + currentPos = 0; + SetTopLine(0); + SetVerticalScrollPos(); + InvalidateStyleRedraw(); +} + +void Editor::ClearDocumentStyle() { + Decoration *deco = pdoc->decorations.root; + while (deco) { + // Save next in case deco deleted + Decoration *decoNext = deco->next; + if (deco->indicator < INDIC_CONTAINER) { + pdoc->decorations.SetCurrentIndicator(deco->indicator); + pdoc->DecorationFillRange(0, 0, pdoc->Length()); + } + deco = decoNext; + } + pdoc->StartStyling(0, '\377'); + pdoc->SetStyleFor(pdoc->Length(), 0); + cs.ShowAll(); + pdoc->ClearLevels(); +} + +void Editor::CopyAllowLine() { + SelectionText selectedText; + CopySelectionRange(&selectedText, true); + CopyToClipboard(selectedText); +} + +void Editor::Cut() { + pdoc->CheckReadOnly(); + if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) { + Copy(); + ClearSelection(); + } +} + +void Editor::PasteRectangular(int pos, const char *ptr, int len) { + if (pdoc->IsReadOnly() || SelectionContainsProtected()) { + return; + } + currentPos = pos; + int xInsert = XFromPosition(currentPos); + int line = pdoc->LineFromPosition(currentPos); + bool prevCr = false; + pdoc->BeginUndoAction(); + for (int i = 0; i < len; i++) { + if (IsEOLChar(ptr[i])) { + if ((ptr[i] == '\r') || (!prevCr)) + line++; + if (line >= pdoc->LinesTotal()) { + if (pdoc->eolMode != SC_EOL_LF) + pdoc->InsertChar(pdoc->Length(), '\r'); + if (pdoc->eolMode != SC_EOL_CR) + pdoc->InsertChar(pdoc->Length(), '\n'); + } + // Pad the end of lines with spaces if required + currentPos = PositionFromLineX(line, xInsert); + if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) { + for (int i = 0; i < xInsert - XFromPosition(currentPos); i++) { + pdoc->InsertChar(currentPos, ' '); + currentPos++; + } + } + prevCr = ptr[i] == '\r'; + } else { + pdoc->InsertString(currentPos, ptr + i, 1); + currentPos++; + prevCr = false; + } + } + pdoc->EndUndoAction(); + SetEmptySelection(pos); +} + +bool Editor::CanPaste() { + return !pdoc->IsReadOnly() && !SelectionContainsProtected(); +} + +void Editor::Clear() { + if (currentPos == anchor) { + if (!RangeContainsProtected(currentPos, currentPos + 1)) { + DelChar(); + } + } else { + ClearSelection(); + } + SetEmptySelection(currentPos); +} + +void Editor::SelectAll() { + SetSelection(0, pdoc->Length()); + Redraw(); +} + +void Editor::Undo() { + if (pdoc->CanUndo()) { + InvalidateCaret(); + int newPos = pdoc->Undo(); + if (newPos >= 0) + SetEmptySelection(newPos); + EnsureCaretVisible(); + } +} + +void Editor::Redo() { + if (pdoc->CanRedo()) { + int newPos = pdoc->Redo(); + if (newPos >= 0) + SetEmptySelection(newPos); + EnsureCaretVisible(); + } +} + +void Editor::DelChar() { + if (!RangeContainsProtected(currentPos, currentPos + 1)) { + pdoc->DelChar(currentPos); + } + // Avoid blinking during rapid typing: + ShowCaretAtCurrentPosition(); +} + +void Editor::DelCharBack(bool allowLineStartDeletion) { + if (currentPos == anchor) { + if (!RangeContainsProtected(currentPos - 1, currentPos)) { + int lineCurrentPos = pdoc->LineFromPosition(currentPos); + if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) { + if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) && + pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) { + pdoc->BeginUndoAction(); + int indentation = pdoc->GetLineIndentation(lineCurrentPos); + int indentationStep = pdoc->IndentSize(); + if (indentation % indentationStep == 0) { + pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); + } else { + pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep)); + } + SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos)); + pdoc->EndUndoAction(); + } else { + pdoc->DelCharBack(currentPos); + } + } + } + } else { + ClearSelection(); + SetEmptySelection(currentPos); + } + // Avoid blinking during rapid typing: + ShowCaretAtCurrentPosition(); +} + +void Editor::NotifyFocus(bool) {} + +SCNotification scNotification() +{ + SCNotification scn = {{0,0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + return scn; +} + +void Editor::NotifyStyleToNeeded(int endStyleNeeded) { + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_STYLENEEDED; + scn.position = endStyleNeeded; + NotifyParent(scn); +} + +void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) { + NotifyStyleToNeeded(endStyleNeeded); +} + +void Editor::NotifyChar(int ch) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_CHARADDED; + scn.ch = ch; + NotifyParent(scn); + if (recordingMacro) { + char txt[2]; + txt[0] = static_cast(ch); + txt[1] = '\0'; + NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast(txt)); + } +} + +void Editor::NotifySavePoint(bool isSavePoint) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + if (isSavePoint) { + scn.nmhdr.code = SCN_SAVEPOINTREACHED; + } else { + scn.nmhdr.code = SCN_SAVEPOINTLEFT; + } + NotifyParent(scn); +} + +void Editor::NotifyModifyAttempt() { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_MODIFYATTEMPTRO; + NotifyParent(scn); +} + +void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_DOUBLECLICK; + scn.line = LineFromLocation(pt); + scn.position = PositionFromLocationClose(pt); + scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + NotifyParent(scn); +} + +void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK; + scn.position = position; + scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + NotifyParent(scn); +} + +void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_HOTSPOTCLICK; + scn.position = position; + scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + NotifyParent(scn); +} + +void Editor::NotifyUpdateUI() { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_UPDATEUI; + NotifyParent(scn); +} + +void Editor::NotifyPainted() { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_PAINTED; + NotifyParent(scn); +} + +void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) { + int mask = pdoc->decorations.AllOnFor(position); + if ((click && mask) || pdoc->decorations.clickNotified) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + pdoc->decorations.clickNotified = click; + scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE; + scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); + scn.position = position; + NotifyParent(scn); + } +} + +bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) { + int marginClicked = -1; + int x = 0; + for (int margin = 0; margin < ViewStyle::margins; margin++) { + if ((pt.x > x) && (pt.x < x + vs.ms[margin].width)) + marginClicked = margin; + x += vs.ms[margin].width; + } + if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_MARGINCLICK; + scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + scn.position = pdoc->LineStart(LineFromLocation(pt)); + scn.margin = marginClicked; + NotifyParent(scn); + return true; + } else { + return false; + } +} + +void Editor::NotifyNeedShown(int pos, int len) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_NEEDSHOWN; + scn.position = pos; + scn.length = len; + NotifyParent(scn); +} + +void Editor::NotifyDwelling(Point pt, bool state) { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND; + scn.position = PositionFromLocationClose(pt); + scn.x = pt.x; + scn.y = pt.y; + NotifyParent(scn); +} + +void Editor::NotifyZoom() { + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_ZOOM; + NotifyParent(scn); +} + +// Notifications from document +void Editor::NotifyModifyAttempt(Document*, void *) { + //Platform::DebugPrintf("** Modify Attempt\n"); + NotifyModifyAttempt(); +} + +void Editor::NotifyMove(int position) { + position = position; +#ifdef INCLUDE_DEPRECATED_FEATURES + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_POSCHANGED; + scn.position = position; + NotifyParent(scn); +#endif +} + +void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) { + //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); + NotifySavePoint(atSavePoint); +} + +void Editor::CheckModificationForWrap(DocModification mh) { + if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { + llc.Invalidate(LineLayout::llCheckTextAndStyle); + if (wrapState != eWrapNone) { + int lineDoc = pdoc->LineFromPosition(mh.position); + int lines = Platform::Maximum(0, mh.linesAdded); + NeedWrapping(lineDoc, lineDoc + lines + 1); + } + // Fix up annotation heights + int lineDoc = pdoc->LineFromPosition(mh.position); + int lines = Platform::Maximum(0, mh.linesAdded); + SetAnnotationHeights(lineDoc, lineDoc + lines + 2); + } +} + +// Move a position so it is still after the same character as before the insertion. +static inline int MovePositionForInsertion(int position, int startInsertion, int length) { + if (position > startInsertion) { + return position + length; + } + return position; +} + +// Move a position so it is still after the same character as before the deletion if that +// character is still present else after the previous surviving character. +static inline int MovePositionForDeletion(int position, int startDeletion, int length) { + if (position > startDeletion) { + int endDeletion = startDeletion + length; + if (position > endDeletion) { + return position - length; + } else { + return startDeletion; + } + } else { + return position; + } +} + +void Editor::NotifyModified(Document*, DocModification mh, void *) { + needUpdateUI = true; + if (paintState == painting) { + CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); + } + if (mh.modificationType & SC_MOD_CHANGELINESTATE) { + if (paintState == painting) { + CheckForChangeOutsidePaint( + Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1))); + } else { + // Could check that change is before last visible line. + Redraw(); + } + } + if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) { + if (mh.modificationType & SC_MOD_CHANGESTYLE) { + pdoc->IncrementStyleClock(); + } + if (paintState == notPainting) { + if (mh.position < pdoc->LineStart(topLine)) { + // Styling performed before this view + Redraw(); + } else { + InvalidateRange(mh.position, mh.position + mh.length); + } + } + if (mh.modificationType & SC_MOD_CHANGESTYLE) { + llc.Invalidate(LineLayout::llCheckTextAndStyle); + } + } else { + // Move selection and brace highlights + if (mh.modificationType & SC_MOD_INSERTTEXT) { + currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length); + anchor = MovePositionForInsertion(anchor, mh.position, mh.length); + braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length); + braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length); + } else if (mh.modificationType & SC_MOD_DELETETEXT) { + currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length); + anchor = MovePositionForDeletion(anchor, mh.position, mh.length); + braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length); + braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length); + } + if (cs.LinesDisplayed() < cs.LinesInDoc()) { + // Some lines are hidden so may need shown. + // TODO: check if the modified area is hidden. + if (mh.modificationType & SC_MOD_BEFOREINSERT) { + NotifyNeedShown(mh.position, 0); + } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { + NotifyNeedShown(mh.position, mh.length); + } + } + if (mh.linesAdded != 0) { + // Update contraction state for inserted and removed lines + // lineOfPos should be calculated in context of state before modification, shouldn't it + int lineOfPos = pdoc->LineFromPosition(mh.position); + if (mh.linesAdded > 0) { + cs.InsertLines(lineOfPos, mh.linesAdded); + } else { + cs.DeleteLines(lineOfPos, -mh.linesAdded); + } + } + if (mh.modificationType & SC_MOD_CHANGEANNOTATION) { + int lineDoc = pdoc->LineFromPosition(mh.position); + if (vs.annotationVisible) { + cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded); + } + } + CheckModificationForWrap(mh); + if (mh.linesAdded != 0) { + // Avoid scrolling of display if change before current display + if (mh.position < posTopLine && !CanDeferToLastStep(mh)) { + int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos()); + if (newTop != topLine) { + SetTopLine(newTop); + SetVerticalScrollPos(); + } + } + + //Platform::DebugPrintf("** %x Doc Changed\n", this); + // TODO: could invalidate from mh.startModification to end of screen + //InvalidateRange(mh.position, mh.position + mh.length); + if (paintState == notPainting && !CanDeferToLastStep(mh)) { + Redraw(); + } + } else { + //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, + // mh.position, mh.position + mh.length); + if (paintState == notPainting && mh.length && !CanEliminate(mh)) { + InvalidateRange(mh.position, mh.position + mh.length); + } + } + } + + if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) { + SetScrollBars(); + } + + if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) { + if ((paintState == notPainting) || !PaintContainsMargin()) { + if (mh.modificationType & SC_MOD_CHANGEFOLD) { + // Fold changes can affect the drawing of following lines so redraw whole margin + RedrawSelMargin(); + } else { + RedrawSelMargin(mh.line); + } + } + } + + // NOW pay the piper WRT "deferred" visual updates + if (IsLastStep(mh)) { + SetScrollBars(); + Redraw(); + } + + // If client wants to see this modification + if (mh.modificationType & modEventMask) { + if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) { + // Real modification made to text of document. + NotifyChange(); // Send EN_CHANGE + } + + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_MODIFIED; + scn.position = mh.position; + scn.modificationType = mh.modificationType; + scn.text = mh.text; + scn.length = mh.length; + scn.linesAdded = mh.linesAdded; + scn.line = mh.line; + scn.foldLevelNow = mh.foldLevelNow; + scn.foldLevelPrev = mh.foldLevelPrev; + scn.token = mh.token; + scn.annotationLinesAdded = mh.annotationLinesAdded; + NotifyParent(scn); + } +} + +void Editor::NotifyDeleted(Document *, void *) { + /* Do nothing */ +} + +void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + + // Enumerates all macroable messages + switch (iMessage) { + case SCI_CUT: + case SCI_COPY: + case SCI_PASTE: + case SCI_CLEAR: + case SCI_REPLACESEL: + case SCI_ADDTEXT: + case SCI_INSERTTEXT: + case SCI_APPENDTEXT: + case SCI_CLEARALL: + case SCI_SELECTALL: + case SCI_GOTOLINE: + case SCI_GOTOPOS: + case SCI_SEARCHANCHOR: + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + case SCI_LINEDOWN: + case SCI_LINEDOWNEXTEND: + case SCI_PARADOWN: + case SCI_PARADOWNEXTEND: + case SCI_LINEUP: + case SCI_LINEUPEXTEND: + case SCI_PARAUP: + case SCI_PARAUPEXTEND: + case SCI_CHARLEFT: + case SCI_CHARLEFTEXTEND: + case SCI_CHARRIGHT: + case SCI_CHARRIGHTEXTEND: + case SCI_WORDLEFT: + case SCI_WORDLEFTEXTEND: + case SCI_WORDRIGHT: + case SCI_WORDRIGHTEXTEND: + case SCI_WORDPARTLEFT: + case SCI_WORDPARTLEFTEXTEND: + case SCI_WORDPARTRIGHT: + case SCI_WORDPARTRIGHTEXTEND: + case SCI_WORDLEFTEND: + case SCI_WORDLEFTENDEXTEND: + case SCI_WORDRIGHTEND: + case SCI_WORDRIGHTENDEXTEND: + case SCI_HOME: + case SCI_HOMEEXTEND: + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + case SCI_HOMEWRAP: + case SCI_HOMEWRAPEXTEND: + case SCI_LINEENDWRAP: + case SCI_LINEENDWRAPEXTEND: + case SCI_DOCUMENTSTART: + case SCI_DOCUMENTSTARTEXTEND: + case SCI_DOCUMENTEND: + case SCI_DOCUMENTENDEXTEND: + case SCI_STUTTEREDPAGEUP: + case SCI_STUTTEREDPAGEUPEXTEND: + case SCI_STUTTEREDPAGEDOWN: + case SCI_STUTTEREDPAGEDOWNEXTEND: + case SCI_PAGEUP: + case SCI_PAGEUPEXTEND: + case SCI_PAGEDOWN: + case SCI_PAGEDOWNEXTEND: + case SCI_EDITTOGGLEOVERTYPE: + case SCI_CANCEL: + case SCI_DELETEBACK: + case SCI_TAB: + case SCI_BACKTAB: + case SCI_FORMFEED: + case SCI_VCHOME: + case SCI_VCHOMEEXTEND: + case SCI_VCHOMEWRAP: + case SCI_VCHOMEWRAPEXTEND: + case SCI_DELWORDLEFT: + case SCI_DELWORDRIGHT: + case SCI_DELWORDRIGHTEND: + case SCI_DELLINELEFT: + case SCI_DELLINERIGHT: + case SCI_LINECOPY: + case SCI_LINECUT: + case SCI_LINEDELETE: + case SCI_LINETRANSPOSE: + case SCI_LINEDUPLICATE: + case SCI_LOWERCASE: + case SCI_UPPERCASE: + case SCI_LINESCROLLDOWN: + case SCI_LINESCROLLUP: + case SCI_DELETEBACKNOTLINE: + case SCI_HOMEDISPLAY: + case SCI_HOMEDISPLAYEXTEND: + case SCI_LINEENDDISPLAY: + case SCI_LINEENDDISPLAYEXTEND: + case SCI_SETSELECTIONMODE: + case SCI_LINEDOWNRECTEXTEND: + case SCI_LINEUPRECTEXTEND: + case SCI_CHARLEFTRECTEXTEND: + case SCI_CHARRIGHTRECTEXTEND: + case SCI_HOMERECTEXTEND: + case SCI_VCHOMERECTEXTEND: + case SCI_LINEENDRECTEXTEND: + case SCI_PAGEUPRECTEXTEND: + case SCI_PAGEDOWNRECTEXTEND: + case SCI_SELECTIONDUPLICATE: + case SCI_COPYALLOWLINE: + break; + + // Filter out all others like display changes. Also, newlines are redundant + // with char insert messages. + case SCI_NEWLINE: + default: + // printf("Filtered out %ld of macro recording\n", iMessage); + return ; + } + + // Send notification + //SCNotification scn = {0}; + SCNotification scn = scNotification(); + scn.nmhdr.code = SCN_MACRORECORD; + scn.message = iMessage; + scn.wParam = wParam; + scn.lParam = lParam; + NotifyParent(scn); +} + +/** + * Force scroll and keep position relative to top of window. + * + * If stuttered = true and not already at first/last row, move to first/last row of window. + * If stuttered = true and already at first/last row, scroll as normal. + */ +void Editor::PageMove(int direction, selTypes sel, bool stuttered) { + int topLineNew, newPos; + + // I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem? + int currentLine = pdoc->LineFromPosition(currentPos); + int topStutterLine = topLine + caretYSlop; + int bottomStutterLine = + pdoc->LineFromPosition(PositionFromLocation( + Point(lastXChosen, direction * vs.lineHeight * LinesToScroll()))) + - caretYSlop - 1; + + if (stuttered && (direction < 0 && currentLine > topStutterLine)) { + topLineNew = topLine; + newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * caretYSlop)); + + } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) { + topLineNew = topLine; + newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop))); + + } else { + Point pt = LocationFromPosition(currentPos); + + topLineNew = Platform::Clamp( + topLine + direction * LinesToScroll(), 0, MaxScrollPos()); + newPos = PositionFromLocation( + Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll()))); + } + + if (topLineNew != topLine) { + SetTopLine(topLineNew); + MovePositionTo(newPos, sel); + Redraw(); + SetVerticalScrollPos(); + } else { + MovePositionTo(newPos, sel); + } +} + +void Editor::ChangeCaseOfSelection(bool makeUpperCase) { + pdoc->BeginUndoAction(); + int startCurrent = currentPos; + int startAnchor = anchor; + if (selType == selStream) { + pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()), + makeUpperCase); + SetSelection(startCurrent, startAnchor); + } else { + SelectionLineIterator lineIterator(this, false); + while (lineIterator.Iterate()) { + pdoc->ChangeCase( + Range(lineIterator.startPos, lineIterator.endPos), + makeUpperCase); + } + // Would be nicer to keep the rectangular selection but this is complex + SetEmptySelection(startCurrent); + } + pdoc->EndUndoAction(); +} + +void Editor::LineTranspose() { + int line = pdoc->LineFromPosition(currentPos); + if (line > 0) { + pdoc->BeginUndoAction(); + int startPrev = pdoc->LineStart(line - 1); + int endPrev = pdoc->LineEnd(line - 1); + int start = pdoc->LineStart(line); + int end = pdoc->LineEnd(line); + char *line1 = CopyRange(startPrev, endPrev); + int len1 = endPrev - startPrev; + char *line2 = CopyRange(start, end); + int len2 = end - start; + pdoc->DeleteChars(start, len2); + pdoc->DeleteChars(startPrev, len1); + pdoc->InsertString(startPrev, line2, len2); + pdoc->InsertString(start - len1 + len2, line1, len1); + MovePositionTo(start - len1 + len2); + delete []line1; + delete []line2; + pdoc->EndUndoAction(); + } +} + +void Editor::Duplicate(bool forLine) { + int start = SelectionStart(); + int end = SelectionEnd(); + if (start == end) { + forLine = true; + } + if (forLine) { + int line = pdoc->LineFromPosition(currentPos); + start = pdoc->LineStart(line); + end = pdoc->LineEnd(line); + } + char *text = CopyRange(start, end); + if (forLine) { + const char *eol = StringFromEOLMode(pdoc->eolMode); + pdoc->InsertCString(end, eol); + pdoc->InsertString(end + istrlen(eol), text, end - start); + } else { + pdoc->InsertString(end, text, end - start); + } + delete []text; +} + +void Editor::CancelModes() { + moveExtendsSelection = false; +} + +void Editor::NewLine() { + ClearSelection(); + const char *eol = "\n"; + if (pdoc->eolMode == SC_EOL_CRLF) { + eol = "\r\n"; + } else if (pdoc->eolMode == SC_EOL_CR) { + eol = "\r"; + } // else SC_EOL_LF -> "\n" already set + if (pdoc->InsertCString(currentPos, eol)) { + SetEmptySelection(currentPos + istrlen(eol)); + while (*eol) { + NotifyChar(*eol); + eol++; + } + } + SetLastXChosen(); + SetScrollBars(); + EnsureCaretVisible(); + // Avoid blinking during rapid typing: + ShowCaretAtCurrentPosition(); +} + +void Editor::CursorUpOrDown(int direction, selTypes sel) { + Point pt = LocationFromPosition(currentPos); + int lineDoc = pdoc->LineFromPosition(currentPos); + Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); + int subLine = (pt.y - ptStartLine.y) / vs.lineHeight; + int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0; + int posNew = PositionFromLocation( + Point(lastXChosen, pt.y + direction * vs.lineHeight)); + if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) { + posNew = PositionFromLocation( + Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight)); + } + if (direction < 0) { + // Line wrapping may lead to a location on the same line, so + // seek back if that is the case. + // There is an equivalent case when moving down which skips + // over a line but as that does not trap the user it is fine. + Point ptNew = LocationFromPosition(posNew); + while ((posNew > 0) && (pt.y == ptNew.y)) { + posNew--; + ptNew = LocationFromPosition(posNew); + } + } + MovePositionTo(posNew, sel); +} + +void Editor::ParaUpOrDown(int direction, selTypes sel) { + int lineDoc, savedPos = currentPos; + do { + MovePositionTo(direction > 0 ? pdoc->ParaDown(currentPos) : pdoc->ParaUp(currentPos), sel); + lineDoc = pdoc->LineFromPosition(currentPos); + if (direction > 0) { + if (currentPos >= pdoc->Length() && !cs.GetVisible(lineDoc)) { + if (sel == noSel) { + MovePositionTo(pdoc->LineEndPosition(savedPos)); + } + break; + } + } + } while (!cs.GetVisible(lineDoc)); +} + +int Editor::StartEndDisplayLine(int pos, bool start) { + RefreshStyleData(); + int line = pdoc->LineFromPosition(pos); + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(line)); + int posRet = INVALID_POSITION; + if (surface && ll) { + unsigned int posLineStart = pdoc->LineStart(line); + LayoutLine(line, surface, vs, ll, wrapWidth); + int posInLine = pos - posLineStart; + if (posInLine <= ll->maxLineLength) { + for (int subLine = 0; subLine < ll->lines; subLine++) { + if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { + if (start) { + posRet = ll->LineStart(subLine) + posLineStart; + } else { + if (subLine == ll->lines - 1) + posRet = ll->LineStart(subLine + 1) + posLineStart; + else + posRet = ll->LineStart(subLine + 1) + posLineStart - 1; + } + } + } + } + } + if (posRet == INVALID_POSITION) { + return pos; + } else { + return posRet; + } +} + +int Editor::KeyCommand(unsigned int iMessage) { + switch (iMessage) { + case SCI_LINEDOWN: + CursorUpOrDown(1); + break; + case SCI_LINEDOWNEXTEND: + CursorUpOrDown(1, selStream); + break; + case SCI_LINEDOWNRECTEXTEND: + CursorUpOrDown(1, selRectangle); + break; + case SCI_PARADOWN: + ParaUpOrDown(1); + break; + case SCI_PARADOWNEXTEND: + ParaUpOrDown(1, selStream); + break; + case SCI_LINESCROLLDOWN: + ScrollTo(topLine + 1); + MoveCaretInsideView(false); + break; + case SCI_LINEUP: + CursorUpOrDown(-1); + break; + case SCI_LINEUPEXTEND: + CursorUpOrDown(-1, selStream); + break; + case SCI_LINEUPRECTEXTEND: + CursorUpOrDown(-1, selRectangle); + break; + case SCI_PARAUP: + ParaUpOrDown(-1); + break; + case SCI_PARAUPEXTEND: + ParaUpOrDown(-1, selStream); + break; + case SCI_LINESCROLLUP: + ScrollTo(topLine - 1); + MoveCaretInsideView(false); + break; + case SCI_CHARLEFT: + if (SelectionEmpty() || moveExtendsSelection) { + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1)); + } else { + MovePositionTo(SelectionStart()); + } + SetLastXChosen(); + break; + case SCI_CHARLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selStream); + SetLastXChosen(); + break; + case SCI_CHARLEFTRECTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selRectangle); + SetLastXChosen(); + break; + case SCI_CHARRIGHT: + if (SelectionEmpty() || moveExtendsSelection) { + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1)); + } else { + MovePositionTo(SelectionEnd()); + } + SetLastXChosen(); + break; + case SCI_CHARRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selStream); + SetLastXChosen(); + break; + case SCI_CHARRIGHTRECTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selRectangle); + SetLastXChosen(); + break; + case SCI_WORDLEFT: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1)); + SetLastXChosen(); + break; + case SCI_WORDLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), selStream); + SetLastXChosen(); + break; + case SCI_WORDRIGHT: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1)); + SetLastXChosen(); + break; + case SCI_WORDRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), selStream); + SetLastXChosen(); + break; + + case SCI_WORDLEFTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1)); + SetLastXChosen(); + break; + case SCI_WORDLEFTENDEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1), selStream); + SetLastXChosen(); + break; + case SCI_WORDRIGHTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1)); + SetLastXChosen(); + break; + case SCI_WORDRIGHTENDEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1), selStream); + SetLastXChosen(); + break; + + case SCI_HOME: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos))); + SetLastXChosen(); + break; + case SCI_HOMEEXTEND: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selStream); + SetLastXChosen(); + break; + case SCI_HOMERECTEXTEND: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selRectangle); + SetLastXChosen(); + break; + case SCI_LINEEND: + MovePositionTo(pdoc->LineEndPosition(currentPos)); + SetLastXChosen(); + break; + case SCI_LINEENDEXTEND: + MovePositionTo(pdoc->LineEndPosition(currentPos), selStream); + SetLastXChosen(); + break; + case SCI_LINEENDRECTEXTEND: + MovePositionTo(pdoc->LineEndPosition(currentPos), selRectangle); + SetLastXChosen(); + break; + case SCI_HOMEWRAP: { + int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); + if (currentPos <= homePos) + homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos)); + MovePositionTo(homePos); + SetLastXChosen(); + } + break; + case SCI_HOMEWRAPEXTEND: { + int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); + if (currentPos <= homePos) + homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos)); + MovePositionTo(homePos, selStream); + SetLastXChosen(); + } + break; + case SCI_LINEENDWRAP: { + int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1); + int realEndPos = pdoc->LineEndPosition(currentPos); + if (endPos > realEndPos // if moved past visible EOLs + || currentPos >= endPos) // if at end of display line already + endPos = realEndPos; + MovePositionTo(endPos); + SetLastXChosen(); + } + break; + case SCI_LINEENDWRAPEXTEND: { + int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1); + int realEndPos = pdoc->LineEndPosition(currentPos); + if (endPos > realEndPos // if moved past visible EOLs + || currentPos >= endPos) // if at end of display line already + endPos = realEndPos; + MovePositionTo(endPos, selStream); + SetLastXChosen(); + } + break; + case SCI_DOCUMENTSTART: + MovePositionTo(0); + SetLastXChosen(); + break; + case SCI_DOCUMENTSTARTEXTEND: + MovePositionTo(0, selStream); + SetLastXChosen(); + break; + case SCI_DOCUMENTEND: + MovePositionTo(pdoc->Length()); + SetLastXChosen(); + break; + case SCI_DOCUMENTENDEXTEND: + MovePositionTo(pdoc->Length(), selStream); + SetLastXChosen(); + break; + case SCI_STUTTEREDPAGEUP: + PageMove(-1, noSel, true); + break; + case SCI_STUTTEREDPAGEUPEXTEND: + PageMove(-1, selStream, true); + break; + case SCI_STUTTEREDPAGEDOWN: + PageMove(1, noSel, true); + break; + case SCI_STUTTEREDPAGEDOWNEXTEND: + PageMove(1, selStream, true); + break; + case SCI_PAGEUP: + PageMove(-1); + break; + case SCI_PAGEUPEXTEND: + PageMove(-1, selStream); + break; + case SCI_PAGEUPRECTEXTEND: + PageMove(-1, selRectangle); + break; + case SCI_PAGEDOWN: + PageMove(1); + break; + case SCI_PAGEDOWNEXTEND: + PageMove(1, selStream); + break; + case SCI_PAGEDOWNRECTEXTEND: + PageMove(1, selRectangle); + break; + case SCI_EDITTOGGLEOVERTYPE: + inOverstrike = !inOverstrike; + DropCaret(); + ShowCaretAtCurrentPosition(); + NotifyUpdateUI(); + break; + case SCI_CANCEL: // Cancel any modes - handled in subclass + // Also unselect text + CancelModes(); + break; + case SCI_DELETEBACK: + DelCharBack(true); + if (!caretSticky) { + SetLastXChosen(); + } + EnsureCaretVisible(); + break; + case SCI_DELETEBACKNOTLINE: + DelCharBack(false); + if (!caretSticky) { + SetLastXChosen(); + } + EnsureCaretVisible(); + break; + case SCI_TAB: + Indent(true); + if (!caretSticky) { + SetLastXChosen(); + } + EnsureCaretVisible(); + ShowCaretAtCurrentPosition(); // Avoid blinking + break; + case SCI_BACKTAB: + Indent(false); + if (!caretSticky) { + SetLastXChosen(); + } + EnsureCaretVisible(); + ShowCaretAtCurrentPosition(); // Avoid blinking + break; + case SCI_NEWLINE: + NewLine(); + break; + case SCI_FORMFEED: + AddChar('\f'); + break; + case SCI_VCHOME: + MovePositionTo(pdoc->VCHomePosition(currentPos)); + SetLastXChosen(); + break; + case SCI_VCHOMEEXTEND: + MovePositionTo(pdoc->VCHomePosition(currentPos), selStream); + SetLastXChosen(); + break; + case SCI_VCHOMERECTEXTEND: + MovePositionTo(pdoc->VCHomePosition(currentPos), selRectangle); + SetLastXChosen(); + break; + case SCI_VCHOMEWRAP: { + int homePos = pdoc->VCHomePosition(currentPos); + int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); + if ((viewLineStart < currentPos) && (viewLineStart > homePos)) + homePos = viewLineStart; + + MovePositionTo(homePos); + SetLastXChosen(); + } + break; + case SCI_VCHOMEWRAPEXTEND: { + int homePos = pdoc->VCHomePosition(currentPos); + int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); + if ((viewLineStart < currentPos) && (viewLineStart > homePos)) + homePos = viewLineStart; + + MovePositionTo(homePos, selStream); + SetLastXChosen(); + } + break; + case SCI_ZOOMIN: + if (vs.zoomLevel < 20) { + vs.zoomLevel++; + InvalidateStyleRedraw(); + NotifyZoom(); + } + break; + case SCI_ZOOMOUT: + if (vs.zoomLevel > -10) { + vs.zoomLevel--; + InvalidateStyleRedraw(); + NotifyZoom(); + } + break; + case SCI_DELWORDLEFT: { + int startWord = pdoc->NextWordStart(currentPos, -1); + pdoc->DeleteChars(startWord, currentPos - startWord); + SetLastXChosen(); + } + break; + case SCI_DELWORDRIGHT: { + int endWord = pdoc->NextWordStart(currentPos, 1); + pdoc->DeleteChars(currentPos, endWord - currentPos); + } + break; + case SCI_DELWORDRIGHTEND: { + int endWord = pdoc->NextWordEnd(currentPos, 1); + pdoc->DeleteChars(currentPos, endWord - currentPos); + } + break; + case SCI_DELLINELEFT: { + int line = pdoc->LineFromPosition(currentPos); + int start = pdoc->LineStart(line); + pdoc->DeleteChars(start, currentPos - start); + SetLastXChosen(); + } + break; + case SCI_DELLINERIGHT: { + int line = pdoc->LineFromPosition(currentPos); + int end = pdoc->LineEnd(line); + pdoc->DeleteChars(currentPos, end - currentPos); + } + break; + case SCI_LINECOPY: { + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + CopyRangeToClipboard(pdoc->LineStart(lineStart), + pdoc->LineStart(lineEnd + 1)); + } + break; + case SCI_LINECUT: { + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int start = pdoc->LineStart(lineStart); + int end = pdoc->LineStart(lineEnd + 1); + SetSelection(start, end); + Cut(); + SetLastXChosen(); + } + break; + case SCI_LINEDELETE: { + int line = pdoc->LineFromPosition(currentPos); + int start = pdoc->LineStart(line); + int end = pdoc->LineStart(line + 1); + pdoc->DeleteChars(start, end - start); + } + break; + case SCI_LINETRANSPOSE: + LineTranspose(); + break; + case SCI_LINEDUPLICATE: + Duplicate(true); + break; + case SCI_SELECTIONDUPLICATE: + Duplicate(false); + break; + case SCI_LOWERCASE: + ChangeCaseOfSelection(false); + break; + case SCI_UPPERCASE: + ChangeCaseOfSelection(true); + break; + case SCI_WORDPARTLEFT: + MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1)); + SetLastXChosen(); + break; + case SCI_WORDPARTLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), selStream); + SetLastXChosen(); + break; + case SCI_WORDPARTRIGHT: + MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1)); + SetLastXChosen(); + break; + case SCI_WORDPARTRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), selStream); + SetLastXChosen(); + break; + case SCI_HOMEDISPLAY: + MovePositionTo(MovePositionSoVisible( + StartEndDisplayLine(currentPos, true), -1)); + SetLastXChosen(); + break; + case SCI_HOMEDISPLAYEXTEND: + MovePositionTo(MovePositionSoVisible( + StartEndDisplayLine(currentPos, true), -1), selStream); + SetLastXChosen(); + break; + case SCI_LINEENDDISPLAY: + MovePositionTo(MovePositionSoVisible( + StartEndDisplayLine(currentPos, false), 1)); + SetLastXChosen(); + break; + case SCI_LINEENDDISPLAYEXTEND: + MovePositionTo(MovePositionSoVisible( + StartEndDisplayLine(currentPos, false), 1), selStream); + SetLastXChosen(); + break; + } + return 0; +} + +int Editor::KeyDefault(int, int) { + return 0; +} + +int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) { + DwellEnd(false); + int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + int msg = kmap.Find(key, modifiers); + if (msg) { + if (consumed) + *consumed = true; + return WndProc(msg, 0, 0); + } else { + if (consumed) + *consumed = false; + return KeyDefault(key, modifiers); + } +} + +void Editor::SetWhitespaceVisible(int view) { + vs.viewWhitespace = static_cast(view); +} + +int Editor::GetWhitespaceVisible() { + return vs.viewWhitespace; +} + +void Editor::Indent(bool forwards) { + //Platform::DebugPrintf("INdent %d\n", forwards); + int lineOfAnchor = pdoc->LineFromPosition(anchor); + int lineCurrentPos = pdoc->LineFromPosition(currentPos); + if (lineOfAnchor == lineCurrentPos) { + if (forwards) { + pdoc->BeginUndoAction(); + ClearSelection(); + if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) && + pdoc->tabIndents) { + int indentation = pdoc->GetLineIndentation(lineCurrentPos); + int indentationStep = pdoc->IndentSize(); + pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep); + SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos)); + } else { + if (pdoc->useTabs) { + pdoc->InsertChar(currentPos, '\t'); + SetEmptySelection(currentPos + 1); + } else { + int numSpaces = (pdoc->tabInChars) - + (pdoc->GetColumn(currentPos) % (pdoc->tabInChars)); + if (numSpaces < 1) + numSpaces = pdoc->tabInChars; + for (int i = 0; i < numSpaces; i++) { + pdoc->InsertChar(currentPos + i, ' '); + } + SetEmptySelection(currentPos + numSpaces); + } + } + pdoc->EndUndoAction(); + } else { + if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) && + pdoc->tabIndents) { + pdoc->BeginUndoAction(); + int indentation = pdoc->GetLineIndentation(lineCurrentPos); + int indentationStep = pdoc->IndentSize(); + pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); + SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos)); + pdoc->EndUndoAction(); + } else { + int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) * + pdoc->tabInChars; + if (newColumn < 0) + newColumn = 0; + int newPos = currentPos; + while (pdoc->GetColumn(newPos) > newColumn) + newPos--; + SetEmptySelection(newPos); + } + } + } else { + int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor); + int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos); + // Multiple lines selected so indent / dedent + int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos); + int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos); + if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos) + lineBottomSel--; // If not selecting any characters on a line, do not indent + pdoc->BeginUndoAction(); + pdoc->Indent(forwards, lineBottomSel, lineTopSel); + pdoc->EndUndoAction(); + if (lineOfAnchor < lineCurrentPos) { + if (currentPosPosOnLine == 0) + SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); + else + SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor)); + } else { + if (anchorPosOnLine == 0) + SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); + else + SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1)); + } + } +} + +/** + * Search of a text in the document, in the given range. + * @return The position of the found text, -1 if not found. + */ +long Editor::FindText( + uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, + ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. + sptr_t lParam) { ///< @c TextToFind structure: The text to search for in the given range. + + TextToFind *ft = reinterpret_cast(lParam); + int lengthFound = istrlen(ft->lpstrText); + int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, + (wParam & SCFIND_MATCHCASE) != 0, + (wParam & SCFIND_WHOLEWORD) != 0, + (wParam & SCFIND_WORDSTART) != 0, + (wParam & SCFIND_REGEXP) != 0, + wParam, + &lengthFound); + if (pos != -1) { + ft->chrgText.cpMin = pos; + ft->chrgText.cpMax = pos + lengthFound; + } + return pos; +} + +/** + * Relocatable search support : Searches relative to current selection + * point and sets the selection to the found text range with + * each search. + */ +/** + * Anchor following searches at current selection start: This allows + * multiple incremental interactive searches to be macro recorded + * while still setting the selection to found text so the find/select + * operation is self-contained. + */ +void Editor::SearchAnchor() { + searchAnchor = SelectionStart(); +} + +/** + * Find text from current search anchor: Must call @c SearchAnchor first. + * Used for next text and previous text requests. + * @return The position of the found text, -1 if not found. + */ +long Editor::SearchText( + unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV. + uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, + ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. + sptr_t lParam) { ///< The text to search for. + + const char *txt = reinterpret_cast(lParam); + int pos; + int lengthFound = istrlen(txt); + if (iMessage == SCI_SEARCHNEXT) { + pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, + (wParam & SCFIND_MATCHCASE) != 0, + (wParam & SCFIND_WHOLEWORD) != 0, + (wParam & SCFIND_WORDSTART) != 0, + (wParam & SCFIND_REGEXP) != 0, + wParam, + &lengthFound); + } else { + pos = pdoc->FindText(searchAnchor, 0, txt, + (wParam & SCFIND_MATCHCASE) != 0, + (wParam & SCFIND_WHOLEWORD) != 0, + (wParam & SCFIND_WORDSTART) != 0, + (wParam & SCFIND_REGEXP) != 0, + wParam, + &lengthFound); + } + + if (pos != -1) { + SetSelection(pos, pos + lengthFound); + } + + return pos; +} + +/** + * Search for text in the target range of the document. + * @return The position of the found text, -1 if not found. + */ +long Editor::SearchInTarget(const char *text, int length) { + int lengthFound = length; + int pos = pdoc->FindText(targetStart, targetEnd, text, + (searchFlags & SCFIND_MATCHCASE) != 0, + (searchFlags & SCFIND_WHOLEWORD) != 0, + (searchFlags & SCFIND_WORDSTART) != 0, + (searchFlags & SCFIND_REGEXP) != 0, + searchFlags, + &lengthFound); + if (pos != -1) { + targetStart = pos; + targetEnd = pos + lengthFound; + } + return pos; +} + +void Editor::GoToLine(int lineNo) { + if (lineNo > pdoc->LinesTotal()) + lineNo = pdoc->LinesTotal(); + if (lineNo < 0) + lineNo = 0; + SetEmptySelection(pdoc->LineStart(lineNo)); + ShowCaretAtCurrentPosition(); + EnsureCaretVisible(); +} + +static bool Close(Point pt1, Point pt2) { + if (abs(pt1.x - pt2.x) > 3) + return false; + if (abs(pt1.y - pt2.y) > 3) + return false; + return true; +} + +char *Editor::CopyRange(int start, int end) { + char *text = 0; + if (start < end) { + int len = end - start; + text = new char[len + 1]; + if (text) { + for (int i = 0; i < len; i++) { + text[i] = pdoc->CharAt(start + i); + } + text[len] = '\0'; + } + } + return text; +} + +void Editor::CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end) { + bool isLine = allowLineCopy && (start == end); + if (isLine) { + int currentLine = pdoc->LineFromPosition(currentPos); + start = pdoc->LineStart(currentLine); + end = pdoc->LineEnd(currentLine); + + char *text = CopyRange(start, end); + int textLen = text ? strlen(text) : 0; + // include room for \r\n\0 + textLen += 3; + char *textWithEndl = new char[textLen]; + textWithEndl[0] = '\0'; + if (text) + strncat(textWithEndl, text, textLen); + if (pdoc->eolMode != SC_EOL_LF) + strncat(textWithEndl, "\r", textLen); + if (pdoc->eolMode != SC_EOL_CR) + strncat(textWithEndl, "\n", textLen); + ss->Set(textWithEndl, strlen(textWithEndl), + pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true); + delete []text; + } else { + ss->Set(CopyRange(start, end), end - start + 1, + pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); + } +} + +void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) { + if (selType == selStream) { + CopySelectionFromRange(ss, allowLineCopy, SelectionStart(), SelectionEnd()); + } else { + char *text = 0; + int size = 0; + SelectionLineIterator lineIterator(this); + while (lineIterator.Iterate()) { + size += lineIterator.endPos - lineIterator.startPos; + if (selType != selLines) { + size++; + if (pdoc->eolMode == SC_EOL_CRLF) { + size++; + } + } + } + if (size > 0) { + text = new char[size + 1]; + if (text) { + int j = 0; + lineIterator.Reset(); + while (lineIterator.Iterate()) { + for (int i = lineIterator.startPos; + i < lineIterator.endPos; + i++) { + text[j++] = pdoc->CharAt(i); + } + if (selType != selLines) { + if (pdoc->eolMode != SC_EOL_LF) { + text[j++] = '\r'; + } + if (pdoc->eolMode != SC_EOL_CR) { + text[j++] = '\n'; + } + } + } + text[size] = '\0'; + } + } + ss->Set(text, size + 1, pdoc->dbcsCodePage, + vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle, selType == selLines); + } +} + +void Editor::CopyRangeToClipboard(int start, int end) { + start = pdoc->ClampPositionIntoDocument(start); + end = pdoc->ClampPositionIntoDocument(end); + SelectionText selectedText; + selectedText.Set(CopyRange(start, end), end - start + 1, + pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); + CopyToClipboard(selectedText); +} + +void Editor::CopyText(int length, const char *text) { + SelectionText selectedText; + selectedText.Copy(text, length + 1, + pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); + CopyToClipboard(selectedText); +} + +void Editor::SetDragPosition(int newPos) { + if (newPos >= 0) { + newPos = MovePositionOutsideChar(newPos, 1); + posDrop = newPos; + } + if (posDrag != newPos) { + caret.on = true; + SetTicking(true); + InvalidateCaret(); + posDrag = newPos; + InvalidateCaret(); + } +} + +void Editor::DisplayCursor(Window::Cursor c) { + if (cursorMode == SC_CURSORNORMAL) + wMain.SetCursor(c); + else + wMain.SetCursor(static_cast(cursorMode)); +} + +bool Editor::DragThreshold(Point ptStart, Point ptNow) { + int xMove = ptStart.x - ptNow.x; + int yMove = ptStart.y - ptNow.y; + int distanceSquared = xMove * xMove + yMove * yMove; + return distanceSquared > 16; +} + +void Editor::StartDrag() { + // Always handled by subclasses + //SetMouseCapture(true); + //DisplayCursor(Window::cursorArrow); +} + +void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) { + //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position); + if (inDragDrop == ddDragging) + dropWentOutside = false; + + int positionWasInSelection = PositionInSelection(position); + + bool positionOnEdgeOfSelection = + (position == SelectionStart()) || (position == SelectionEnd()); + + if ((inDragDrop != ddDragging) || !(0 == positionWasInSelection) || + (positionOnEdgeOfSelection && !moving)) { + + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + + pdoc->BeginUndoAction(); + + int positionAfterDeletion = position; + if ((inDragDrop == ddDragging) && moving) { + // Remove dragged out text + if (rectangular || selType == selLines) { + SelectionLineIterator lineIterator(this); + while (lineIterator.Iterate()) { + if (position >= lineIterator.startPos) { + if (position > lineIterator.endPos) { + positionAfterDeletion -= lineIterator.endPos - lineIterator.startPos; + } else { + positionAfterDeletion -= position - lineIterator.startPos; + } + } + } + } else { + if (position > selStart) { + positionAfterDeletion -= selEnd - selStart; + } + } + ClearSelection(); + } + position = positionAfterDeletion; + + if (rectangular) { + PasteRectangular(position, value, istrlen(value)); + pdoc->EndUndoAction(); + // Should try to select new rectangle but it may not be a rectangle now so just select the drop position + SetEmptySelection(position); + } else { + position = MovePositionOutsideChar(position, currentPos - position); + if (pdoc->InsertCString(position, value)) { + SetSelection(position + istrlen(value), position); + } + pdoc->EndUndoAction(); + } + } else if (inDragDrop == ddDragging) { + SetEmptySelection(position); + } +} + +/** + * @return -1 if given position is before the selection, + * 1 if position is after the selection, + * 0 if position is inside the selection, + */ +int Editor::PositionInSelection(int pos) { + pos = MovePositionOutsideChar(pos, currentPos - pos); + if (pos < SelectionStart()) { + return -1; + } + if (pos > SelectionEnd()) { + return 1; + } + if (selType == selStream) { + return 0; + } else { + SelectionLineIterator lineIterator(this); + lineIterator.SetAt(pdoc->LineFromPosition(pos)); + if (pos < lineIterator.startPos) { + return -1; + } else if (pos > lineIterator.endPos) { + return 1; + } else { + return 0; + } + } +} + +bool Editor::PointInSelection(Point pt) { + int pos = PositionFromLocation(pt); + if (0 == PositionInSelection(pos)) { + // Probably inside, but we must make a finer test + int selStart, selEnd; + if (selType == selStream) { + selStart = SelectionStart(); + selEnd = SelectionEnd(); + } else { + SelectionLineIterator lineIterator(this); + lineIterator.SetAt(pdoc->LineFromPosition(pos)); + selStart = lineIterator.startPos; + selEnd = lineIterator.endPos; + } + if (pos == selStart) { + // see if just before selection + Point locStart = LocationFromPosition(pos); + if (pt.x < locStart.x) { + return false; + } + } + if (pos == selEnd) { + // see if just after selection + Point locEnd = LocationFromPosition(pos); + if (pt.x > locEnd.x) { + return false; + } + } + return true; + } + return false; +} + +bool Editor::PointInSelMargin(Point pt) { + // Really means: "Point in a margin" + if (vs.fixedColumnWidth > 0) { // There is a margin + PRectangle rcSelMargin = GetClientRectangle(); + rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth; + return rcSelMargin.Contains(pt); + } else { + return false; + } +} + +void Editor::LineSelection(int lineCurrent_, int lineAnchor_) { + if (lineAnchor_ < lineCurrent_) { + SetSelection(pdoc->LineStart(lineCurrent_ + 1), + pdoc->LineStart(lineAnchor_)); + } else if (lineAnchor_ > lineCurrent_) { + SetSelection(pdoc->LineStart(lineCurrent_), + pdoc->LineStart(lineAnchor_ + 1)); + } else { // Same line, select it + SetSelection(pdoc->LineStart(lineAnchor_ + 1), + pdoc->LineStart(lineAnchor_)); + } +} + +void Editor::DwellEnd(bool mouseMoved) { + if (mouseMoved) + ticksToDwell = dwellDelay; + else + ticksToDwell = SC_TIME_FOREVER; + if (dwelling && (dwellDelay < SC_TIME_FOREVER)) { + dwelling = false; + NotifyDwelling(ptMouseLast, dwelling); + } +} + +void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop); + ptMouseLast = pt; + int newPos = PositionFromLocation(pt); + newPos = MovePositionOutsideChar(newPos, currentPos - newPos); + inDragDrop = ddNone; + moveExtendsSelection = false; + + bool processed = NotifyMarginClick(pt, shift, ctrl, alt); + if (processed) + return; + + NotifyIndicatorClick(true, newPos, shift, ctrl, alt); + + bool inSelMargin = PointInSelMargin(pt); + if (shift & !inSelMargin) { + SetSelection(newPos); + } + if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) { + //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime); + SetMouseCapture(true); + SetEmptySelection(newPos); + bool doubleClick = false; + // Stop mouse button bounce changing selection type + if (!Platform::MouseButtonBounce() || curTime != lastClickTime) { + if (selectionType == selChar) { + selectionType = selWord; + doubleClick = true; + } else if (selectionType == selWord) { + selectionType = selLine; + } else { + selectionType = selChar; + originalAnchorPos = currentPos; + } + } + + if (selectionType == selWord) { + if (currentPos >= originalAnchorPos) { // Moved forward + SetSelection(pdoc->ExtendWordSelect(currentPos, 1), + pdoc->ExtendWordSelect(originalAnchorPos, -1)); + } else { // Moved backward + SetSelection(pdoc->ExtendWordSelect(currentPos, -1), + pdoc->ExtendWordSelect(originalAnchorPos, 1)); + } + } else if (selectionType == selLine) { + lineAnchor = LineFromLocation(pt); + SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor)); + //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos); + } else { + SetEmptySelection(currentPos); + } + //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos); + if (doubleClick) { + NotifyDoubleClick(pt, shift, ctrl, alt); + if (PositionIsHotspot(newPos)) + NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt); + } + } else { // Single click + if (inSelMargin) { + selType = selStream; + if (ctrl) { + SelectAll(); + lastClickTime = curTime; + return; + } + if (!shift) { + lineAnchor = LineFromLocation(pt); + // Single click in margin: select whole line + LineSelection(lineAnchor, lineAnchor); + SetSelection(pdoc->LineStart(lineAnchor + 1), + pdoc->LineStart(lineAnchor)); + } else { + // Single shift+click in margin: select from line anchor to clicked line + if (anchor > currentPos) + lineAnchor = pdoc->LineFromPosition(anchor - 1); + else + lineAnchor = pdoc->LineFromPosition(anchor); + int lineStart = LineFromLocation(pt); + LineSelection(lineStart, lineAnchor); + //lineAnchor = lineStart; // Keep the same anchor for ButtonMove + } + + SetDragPosition(invalidPosition); + SetMouseCapture(true); + selectionType = selLine; + } else { + if (PointIsHotspot(pt)) { + NotifyHotSpotClicked(newPos, shift, ctrl, alt); + } + if (!shift) { + if (PointInSelection(pt) && !SelectionEmpty()) + inDragDrop = ddInitial; + else + inDragDrop = ddNone; + } + SetMouseCapture(true); + if (inDragDrop != ddInitial) { + SetDragPosition(invalidPosition); + if (!shift) { + SetEmptySelection(newPos); + } + selType = alt ? selRectangle : selStream; + selectionType = selChar; + originalAnchorPos = currentPos; + SetRectangularRange(); + } + } + } + lastClickTime = curTime; + lastXChosen = pt.x; + ShowCaretAtCurrentPosition(); +} + +bool Editor::PositionIsHotspot(int position) { + return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot; +} + +bool Editor::PointIsHotspot(Point pt) { + int pos = PositionFromLocationClose(pt); + if (pos == INVALID_POSITION) + return false; + return PositionIsHotspot(pos); +} + +void Editor::SetHotSpotRange(Point *pt) { + if (pt) { + int pos = PositionFromLocation(*pt); + + // If we don't limit this to word characters then the + // range can encompass more than the run range and then + // the underline will not be drawn properly. + int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine); + int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine); + + // Only invalidate the range if the hotspot range has changed... + if (hsStart_ != hsStart || hsEnd_ != hsEnd) { + if (hsStart != -1) { + InvalidateRange(hsStart, hsEnd); + } + hsStart = hsStart_; + hsEnd = hsEnd_; + InvalidateRange(hsStart, hsEnd); + } + } else { + if (hsStart != -1) { + int hsStart_ = hsStart; + int hsEnd_ = hsEnd; + hsStart = -1; + hsEnd = -1; + InvalidateRange(hsStart_, hsEnd_); + } else { + hsStart = -1; + hsEnd = -1; + } + } +} + +void Editor::GetHotSpotRange(int& hsStart_, int& hsEnd_) { + hsStart_ = hsStart; + hsEnd_ = hsEnd; +} + +void Editor::ButtonMove(Point pt) { + if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) { + DwellEnd(true); + } + + int movePos = PositionFromLocation(pt); + movePos = MovePositionOutsideChar(movePos, currentPos - movePos); + + if (inDragDrop == ddInitial) { + if (DragThreshold(ptMouseLast, pt)) { + SetMouseCapture(false); + SetDragPosition(movePos); + CopySelectionRange(&drag); + StartDrag(); + } + return; + } + + ptMouseLast = pt; + //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); + if (HaveMouseCapture()) { + + // Slow down autoscrolling/selection + autoScrollTimer.ticksToWait -= timer.tickSize; + if (autoScrollTimer.ticksToWait > 0) + return; + autoScrollTimer.ticksToWait = autoScrollDelay; + + // Adjust selection + if (posDrag >= 0) { + SetDragPosition(movePos); + } else { + if (selectionType == selChar) { + SetSelection(movePos); + } else if (selectionType == selWord) { + // Continue selecting by word + if (movePos == originalAnchorPos) { // Didn't move + // No need to do anything. Previously this case was lumped + // in with "Moved forward", but that can be harmful in this + // case: a handler for the NotifyDoubleClick re-adjusts + // the selection for a fancier definition of "word" (for + // example, in Perl it is useful to include the leading + // '$', '%' or '@' on variables for word selection). In this + // the ButtonMove() called via Tick() for auto-scrolling + // could result in the fancier word selection adjustment + // being unmade. + } else if (movePos > originalAnchorPos) { // Moved forward + SetSelection(pdoc->ExtendWordSelect(movePos, 1), + pdoc->ExtendWordSelect(originalAnchorPos, -1)); + } else { // Moved backward + SetSelection(pdoc->ExtendWordSelect(movePos, -1), + pdoc->ExtendWordSelect(originalAnchorPos, 1)); + } + } else { + // Continue selecting by line + int lineMove = LineFromLocation(pt); + LineSelection(lineMove, lineAnchor); + } + } + // While dragging to make rectangular selection, we don't want the current + // position to jump to the end of smaller or empty lines. + //xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + xEndSelect = XFromPosition(movePos); + + // Autoscroll + PRectangle rcClient = GetClientRectangle(); + if (pt.y > rcClient.bottom) { + int lineMove = cs.DisplayFromDoc(LineFromLocation(pt)); + if (lineMove < 0) { + lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1); + } + ScrollTo(lineMove - LinesOnScreen() + 1); + Redraw(); + } else if (pt.y < rcClient.top) { + int lineMove = cs.DisplayFromDoc(LineFromLocation(pt)); + ScrollTo(lineMove - 1); + Redraw(); + } + EnsureCaretVisible(false, false, true); + + if (hsStart != -1 && !PositionIsHotspot(movePos)) + SetHotSpotRange(NULL); + + } else { + if (vs.fixedColumnWidth > 0) { // There is a margin + if (PointInSelMargin(pt)) { + DisplayCursor(Window::cursorReverseArrow); + return; // No need to test for selection + } + } + // Display regular (drag) cursor over selection + if (PointInSelection(pt) && !SelectionEmpty()) { + DisplayCursor(Window::cursorArrow); + } else if (PointIsHotspot(pt)) { + DisplayCursor(Window::cursorHand); + SetHotSpotRange(&pt); + } else { + DisplayCursor(Window::cursorText); + SetHotSpotRange(NULL); + } + } +} + +void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { + //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop); + int newPos = PositionFromLocation(pt); + newPos = MovePositionOutsideChar(newPos, currentPos - newPos); + if (inDragDrop == ddInitial) { + inDragDrop = ddNone; + SetEmptySelection(newPos); + } + if (HaveMouseCapture()) { + if (PointInSelMargin(pt)) { + DisplayCursor(Window::cursorReverseArrow); + } else { + DisplayCursor(Window::cursorText); + SetHotSpotRange(NULL); + } + ptMouseLast = pt; + SetMouseCapture(false); + int newPos = PositionFromLocation(pt); + newPos = MovePositionOutsideChar(newPos, currentPos - newPos); + NotifyIndicatorClick(false, newPos, false, false, false); + if (inDragDrop == ddDragging) { + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + if (selStart < selEnd) { + if (drag.len) { + if (ctrl) { + if (pdoc->InsertString(newPos, drag.s, drag.len)) { + SetSelection(newPos, newPos + drag.len); + } + } else if (newPos < selStart) { + pdoc->DeleteChars(selStart, drag.len); + if (pdoc->InsertString(newPos, drag.s, drag.len)) { + SetSelection(newPos, newPos + drag.len); + } + } else if (newPos > selEnd) { + pdoc->DeleteChars(selStart, drag.len); + newPos -= drag.len; + if (pdoc->InsertString(newPos, drag.s, drag.len)) { + SetSelection(newPos, newPos + drag.len); + } + } else { + SetEmptySelection(newPos); + } + drag.Free(); + } + selectionType = selChar; + } + } else { + if (selectionType == selChar) { + SetSelection(newPos); + } + } + SetRectangularRange(); + lastClickTime = curTime; + lastClick = pt; + lastXChosen = pt.x; + if (selType == selStream) { + SetLastXChosen(); + } + inDragDrop = ddNone; + EnsureCaretVisible(false); + } +} + +// Called frequently to perform background UI including +// caret blinking and automatic scrolling. +void Editor::Tick() { + if (HaveMouseCapture()) { + // Auto scroll + ButtonMove(ptMouseLast); + } + if (caret.period > 0) { + timer.ticksToWait -= timer.tickSize; + if (timer.ticksToWait <= 0) { + caret.on = !caret.on; + timer.ticksToWait = caret.period; + if (caret.active) { + InvalidateCaret(); + } + } + } + if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) { + scrollWidth = lineWidthMaxSeen; + SetScrollBars(); + } + if ((dwellDelay < SC_TIME_FOREVER) && + (ticksToDwell > 0) && + (!HaveMouseCapture())) { + ticksToDwell -= timer.tickSize; + if (ticksToDwell <= 0) { + dwelling = true; + NotifyDwelling(ptMouseLast, dwelling); + } + } +} + +bool Editor::Idle() { + + bool idleDone; + + bool wrappingDone = wrapState == eWrapNone; + + if (!wrappingDone) { + // Wrap lines during idle. + WrapLines(false, -1); + // No more wrapping + if (wrapStart == wrapEnd) + wrappingDone = true; + } + + // Add more idle things to do here, but make sure idleDone is + // set correctly before the function returns. returning + // false will stop calling this idle funtion until SetIdle() is + // called again. + + idleDone = wrappingDone; // && thatDone && theOtherThingDone... + + return !idleDone; +} + +void Editor::SetFocusState(bool focusState) { + hasFocus = focusState; + NotifyFocus(hasFocus); + if (hasFocus) { + ShowCaretAtCurrentPosition(); + } else { + CancelModes(); + DropCaret(); + } +} + +bool Editor::PaintContains(PRectangle rc) { + if (rc.Empty()) { + return true; + } else { + return rcPaint.Contains(rc); + } +} + +bool Editor::PaintContainsMargin() { + PRectangle rcSelMargin = GetClientRectangle(); + rcSelMargin.right = vs.fixedColumnWidth; + return PaintContains(rcSelMargin); +} + +void Editor::CheckForChangeOutsidePaint(Range r) { + if (paintState == painting && !paintingAllText) { + //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end); + if (!r.Valid()) + return; + + PRectangle rcRange = RectangleFromRange(r.start, r.end); + PRectangle rcText = GetTextRectangle(); + if (rcRange.top < rcText.top) { + rcRange.top = rcText.top; + } + if (rcRange.bottom > rcText.bottom) { + rcRange.bottom = rcText.bottom; + } + + if (!PaintContains(rcRange)) { + AbandonPaint(); + } + } +} + +void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) { + if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) { + if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) { + CheckForChangeOutsidePaint(Range(braces[0])); + CheckForChangeOutsidePaint(Range(pos0)); + braces[0] = pos0; + } + if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) { + CheckForChangeOutsidePaint(Range(braces[1])); + CheckForChangeOutsidePaint(Range(pos1)); + braces[1] = pos1; + } + bracesMatchStyle = matchStyle; + if (paintState == notPainting) { + Redraw(); + } + } +} + +void Editor::SetAnnotationHeights(int start, int end) { + if (vs.annotationVisible) { + for (int line=start; lineAnnotationLines(line) + 1); + } + } +} + +void Editor::SetDocPointer(Document *document) { + //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document); + pdoc->RemoveWatcher(this, 0); + pdoc->Release(); + if (document == NULL) { + pdoc = new Document(); + } else { + pdoc = document; + } + pdoc->AddRef(); + + // Ensure all positions within document + selType = selStream; + currentPos = 0; + anchor = 0; + targetStart = 0; + targetEnd = 0; + + braces[0] = invalidPosition; + braces[1] = invalidPosition; + + // Reset the contraction state to fully shown. + cs.Clear(); + cs.InsertLines(0, pdoc->LinesTotal() - 1); + SetAnnotationHeights(0, pdoc->LinesTotal()); + llc.Deallocate(); + NeedWrapping(); + + pdoc->AddWatcher(this, 0); + SetScrollBars(); + Redraw(); +} + +void Editor::SetAnnotationVisible(int visible) { + if (vs.annotationVisible != visible) { + bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0)); + vs.annotationVisible = visible; + if (changedFromOrToHidden) { + int dir = vs.annotationVisible ? 1 : -1; + for (int line=0; lineLinesTotal(); line++) { + int annotationLines = pdoc->AnnotationLines(line); + if (annotationLines > 0) { + cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir); + } + } + } + } +} + +/** + * Recursively expand a fold, making lines visible except where they have an unexpanded parent. + */ +void Editor::Expand(int &line, bool doExpand) { + int lineMaxSubord = pdoc->GetLastChild(line); + line++; + while (line <= lineMaxSubord) { + if (doExpand) + cs.SetVisible(line, line, true); + int level = pdoc->GetLevel(line); + if (level & SC_FOLDLEVELHEADERFLAG) { + if (doExpand && cs.GetExpanded(line)) { + Expand(line, true); + } else { + Expand(line, false); + } + } else { + line++; + } + } +} + +void Editor::ToggleContraction(int line) { + if (line >= 0) { + if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) { + line = pdoc->GetFoldParent(line); + if (line < 0) + return; + } + + if (cs.GetExpanded(line)) { + int lineMaxSubord = pdoc->GetLastChild(line); + cs.SetExpanded(line, 0); + if (lineMaxSubord > line) { + cs.SetVisible(line + 1, lineMaxSubord, false); + + int lineCurrent = pdoc->LineFromPosition(currentPos); + if (lineCurrent > line && lineCurrent <= lineMaxSubord) { + // This does not re-expand the fold + EnsureCaretVisible(); + } + + SetScrollBars(); + Redraw(); + } + + } else { + if (!(cs.GetVisible(line))) { + EnsureLineVisible(line, false); + GoToLine(line); + } + cs.SetExpanded(line, 1); + Expand(line, true); + SetScrollBars(); + Redraw(); + } + } +} + +/** + * Recurse up from this line to find any folds that prevent this line from being visible + * and unfold them all. + */ +void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { + + // In case in need of wrapping to ensure DisplayFromDoc works. + WrapLines(true, -1); + + if (!cs.GetVisible(lineDoc)) { + int lineParent = pdoc->GetFoldParent(lineDoc); + if (lineParent >= 0) { + if (lineDoc != lineParent) + EnsureLineVisible(lineParent, enforcePolicy); + if (!cs.GetExpanded(lineParent)) { + cs.SetExpanded(lineParent, 1); + Expand(lineParent, true); + } + } + SetScrollBars(); + Redraw(); + } + if (enforcePolicy) { + int lineDisplay = cs.DisplayFromDoc(lineDoc); + if (visiblePolicy & VISIBLE_SLOP) { + if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) { + SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } else if ((lineDisplay > topLine + LinesOnScreen() - 1) || + ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) { + SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + } else { + if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) { + SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + } + } +} + +int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) { + pdoc->BeginUndoAction(); + if (length == -1) + length = istrlen(text); + if (replacePatterns) { + text = pdoc->SubstituteByPosition(text, &length); + if (!text) { + pdoc->EndUndoAction(); + return 0; + } + } + if (targetStart != targetEnd) + pdoc->DeleteChars(targetStart, targetEnd - targetStart); + targetEnd = targetStart; + pdoc->InsertString(targetStart, text, length); + targetEnd = targetStart + length; + pdoc->EndUndoAction(); + return length; +} + +bool Editor::IsUnicodeMode() const { + return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage); +} + +int Editor::CodePage() const { + if (pdoc) + return pdoc->dbcsCodePage; + else + return 0; +} + +int Editor::WrapCount(int line) { + AutoSurface surface(this); + AutoLineLayout ll(llc, RetrieveLineLayout(line)); + + if (surface && ll) { + LayoutLine(line, surface, vs, ll, wrapWidth); + return ll->lines; + } else { + return 1; + } +} + +void Editor::AddStyledText(char *buffer, int appendLength) { + // The buffer consists of alternating character bytes and style bytes + size_t textLength = appendLength / 2; + char *text = new char[textLength]; + if (text) { + size_t i; + for (i = 0;i < textLength;i++) { + text[i] = buffer[i*2]; + } + pdoc->InsertString(CurrentPosition(), text, textLength); + for (i = 0;i < textLength;i++) { + text[i] = buffer[i*2+1]; + } + pdoc->StartStyling(CurrentPosition(), static_cast(0xff)); + pdoc->SetStyles(textLength, text); + delete []text; + } + SetEmptySelection(currentPos + textLength); +} + +static bool ValidMargin(unsigned long wParam) { + return wParam < ViewStyle::margins; +} + +static char *CharPtrFromSPtr(sptr_t lParam) { + return reinterpret_cast(lParam); +} + +void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + vs.EnsureStyle(wParam); + switch (iMessage) { + case SCI_STYLESETFORE: + vs.styles[wParam].fore.desired = ColourDesired(lParam); + break; + case SCI_STYLESETBACK: + vs.styles[wParam].back.desired = ColourDesired(lParam); + break; + case SCI_STYLESETBOLD: + vs.styles[wParam].bold = lParam != 0; + break; + case SCI_STYLESETITALIC: + vs.styles[wParam].italic = lParam != 0; + break; + case SCI_STYLESETEOLFILLED: + vs.styles[wParam].eolFilled = lParam != 0; + break; + case SCI_STYLESETSIZE: + vs.styles[wParam].size = lParam; + break; + case SCI_STYLESETFONT: + if (lParam != 0) { + vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam)); + } + break; + case SCI_STYLESETUNDERLINE: + vs.styles[wParam].underline = lParam != 0; + break; + case SCI_STYLESETCASE: + vs.styles[wParam].caseForce = static_cast(lParam); + break; + case SCI_STYLESETCHARACTERSET: + vs.styles[wParam].characterSet = lParam; + break; + case SCI_STYLESETVISIBLE: + vs.styles[wParam].visible = lParam != 0; + break; + case SCI_STYLESETCHANGEABLE: + vs.styles[wParam].changeable = lParam != 0; + break; + case SCI_STYLESETHOTSPOT: + vs.styles[wParam].hotspot = lParam != 0; + break; + } + InvalidateStyleRedraw(); +} + +sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + vs.EnsureStyle(wParam); + switch (iMessage) { + case SCI_STYLEGETFORE: + return vs.styles[wParam].fore.desired.AsLong(); + case SCI_STYLEGETBACK: + return vs.styles[wParam].back.desired.AsLong(); + case SCI_STYLEGETBOLD: + return vs.styles[wParam].bold ? 1 : 0; + case SCI_STYLEGETITALIC: + return vs.styles[wParam].italic ? 1 : 0; + case SCI_STYLEGETEOLFILLED: + return vs.styles[wParam].eolFilled ? 1 : 0; + case SCI_STYLEGETSIZE: + return vs.styles[wParam].size; + case SCI_STYLEGETFONT: + if (lParam != 0) + strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName); + return strlen(vs.styles[wParam].fontName); + case SCI_STYLEGETUNDERLINE: + return vs.styles[wParam].underline ? 1 : 0; + case SCI_STYLEGETCASE: + return static_cast(vs.styles[wParam].caseForce); + case SCI_STYLEGETCHARACTERSET: + return vs.styles[wParam].characterSet; + case SCI_STYLEGETVISIBLE: + return vs.styles[wParam].visible ? 1 : 0; + case SCI_STYLEGETCHANGEABLE: + return vs.styles[wParam].changeable ? 1 : 0; + case SCI_STYLEGETHOTSPOT: + return vs.styles[wParam].hotspot ? 1 : 0; + } + return 0; +} + +sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); + + // Optional macro recording hook + if (recordingMacro) + NotifyMacroRecord(iMessage, wParam, lParam); + + switch (iMessage) { + + case SCI_GETTEXT: { + if (lParam == 0) + return pdoc->Length() + 1; + if (wParam == 0) + return 0; + char *ptr = CharPtrFromSPtr(lParam); + unsigned int iChar = 0; + for (; iChar < wParam - 1; iChar++) + ptr[iChar] = pdoc->CharAt(iChar); + ptr[iChar] = '\0'; + return iChar; + } + + case SCI_SETTEXT: { + if (lParam == 0) + return 0; + pdoc->BeginUndoAction(); + pdoc->DeleteChars(0, pdoc->Length()); + SetEmptySelection(0); + pdoc->InsertCString(0, CharPtrFromSPtr(lParam)); + pdoc->EndUndoAction(); + return 1; + } + + case SCI_GETTEXTLENGTH: + return pdoc->Length(); + + case SCI_CUT: + Cut(); + SetLastXChosen(); + break; + + case SCI_COPY: + Copy(); + break; + + case SCI_COPYALLOWLINE: + CopyAllowLine(); + break; + + case SCI_COPYRANGE: + CopyRangeToClipboard(wParam, lParam); + break; + + case SCI_COPYTEXT: + CopyText(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_PASTE: + Paste(); + if (!caretSticky) { + SetLastXChosen(); + } + EnsureCaretVisible(); + break; + + case SCI_CLEAR: + Clear(); + SetLastXChosen(); + EnsureCaretVisible(); + break; + + case SCI_UNDO: + Undo(); + SetLastXChosen(); + break; + + case SCI_CANUNDO: + return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0; + + case SCI_EMPTYUNDOBUFFER: + pdoc->DeleteUndoHistory(); + return 0; + + case SCI_GETFIRSTVISIBLELINE: + return topLine; + + case SCI_GETLINE: { // Risk of overwriting the end of the buffer + int lineStart = pdoc->LineStart(wParam); + int lineEnd = pdoc->LineStart(wParam + 1); + if (lParam == 0) { + return lineEnd - lineStart; + } + char *ptr = CharPtrFromSPtr(lParam); + int iPlace = 0; + for (int iChar = lineStart; iChar < lineEnd; iChar++) { + ptr[iPlace++] = pdoc->CharAt(iChar); + } + return iPlace; + } + + case SCI_GETLINECOUNT: + if (pdoc->LinesTotal() == 0) + return 1; + else + return pdoc->LinesTotal(); + + case SCI_GETMODIFY: + return !pdoc->IsSavePoint(); + + case SCI_SETSEL: { + int nStart = static_cast(wParam); + int nEnd = static_cast(lParam); + if (nEnd < 0) + nEnd = pdoc->Length(); + if (nStart < 0) + nStart = nEnd; // Remove selection + selType = selStream; + SetSelection(nEnd, nStart); + EnsureCaretVisible(); + } + break; + + case SCI_GETSELTEXT: { + if (lParam == 0) { + if (selType == selStream) { + return 1 + SelectionEnd() - SelectionStart(); + } else { + // TODO: why is selLines handled the slow way? + int size = 0; + int extraCharsPerLine = 0; + if (selType != selLines) + extraCharsPerLine = (pdoc->eolMode == SC_EOL_CRLF) ? 2 : 1; + SelectionLineIterator lineIterator(this); + while (lineIterator.Iterate()) { + size += lineIterator.endPos + extraCharsPerLine - lineIterator.startPos; + } + + return 1 + size; + } + } + SelectionText selectedText; + CopySelectionRange(&selectedText); + char *ptr = CharPtrFromSPtr(lParam); + int iChar = 0; + if (selectedText.len) { + for (; iChar < selectedText.len; iChar++) + ptr[iChar] = selectedText.s[iChar]; + } else { + ptr[0] = '\0'; + } + return iChar; + } + + case SCI_LINEFROMPOSITION: + if (static_cast(wParam) < 0) + return 0; + return pdoc->LineFromPosition(wParam); + + case SCI_POSITIONFROMLINE: + if (static_cast(wParam) < 0) + wParam = pdoc->LineFromPosition(SelectionStart()); + if (wParam == 0) + return 0; // Even if there is no text, there is a first line that starts at 0 + if (static_cast(wParam) > pdoc->LinesTotal()) + return -1; + //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway... + // return -1; + return pdoc->LineStart(wParam); + + // Replacement of the old Scintilla interpretation of EM_LINELENGTH + case SCI_LINELENGTH: + if ((static_cast(wParam) < 0) || + (static_cast(wParam) > pdoc->LineFromPosition(pdoc->Length()))) + return 0; + return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam); + + case SCI_REPLACESEL: { + if (lParam == 0) + return 0; + pdoc->BeginUndoAction(); + ClearSelection(); + char *replacement = CharPtrFromSPtr(lParam); + pdoc->InsertCString(currentPos, replacement); + pdoc->EndUndoAction(); + SetEmptySelection(currentPos + istrlen(replacement)); + EnsureCaretVisible(); + } + break; + + case SCI_SETTARGETSTART: + targetStart = wParam; + break; + + case SCI_GETTARGETSTART: + return targetStart; + + case SCI_SETTARGETEND: + targetEnd = wParam; + break; + + case SCI_GETTARGETEND: + return targetEnd; + + case SCI_TARGETFROMSELECTION: + if (currentPos < anchor) { + targetStart = currentPos; + targetEnd = anchor; + } else { + targetStart = anchor; + targetEnd = currentPos; + } + break; + + case SCI_REPLACETARGET: + PLATFORM_ASSERT(lParam); + return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam); + + case SCI_REPLACETARGETRE: + PLATFORM_ASSERT(lParam); + return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam); + + case SCI_SEARCHINTARGET: + PLATFORM_ASSERT(lParam); + return SearchInTarget(CharPtrFromSPtr(lParam), wParam); + + case SCI_SETSEARCHFLAGS: + searchFlags = wParam; + break; + + case SCI_GETSEARCHFLAGS: + return searchFlags; + + case SCI_POSITIONBEFORE: + return pdoc->MovePositionOutsideChar(wParam - 1, -1, true); + + case SCI_POSITIONAFTER: + return pdoc->MovePositionOutsideChar(wParam + 1, 1, true); + + case SCI_LINESCROLL: + ScrollTo(topLine + lParam); + HorizontalScrollTo(xOffset + wParam * vs.spaceWidth); + return 1; + + case SCI_SETXOFFSET: + xOffset = wParam; + SetHorizontalScrollPos(); + Redraw(); + break; + + case SCI_GETXOFFSET: + return xOffset; + + case SCI_CHOOSECARETX: + SetLastXChosen(); + break; + + case SCI_SCROLLCARET: + EnsureCaretVisible(); + break; + + case SCI_SETREADONLY: + pdoc->SetReadOnly(wParam != 0); + return 1; + + case SCI_GETREADONLY: + return pdoc->IsReadOnly(); + + case SCI_CANPASTE: + return CanPaste(); + + case SCI_POINTXFROMPOSITION: + if (lParam < 0) { + return 0; + } else { + Point pt = LocationFromPosition(lParam); + return pt.x; + } + + case SCI_POINTYFROMPOSITION: + if (lParam < 0) { + return 0; + } else { + Point pt = LocationFromPosition(lParam); + return pt.y; + } + + case SCI_FINDTEXT: + return FindText(wParam, lParam); + + case SCI_GETTEXTRANGE: { + if (lParam == 0) + return 0; + TextRange *tr = reinterpret_cast(lParam); + int cpMax = tr->chrg.cpMax; + if (cpMax == -1) + cpMax = pdoc->Length(); + PLATFORM_ASSERT(cpMax <= pdoc->Length()); + int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions + pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len); + // Spec says copied text is terminated with a NUL + tr->lpstrText[len] = '\0'; + return len; // Not including NUL + } + + case SCI_HIDESELECTION: + hideSelection = wParam != 0; + Redraw(); + break; + + case SCI_FORMATRANGE: + return FormatRange(wParam != 0, reinterpret_cast(lParam)); + + case SCI_GETMARGINLEFT: + return vs.leftMarginWidth; + + case SCI_GETMARGINRIGHT: + return vs.rightMarginWidth; + + case SCI_SETMARGINLEFT: + vs.leftMarginWidth = lParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETMARGINRIGHT: + vs.rightMarginWidth = lParam; + InvalidateStyleRedraw(); + break; + + // Control specific mesages + + case SCI_ADDTEXT: { + if (lParam == 0) + return 0; + pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam); + SetEmptySelection(currentPos + wParam); + return 0; + } + + case SCI_ADDSTYLEDTEXT: + if (lParam) + AddStyledText(CharPtrFromSPtr(lParam), wParam); + return 0; + + case SCI_INSERTTEXT: { + if (lParam == 0) + return 0; + int insertPos = wParam; + if (static_cast(wParam) == -1) + insertPos = CurrentPosition(); + int newCurrent = CurrentPosition(); + char *sz = CharPtrFromSPtr(lParam); + pdoc->InsertCString(insertPos, sz); + if (newCurrent > insertPos) + newCurrent += istrlen(sz); + SetEmptySelection(newCurrent); + return 0; + } + + case SCI_APPENDTEXT: + pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam); + return 0; + + case SCI_CLEARALL: + ClearAll(); + return 0; + + case SCI_CLEARDOCUMENTSTYLE: + ClearDocumentStyle(); + return 0; + + case SCI_SETUNDOCOLLECTION: + pdoc->SetUndoCollection(wParam != 0); + return 0; + + case SCI_GETUNDOCOLLECTION: + return pdoc->IsCollectingUndo(); + + case SCI_BEGINUNDOACTION: + pdoc->BeginUndoAction(); + return 0; + + case SCI_ENDUNDOACTION: + pdoc->EndUndoAction(); + return 0; + + case SCI_GETCARETPERIOD: + return caret.period; + + case SCI_SETCARETPERIOD: + caret.period = wParam; + break; + + case SCI_SETWORDCHARS: { + pdoc->SetDefaultCharClasses(false); + if (lParam == 0) + return 0; + pdoc->SetCharClasses(reinterpret_cast(lParam), CharClassify::ccWord); + } + break; + + case SCI_SETWHITESPACECHARS: { + if (lParam == 0) + return 0; + pdoc->SetCharClasses(reinterpret_cast(lParam), CharClassify::ccSpace); + } + break; + + case SCI_SETCHARSDEFAULT: + pdoc->SetDefaultCharClasses(true); + break; + + case SCI_GETLENGTH: + return pdoc->Length(); + + case SCI_ALLOCATE: + pdoc->Allocate(wParam); + break; + + case SCI_GETCHARAT: + return pdoc->CharAt(wParam); + + case SCI_SETCURRENTPOS: + SetSelection(wParam, anchor); + break; + + case SCI_GETCURRENTPOS: + return currentPos; + + case SCI_SETANCHOR: + SetSelection(currentPos, wParam); + break; + + case SCI_GETANCHOR: + return anchor; + + case SCI_SETSELECTIONSTART: + SetSelection(Platform::Maximum(currentPos, wParam), wParam); + break; + + case SCI_GETSELECTIONSTART: + return Platform::Minimum(anchor, currentPos); + + case SCI_SETSELECTIONEND: + SetSelection(wParam, Platform::Minimum(anchor, wParam)); + break; + + case SCI_GETSELECTIONEND: + return Platform::Maximum(anchor, currentPos); + + case SCI_SETPRINTMAGNIFICATION: + printMagnification = wParam; + break; + + case SCI_GETPRINTMAGNIFICATION: + return printMagnification; + + case SCI_SETPRINTCOLOURMODE: + printColourMode = wParam; + break; + + case SCI_GETPRINTCOLOURMODE: + return printColourMode; + + case SCI_SETPRINTWRAPMODE: + printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone; + break; + + case SCI_GETPRINTWRAPMODE: + return printWrapState; + + case SCI_GETSTYLEAT: + if (static_cast(wParam) >= pdoc->Length()) + return 0; + else + return pdoc->StyleAt(wParam); + + case SCI_REDO: + Redo(); + break; + + case SCI_SELECTALL: + SelectAll(); + break; + + case SCI_SETSAVEPOINT: + pdoc->SetSavePoint(); + break; + + case SCI_GETSTYLEDTEXT: { + if (lParam == 0) + return 0; + TextRange *tr = reinterpret_cast(lParam); + int iPlace = 0; + for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) { + tr->lpstrText[iPlace++] = pdoc->CharAt(iChar); + tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar); + } + tr->lpstrText[iPlace] = '\0'; + tr->lpstrText[iPlace + 1] = '\0'; + return iPlace; + } + + case SCI_CANREDO: + return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0; + + case SCI_MARKERLINEFROMHANDLE: + return pdoc->LineFromHandle(wParam); + + case SCI_MARKERDELETEHANDLE: + pdoc->DeleteMarkFromHandle(wParam); + break; + + case SCI_GETVIEWWS: + return vs.viewWhitespace; + + case SCI_SETVIEWWS: + vs.viewWhitespace = static_cast(wParam); + Redraw(); + break; + + case SCI_POSITIONFROMPOINT: + return PositionFromLocation(Point(wParam, lParam)); + + case SCI_POSITIONFROMPOINTCLOSE: + return PositionFromLocationClose(Point(wParam, lParam)); + + case SCI_GOTOLINE: + GoToLine(wParam); + break; + + case SCI_GOTOPOS: + SetEmptySelection(wParam); + EnsureCaretVisible(); + Redraw(); + break; + + case SCI_GETCURLINE: { + int lineCurrentPos = pdoc->LineFromPosition(currentPos); + int lineStart = pdoc->LineStart(lineCurrentPos); + unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1); + if (lParam == 0) { + return 1 + lineEnd - lineStart; + } + PLATFORM_ASSERT(wParam > 0); + char *ptr = CharPtrFromSPtr(lParam); + unsigned int iPlace = 0; + for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) { + ptr[iPlace++] = pdoc->CharAt(iChar); + } + ptr[iPlace] = '\0'; + return currentPos - lineStart; + } + + case SCI_GETENDSTYLED: + return pdoc->GetEndStyled(); + + case SCI_GETEOLMODE: + return pdoc->eolMode; + + case SCI_SETEOLMODE: + pdoc->eolMode = wParam; + break; + + case SCI_STARTSTYLING: + pdoc->StartStyling(wParam, static_cast(lParam)); + break; + + case SCI_SETSTYLING: + pdoc->SetStyleFor(wParam, static_cast(lParam)); + break; + + case SCI_SETSTYLINGEX: // Specify a complete styling buffer + if (lParam == 0) + return 0; + pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_SETBUFFEREDDRAW: + bufferedDraw = wParam != 0; + break; + + case SCI_GETBUFFEREDDRAW: + return bufferedDraw; + + case SCI_GETTWOPHASEDRAW: + return twoPhaseDraw; + + case SCI_SETTWOPHASEDRAW: + twoPhaseDraw = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_SETTABWIDTH: + if (wParam > 0) { + pdoc->tabInChars = wParam; + if (pdoc->indentInChars == 0) + pdoc->actualIndentInChars = pdoc->tabInChars; + } + InvalidateStyleRedraw(); + break; + + case SCI_GETTABWIDTH: + return pdoc->tabInChars; + + case SCI_SETINDENT: + pdoc->indentInChars = wParam; + if (pdoc->indentInChars != 0) + pdoc->actualIndentInChars = pdoc->indentInChars; + else + pdoc->actualIndentInChars = pdoc->tabInChars; + InvalidateStyleRedraw(); + break; + + case SCI_GETINDENT: + return pdoc->indentInChars; + + case SCI_SETUSETABS: + pdoc->useTabs = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_GETUSETABS: + return pdoc->useTabs; + + case SCI_SETLINEINDENTATION: + pdoc->SetLineIndentation(wParam, lParam); + break; + + case SCI_GETLINEINDENTATION: + return pdoc->GetLineIndentation(wParam); + + case SCI_GETLINEINDENTPOSITION: + return pdoc->GetLineIndentPosition(wParam); + + case SCI_SETTABINDENTS: + pdoc->tabIndents = wParam != 0; + break; + + case SCI_GETTABINDENTS: + return pdoc->tabIndents; + + case SCI_SETBACKSPACEUNINDENTS: + pdoc->backspaceUnindents = wParam != 0; + break; + + case SCI_GETBACKSPACEUNINDENTS: + return pdoc->backspaceUnindents; + + case SCI_SETMOUSEDWELLTIME: + dwellDelay = wParam; + ticksToDwell = dwellDelay; + break; + + case SCI_GETMOUSEDWELLTIME: + return dwellDelay; + + case SCI_WORDSTARTPOSITION: + return pdoc->ExtendWordSelect(wParam, -1, lParam != 0); + + case SCI_WORDENDPOSITION: + return pdoc->ExtendWordSelect(wParam, 1, lParam != 0); + + case SCI_SETWRAPMODE: + switch (wParam) { + case SC_WRAP_WORD: + wrapState = eWrapWord; + break; + case SC_WRAP_CHAR: + wrapState = eWrapChar; + break; + default: + wrapState = eWrapNone; + break; + } + xOffset = 0; + InvalidateStyleRedraw(); + ReconfigureScrollBars(); + break; + + case SCI_GETWRAPMODE: + return wrapState; + + case SCI_SETWRAPVISUALFLAGS: + wrapVisualFlags = wParam; + actualWrapVisualStartIndent = wrapVisualStartIndent; + if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (actualWrapVisualStartIndent == 0)) + actualWrapVisualStartIndent = 1; // must indent to show start visual + InvalidateStyleRedraw(); + ReconfigureScrollBars(); + break; + + case SCI_GETWRAPVISUALFLAGS: + return wrapVisualFlags; + + case SCI_SETWRAPVISUALFLAGSLOCATION: + wrapVisualFlagsLocation = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETWRAPVISUALFLAGSLOCATION: + return wrapVisualFlagsLocation; + + case SCI_SETWRAPSTARTINDENT: + wrapVisualStartIndent = wParam; + actualWrapVisualStartIndent = wrapVisualStartIndent; + if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (actualWrapVisualStartIndent == 0)) + actualWrapVisualStartIndent = 1; // must indent to show start visual + InvalidateStyleRedraw(); + ReconfigureScrollBars(); + break; + + case SCI_GETWRAPSTARTINDENT: + return wrapVisualStartIndent; + + case SCI_SETLAYOUTCACHE: + llc.SetLevel(wParam); + break; + + case SCI_GETLAYOUTCACHE: + return llc.GetLevel(); + + case SCI_SETPOSITIONCACHE: + posCache.SetSize(wParam); + break; + + case SCI_GETPOSITIONCACHE: + return posCache.GetSize(); + + case SCI_SETSCROLLWIDTH: + PLATFORM_ASSERT(wParam > 0); + if ((wParam > 0) && (wParam != static_cast(scrollWidth))) { + lineWidthMaxSeen = 0; + scrollWidth = wParam; + SetScrollBars(); + } + break; + + case SCI_GETSCROLLWIDTH: + return scrollWidth; + + case SCI_SETSCROLLWIDTHTRACKING: + trackLineWidth = wParam != 0; + break; + + case SCI_GETSCROLLWIDTHTRACKING: + return trackLineWidth; + + case SCI_LINESJOIN: + LinesJoin(); + break; + + case SCI_LINESSPLIT: + LinesSplit(wParam); + break; + + case SCI_TEXTWIDTH: + PLATFORM_ASSERT(wParam < vs.stylesSize); + PLATFORM_ASSERT(lParam); + return TextWidth(wParam, CharPtrFromSPtr(lParam)); + + case SCI_TEXTHEIGHT: + return vs.lineHeight; + + case SCI_SETENDATLASTLINE: + PLATFORM_ASSERT((wParam == 0) || (wParam == 1)); + if (endAtLastLine != (wParam != 0)) { + endAtLastLine = wParam != 0; + SetScrollBars(); + } + break; + + case SCI_GETENDATLASTLINE: + return endAtLastLine; + + case SCI_SETCARETSTICKY: + PLATFORM_ASSERT((wParam == 0) || (wParam == 1)); + if (caretSticky != (wParam != 0)) { + caretSticky = wParam != 0; + } + break; + + case SCI_GETCARETSTICKY: + return caretSticky; + + case SCI_TOGGLECARETSTICKY: + caretSticky = !caretSticky; + break; + + case SCI_GETCOLUMN: + return pdoc->GetColumn(wParam); + + case SCI_FINDCOLUMN: + return pdoc->FindColumn(wParam, lParam); + + case SCI_SETHSCROLLBAR : + if (horizontalScrollBarVisible != (wParam != 0)) { + horizontalScrollBarVisible = wParam != 0; + SetScrollBars(); + ReconfigureScrollBars(); + } + break; + + case SCI_GETHSCROLLBAR: + return horizontalScrollBarVisible; + + case SCI_SETVSCROLLBAR: + if (verticalScrollBarVisible != (wParam != 0)) { + verticalScrollBarVisible = wParam != 0; + SetScrollBars(); + ReconfigureScrollBars(); + } + break; + + case SCI_GETVSCROLLBAR: + return verticalScrollBarVisible; + + case SCI_SETINDENTATIONGUIDES: + vs.viewIndentationGuides = IndentView(wParam); + Redraw(); + break; + + case SCI_GETINDENTATIONGUIDES: + return vs.viewIndentationGuides; + + case SCI_SETHIGHLIGHTGUIDE: + if ((highlightGuideColumn != static_cast(wParam)) || (wParam > 0)) { + highlightGuideColumn = wParam; + Redraw(); + } + break; + + case SCI_GETHIGHLIGHTGUIDE: + return highlightGuideColumn; + + case SCI_GETLINEENDPOSITION: + return pdoc->LineEnd(wParam); + + case SCI_SETCODEPAGE: + if (ValidCodePage(wParam)) { + pdoc->dbcsCodePage = wParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETCODEPAGE: + return pdoc->dbcsCodePage; + + case SCI_SETUSEPALETTE: + palette.allowRealization = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_GETUSEPALETTE: + return palette.allowRealization; + + // Marker definition and setting + case SCI_MARKERDEFINE: + if (wParam <= MARKER_MAX) + vs.markers[wParam].markType = lParam; + InvalidateStyleData(); + RedrawSelMargin(); + break; + + case SCI_MARKERSYMBOLDEFINED: + if (wParam <= MARKER_MAX) + return vs.markers[wParam].markType; + else + return 0; + + case SCI_MARKERSETFORE: + if (wParam <= MARKER_MAX) + vs.markers[wParam].fore.desired = ColourDesired(lParam); + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERSETBACK: + if (wParam <= MARKER_MAX) + vs.markers[wParam].back.desired = ColourDesired(lParam); + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERSETALPHA: + if (wParam <= MARKER_MAX) + vs.markers[wParam].alpha = lParam; + InvalidateStyleRedraw(); + break; + case SCI_MARKERADD: { + int markerID = pdoc->AddMark(wParam, lParam); + return markerID; + } + case SCI_MARKERADDSET: + if (lParam != 0) + pdoc->AddMarkSet(wParam, lParam); + break; + + case SCI_MARKERDELETE: + pdoc->DeleteMark(wParam, lParam); + break; + + case SCI_MARKERDELETEALL: + pdoc->DeleteAllMarks(static_cast(wParam)); + break; + + case SCI_MARKERGET: + return pdoc->GetMark(wParam); + + case SCI_MARKERNEXT: { + int lt = pdoc->LinesTotal(); + for (int iLine = wParam; iLine < lt; iLine++) { + if ((pdoc->GetMark(iLine) & lParam) != 0) + return iLine; + } + } + return -1; + + case SCI_MARKERPREVIOUS: { + for (int iLine = wParam; iLine >= 0; iLine--) { + if ((pdoc->GetMark(iLine) & lParam) != 0) + return iLine; + } + } + return -1; + + case SCI_MARKERDEFINEPIXMAP: + if (wParam <= MARKER_MAX) { + vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam)); + }; + InvalidateStyleData(); + RedrawSelMargin(); + break; + + case SCI_SETMARGINTYPEN: + if (ValidMargin(wParam)) { + vs.ms[wParam].style = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINTYPEN: + if (ValidMargin(wParam)) + return vs.ms[wParam].style; + else + return 0; + + case SCI_SETMARGINWIDTHN: + if (ValidMargin(wParam)) { + // Short-circuit if the width is unchanged, to avoid unnecessary redraw. + if (vs.ms[wParam].width != lParam) { + vs.ms[wParam].width = lParam; + InvalidateStyleRedraw(); + } + } + break; + + case SCI_GETMARGINWIDTHN: + if (ValidMargin(wParam)) + return vs.ms[wParam].width; + else + return 0; + + case SCI_SETMARGINMASKN: + if (ValidMargin(wParam)) { + vs.ms[wParam].mask = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINMASKN: + if (ValidMargin(wParam)) + return vs.ms[wParam].mask; + else + return 0; + + case SCI_SETMARGINSENSITIVEN: + if (ValidMargin(wParam)) { + vs.ms[wParam].sensitive = lParam != 0; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINSENSITIVEN: + if (ValidMargin(wParam)) + return vs.ms[wParam].sensitive ? 1 : 0; + else + return 0; + + case SCI_STYLECLEARALL: + vs.ClearStyles(); + InvalidateStyleRedraw(); + break; + + case SCI_STYLESETFORE: + case SCI_STYLESETBACK: + case SCI_STYLESETBOLD: + case SCI_STYLESETITALIC: + case SCI_STYLESETEOLFILLED: + case SCI_STYLESETSIZE: + case SCI_STYLESETFONT: + case SCI_STYLESETUNDERLINE: + case SCI_STYLESETCASE: + case SCI_STYLESETCHARACTERSET: + case SCI_STYLESETVISIBLE: + case SCI_STYLESETCHANGEABLE: + case SCI_STYLESETHOTSPOT: + StyleSetMessage(iMessage, wParam, lParam); + break; + + case SCI_STYLEGETFORE: + case SCI_STYLEGETBACK: + case SCI_STYLEGETBOLD: + case SCI_STYLEGETITALIC: + case SCI_STYLEGETEOLFILLED: + case SCI_STYLEGETSIZE: + case SCI_STYLEGETFONT: + case SCI_STYLEGETUNDERLINE: + case SCI_STYLEGETCASE: + case SCI_STYLEGETCHARACTERSET: + case SCI_STYLEGETVISIBLE: + case SCI_STYLEGETCHANGEABLE: + case SCI_STYLEGETHOTSPOT: + return StyleGetMessage(iMessage, wParam, lParam); + + case SCI_STYLERESETDEFAULT: + vs.ResetDefaultStyle(); + InvalidateStyleRedraw(); + break; + case SCI_SETSTYLEBITS: + vs.EnsureStyle((1 << wParam) - 1); + pdoc->SetStylingBits(wParam); + break; + + case SCI_GETSTYLEBITS: + return pdoc->stylingBits; + + case SCI_SETLINESTATE: + return pdoc->SetLineState(wParam, lParam); + + case SCI_GETLINESTATE: + return pdoc->GetLineState(wParam); + + case SCI_GETMAXLINESTATE: + return pdoc->GetMaxLineState(); + + case SCI_GETCARETLINEVISIBLE: + return vs.showCaretLineBackground; + case SCI_SETCARETLINEVISIBLE: + vs.showCaretLineBackground = wParam != 0; + InvalidateStyleRedraw(); + break; + case SCI_GETCARETLINEBACK: + return vs.caretLineBackground.desired.AsLong(); + case SCI_SETCARETLINEBACK: + vs.caretLineBackground.desired = wParam; + InvalidateStyleRedraw(); + break; + case SCI_GETCARETLINEBACKALPHA: + return vs.caretLineAlpha; + case SCI_SETCARETLINEBACKALPHA: + vs.caretLineAlpha = wParam; + InvalidateStyleRedraw(); + break; + + // Folding messages + + case SCI_VISIBLEFROMDOCLINE: + return cs.DisplayFromDoc(wParam); + + case SCI_DOCLINEFROMVISIBLE: + return cs.DocFromDisplay(wParam); + + case SCI_WRAPCOUNT: + return WrapCount(wParam); + + case SCI_SETFOLDLEVEL: { + int prev = pdoc->SetLevel(wParam, lParam); + if (prev != lParam) + RedrawSelMargin(); + return prev; + } + + case SCI_GETFOLDLEVEL: + return pdoc->GetLevel(wParam); + + case SCI_GETLASTCHILD: + return pdoc->GetLastChild(wParam, lParam); + + case SCI_GETFOLDPARENT: + return pdoc->GetFoldParent(wParam); + + case SCI_SHOWLINES: + cs.SetVisible(wParam, lParam, true); + SetScrollBars(); + Redraw(); + break; + + case SCI_HIDELINES: + if (wParam > 0) + cs.SetVisible(wParam, lParam, false); + SetScrollBars(); + Redraw(); + break; + + case SCI_GETLINEVISIBLE: + return cs.GetVisible(wParam); + + case SCI_SETFOLDEXPANDED: + if (cs.SetExpanded(wParam, lParam != 0)) { + RedrawSelMargin(); + } + break; + + case SCI_GETFOLDEXPANDED: + return cs.GetExpanded(wParam); + + case SCI_SETFOLDFLAGS: + foldFlags = wParam; + Redraw(); + break; + + case SCI_TOGGLEFOLD: + ToggleContraction(wParam); + break; + + case SCI_ENSUREVISIBLE: + EnsureLineVisible(wParam, false); + break; + + case SCI_ENSUREVISIBLEENFORCEPOLICY: + EnsureLineVisible(wParam, true); + break; + + case SCI_SEARCHANCHOR: + SearchAnchor(); + break; + + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + return SearchText(iMessage, wParam, lParam); + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETCARETPOLICY: // Deprecated + caretXPolicy = caretYPolicy = wParam; + caretXSlop = caretYSlop = lParam; + break; +#endif + + case SCI_SETXCARETPOLICY: + caretXPolicy = wParam; + caretXSlop = lParam; + break; + + case SCI_SETYCARETPOLICY: + caretYPolicy = wParam; + caretYSlop = lParam; + break; + + case SCI_SETVISIBLEPOLICY: + visiblePolicy = wParam; + visibleSlop = lParam; + break; + + case SCI_LINESONSCREEN: + return LinesOnScreen(); + + case SCI_SETSELFORE: + vs.selforeset = wParam != 0; + vs.selforeground.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETSELBACK: + vs.selbackset = wParam != 0; + vs.selbackground.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETSELALPHA: + vs.selAlpha = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETSELALPHA: + return vs.selAlpha; + + case SCI_GETSELEOLFILLED: + return vs.selEOLFilled; + + case SCI_SETSELEOLFILLED: + vs.selEOLFilled = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_SETWHITESPACEFORE: + vs.whitespaceForegroundSet = wParam != 0; + vs.whitespaceForeground.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETWHITESPACEBACK: + vs.whitespaceBackgroundSet = wParam != 0; + vs.whitespaceBackground.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETCARETFORE: + vs.caretcolour.desired = ColourDesired(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_GETCARETFORE: + return vs.caretcolour.desired.AsLong(); + + case SCI_SETCARETSTYLE: + //if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK) + if ( wParam <= CARETSTYLE_BLOCK ) + vs.caretStyle = wParam; + else + /* Default to the line caret */ + vs.caretStyle = CARETSTYLE_LINE; + InvalidateStyleRedraw(); + break; + + case SCI_GETCARETSTYLE: + return vs.caretStyle; + + case SCI_SETCARETWIDTH: + if (wParam <= 0) + vs.caretWidth = 0; + else if (wParam >= 3) + vs.caretWidth = 3; + else + vs.caretWidth = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETCARETWIDTH: + return vs.caretWidth; + + case SCI_ASSIGNCMDKEY: + kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), + Platform::HighShortFromLong(wParam), lParam); + break; + + case SCI_CLEARCMDKEY: + kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), + Platform::HighShortFromLong(wParam), SCI_NULL); + break; + + case SCI_CLEARALLCMDKEYS: + kmap.Clear(); + break; + + case SCI_INDICSETSTYLE: + if (wParam <= INDIC_MAX) { + vs.indicators[wParam].style = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETSTYLE: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0; + + case SCI_INDICSETFORE: + if (wParam <= INDIC_MAX) { + vs.indicators[wParam].fore.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETFORE: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0; + + case SCI_INDICSETUNDER: + if (wParam <= INDIC_MAX) { + vs.indicators[wParam].under = lParam != 0; + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETUNDER: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0; + + case SCI_INDICSETALPHA: + if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 100) { + vs.indicators[wParam].fillAlpha = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETALPHA: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0; + + case SCI_SETINDICATORCURRENT: + pdoc->decorations.SetCurrentIndicator(wParam); + break; + case SCI_GETINDICATORCURRENT: + return pdoc->decorations.GetCurrentIndicator(); + case SCI_SETINDICATORVALUE: + pdoc->decorations.SetCurrentValue(wParam); + break; + case SCI_GETINDICATORVALUE: + return pdoc->decorations.GetCurrentValue(); + + case SCI_INDICATORFILLRANGE: + pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam); + break; + + case SCI_INDICATORCLEARRANGE: + pdoc->DecorationFillRange(wParam, 0, lParam); + break; + + case SCI_INDICATORALLONFOR: + return pdoc->decorations.AllOnFor(wParam); + + case SCI_INDICATORVALUEAT: + return pdoc->decorations.ValueAt(wParam, lParam); + + case SCI_INDICATORSTART: + return pdoc->decorations.Start(wParam, lParam); + + case SCI_INDICATOREND: + return pdoc->decorations.End(wParam, lParam); + + case SCI_LINEDOWN: + case SCI_LINEDOWNEXTEND: + case SCI_PARADOWN: + case SCI_PARADOWNEXTEND: + case SCI_LINEUP: + case SCI_LINEUPEXTEND: + case SCI_PARAUP: + case SCI_PARAUPEXTEND: + case SCI_CHARLEFT: + case SCI_CHARLEFTEXTEND: + case SCI_CHARRIGHT: + case SCI_CHARRIGHTEXTEND: + case SCI_WORDLEFT: + case SCI_WORDLEFTEXTEND: + case SCI_WORDRIGHT: + case SCI_WORDRIGHTEXTEND: + case SCI_WORDLEFTEND: + case SCI_WORDLEFTENDEXTEND: + case SCI_WORDRIGHTEND: + case SCI_WORDRIGHTENDEXTEND: + case SCI_HOME: + case SCI_HOMEEXTEND: + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + case SCI_HOMEWRAP: + case SCI_HOMEWRAPEXTEND: + case SCI_LINEENDWRAP: + case SCI_LINEENDWRAPEXTEND: + case SCI_DOCUMENTSTART: + case SCI_DOCUMENTSTARTEXTEND: + case SCI_DOCUMENTEND: + case SCI_DOCUMENTENDEXTEND: + + case SCI_STUTTEREDPAGEUP: + case SCI_STUTTEREDPAGEUPEXTEND: + case SCI_STUTTEREDPAGEDOWN: + case SCI_STUTTEREDPAGEDOWNEXTEND: + + case SCI_PAGEUP: + case SCI_PAGEUPEXTEND: + case SCI_PAGEDOWN: + case SCI_PAGEDOWNEXTEND: + case SCI_EDITTOGGLEOVERTYPE: + case SCI_CANCEL: + case SCI_DELETEBACK: + case SCI_TAB: + case SCI_BACKTAB: + case SCI_NEWLINE: + case SCI_FORMFEED: + case SCI_VCHOME: + case SCI_VCHOMEEXTEND: + case SCI_VCHOMEWRAP: + case SCI_VCHOMEWRAPEXTEND: + case SCI_ZOOMIN: + case SCI_ZOOMOUT: + case SCI_DELWORDLEFT: + case SCI_DELWORDRIGHT: + case SCI_DELWORDRIGHTEND: + case SCI_DELLINELEFT: + case SCI_DELLINERIGHT: + case SCI_LINECOPY: + case SCI_LINECUT: + case SCI_LINEDELETE: + case SCI_LINETRANSPOSE: + case SCI_LINEDUPLICATE: + case SCI_LOWERCASE: + case SCI_UPPERCASE: + case SCI_LINESCROLLDOWN: + case SCI_LINESCROLLUP: + case SCI_WORDPARTLEFT: + case SCI_WORDPARTLEFTEXTEND: + case SCI_WORDPARTRIGHT: + case SCI_WORDPARTRIGHTEXTEND: + case SCI_DELETEBACKNOTLINE: + case SCI_HOMEDISPLAY: + case SCI_HOMEDISPLAYEXTEND: + case SCI_LINEENDDISPLAY: + case SCI_LINEENDDISPLAYEXTEND: + case SCI_LINEDOWNRECTEXTEND: + case SCI_LINEUPRECTEXTEND: + case SCI_CHARLEFTRECTEXTEND: + case SCI_CHARRIGHTRECTEXTEND: + case SCI_HOMERECTEXTEND: + case SCI_VCHOMERECTEXTEND: + case SCI_LINEENDRECTEXTEND: + case SCI_PAGEUPRECTEXTEND: + case SCI_PAGEDOWNRECTEXTEND: + case SCI_SELECTIONDUPLICATE: + return KeyCommand(iMessage); + + case SCI_BRACEHIGHLIGHT: + SetBraceHighlight(static_cast(wParam), lParam, STYLE_BRACELIGHT); + break; + + case SCI_BRACEBADLIGHT: + SetBraceHighlight(static_cast(wParam), -1, STYLE_BRACEBAD); + break; + + case SCI_BRACEMATCH: + // wParam is position of char to find brace for, + // lParam is maximum amount of text to restyle to find it + return pdoc->BraceMatch(wParam, lParam); + + case SCI_GETVIEWEOL: + return vs.viewEOL; + + case SCI_SETVIEWEOL: + vs.viewEOL = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_SETZOOM: + vs.zoomLevel = wParam; + InvalidateStyleRedraw(); + NotifyZoom(); + break; + + case SCI_GETZOOM: + return vs.zoomLevel; + + case SCI_GETEDGECOLUMN: + return theEdge; + + case SCI_SETEDGECOLUMN: + theEdge = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEDGEMODE: + return vs.edgeState; + + case SCI_SETEDGEMODE: + vs.edgeState = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEDGECOLOUR: + return vs.edgecolour.desired.AsLong(); + + case SCI_SETEDGECOLOUR: + vs.edgecolour.desired = ColourDesired(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_GETDOCPOINTER: + return reinterpret_cast(pdoc); + + case SCI_SETDOCPOINTER: + CancelModes(); + SetDocPointer(reinterpret_cast(lParam)); + return 0; + + case SCI_CREATEDOCUMENT: { + Document *doc = new Document(); + if (doc) { + doc->AddRef(); + } + return reinterpret_cast(doc); + } + + case SCI_ADDREFDOCUMENT: + (reinterpret_cast(lParam))->AddRef(); + break; + + case SCI_RELEASEDOCUMENT: + (reinterpret_cast(lParam))->Release(); + break; + + case SCI_SETMODEVENTMASK: + modEventMask = wParam; + return 0; + + case SCI_GETMODEVENTMASK: + return modEventMask; + + case SCI_CONVERTEOLS: + pdoc->ConvertLineEnds(wParam); + SetSelection(currentPos, anchor); // Ensure selection inside document + return 0; + + case SCI_SETLENGTHFORENCODE: + lengthForEncode = wParam; + return 0; + + case SCI_SELECTIONISRECTANGLE: + return selType == selRectangle ? 1 : 0; + + case SCI_SETSELECTIONMODE: { + switch (wParam) { + case SC_SEL_STREAM: + moveExtendsSelection = !moveExtendsSelection || (selType != selStream); + selType = selStream; + break; + case SC_SEL_RECTANGLE: + moveExtendsSelection = !moveExtendsSelection || (selType != selRectangle); + selType = selRectangle; + break; + case SC_SEL_LINES: + moveExtendsSelection = !moveExtendsSelection || (selType != selLines); + selType = selLines; + break; + default: + moveExtendsSelection = !moveExtendsSelection || (selType != selStream); + selType = selStream; + } + InvalidateSelection(currentPos, anchor, true); + } + case SCI_GETSELECTIONMODE: + switch (selType) { + case selStream: + return SC_SEL_STREAM; + case selRectangle: + return SC_SEL_RECTANGLE; + case selLines: + return SC_SEL_LINES; + default: // ?! + return SC_SEL_STREAM; + } + case SCI_GETLINESELSTARTPOSITION: { + SelectionLineIterator lineIterator(this); + lineIterator.SetAt(wParam); + return lineIterator.startPos; + } + case SCI_GETLINESELENDPOSITION: { + SelectionLineIterator lineIterator(this); + lineIterator.SetAt(wParam); + return lineIterator.endPos; + } + + case SCI_SETOVERTYPE: + inOverstrike = wParam != 0; + break; + + case SCI_GETOVERTYPE: + return inOverstrike ? 1 : 0; + + case SCI_SETFOCUS: + SetFocusState(wParam != 0); + break; + + case SCI_GETFOCUS: + return hasFocus; + + case SCI_SETSTATUS: + errorStatus = wParam; + break; + + case SCI_GETSTATUS: + return errorStatus; + + case SCI_SETMOUSEDOWNCAPTURES: + mouseDownCaptures = wParam != 0; + break; + + case SCI_GETMOUSEDOWNCAPTURES: + return mouseDownCaptures; + + case SCI_SETCURSOR: + cursorMode = wParam; + DisplayCursor(Window::cursorText); + break; + + case SCI_GETCURSOR: + return cursorMode; + + case SCI_SETCONTROLCHARSYMBOL: + controlCharSymbol = wParam; + break; + + case SCI_GETCONTROLCHARSYMBOL: + return controlCharSymbol; + + case SCI_STARTRECORD: + recordingMacro = true; + return 0; + + case SCI_STOPRECORD: + recordingMacro = false; + return 0; + + case SCI_MOVECARETINSIDEVIEW: + MoveCaretInsideView(); + break; + + case SCI_SETFOLDMARGINCOLOUR: + vs.foldmarginColourSet = wParam != 0; + vs.foldmarginColour.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETFOLDMARGINHICOLOUR: + vs.foldmarginHighlightColourSet = wParam != 0; + vs.foldmarginHighlightColour.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETHOTSPOTACTIVEFORE: + vs.hotspotForegroundSet = wParam != 0; + vs.hotspotForeground.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_GETHOTSPOTACTIVEFORE: + return vs.hotspotForeground.desired.AsLong(); + + case SCI_SETHOTSPOTACTIVEBACK: + vs.hotspotBackgroundSet = wParam != 0; + vs.hotspotBackground.desired = ColourDesired(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_GETHOTSPOTACTIVEBACK: + return vs.hotspotBackground.desired.AsLong(); + + case SCI_SETHOTSPOTACTIVEUNDERLINE: + vs.hotspotUnderline = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_GETHOTSPOTACTIVEUNDERLINE: + return vs.hotspotUnderline ? 1 : 0; + + case SCI_SETHOTSPOTSINGLELINE: + vs.hotspotSingleLine = wParam != 0; + InvalidateStyleRedraw(); + break; + + case SCI_GETHOTSPOTSINGLELINE: + return vs.hotspotSingleLine ? 1 : 0; + + case SCI_SETPASTECONVERTENDINGS: + convertPastes = wParam != 0; + break; + + case SCI_GETPASTECONVERTENDINGS: + return convertPastes ? 1 : 0; + + case SCI_GETCHARACTERPOINTER: + return reinterpret_cast(pdoc->BufferPointer()); + + case SCI_SETEXTRAASCENT: + vs.extraAscent = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEXTRAASCENT: + return vs.extraAscent; + + case SCI_SETEXTRADESCENT: + vs.extraDescent = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEXTRADESCENT: + return vs.extraDescent; + + case SCI_MARGINSETSTYLEOFFSET: + vs.marginStyleOffset = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_MARGINGETSTYLEOFFSET: + return vs.marginStyleOffset; + + case SCI_MARGINSETTEXT: + pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_MARGINGETTEXT: { + const StyledText st = pdoc->MarginStyledText(wParam); + if (lParam) { + if (st.text) + memcpy(CharPtrFromSPtr(lParam), st.text, st.length); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return st.length; + } + + case SCI_MARGINSETSTYLE: + pdoc->MarginSetStyle(wParam, lParam); + break; + + case SCI_MARGINGETSTYLE: { + const StyledText st = pdoc->MarginStyledText(wParam); + return st.style; + } + + case SCI_MARGINSETSTYLES: + pdoc->MarginSetStyles(wParam, reinterpret_cast(lParam)); + break; + + case SCI_MARGINGETSTYLES: { + const StyledText st = pdoc->MarginStyledText(wParam); + if (lParam) { + if (st.styles) + memcpy(CharPtrFromSPtr(lParam), st.styles, st.length); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return st.styles ? st.length : 0; + } + + case SCI_MARGINTEXTCLEARALL: + pdoc->MarginClearAll(); + break; + + case SCI_ANNOTATIONSETTEXT: + pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_ANNOTATIONGETTEXT: { + const StyledText st = pdoc->AnnotationStyledText(wParam); + if (lParam) { + if (st.text) + memcpy(CharPtrFromSPtr(lParam), st.text, st.length); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return st.length; + } + + case SCI_ANNOTATIONGETSTYLE: { + const StyledText st = pdoc->AnnotationStyledText(wParam); + return st.style; + } + + case SCI_ANNOTATIONSETSTYLE: + pdoc->AnnotationSetStyle(wParam, lParam); + break; + + case SCI_ANNOTATIONSETSTYLES: + pdoc->AnnotationSetStyles(wParam, reinterpret_cast(lParam)); + break; + + case SCI_ANNOTATIONGETSTYLES: { + const StyledText st = pdoc->AnnotationStyledText(wParam); + if (lParam) { + if (st.styles) + memcpy(CharPtrFromSPtr(lParam), st.styles, st.length); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return st.styles ? st.length : 0; + } + + case SCI_ANNOTATIONGETLINES: + return pdoc->AnnotationLines(wParam); + + case SCI_ANNOTATIONCLEARALL: + pdoc->AnnotationClearAll(); + break; + + case SCI_ANNOTATIONSETVISIBLE: + SetAnnotationVisible(wParam); + break; + + case SCI_ANNOTATIONGETVISIBLE: + return vs.annotationVisible; + + case SCI_ANNOTATIONSETSTYLEOFFSET: + vs.annotationStyleOffset = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_ANNOTATIONGETSTYLEOFFSET: + return vs.annotationStyleOffset; + + case SCI_ADDUNDOACTION: + pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE); + break; + + default: + return DefWndProc(iMessage, wParam, lParam); + } + //Platform::DebugPrintf("end wnd proc\n"); + return 0l; +} diff --git a/harbour/contrib/hbide/qscintilla/Editor.h b/harbour/contrib/hbide/qscintilla/Editor.h new file mode 100644 index 0000000000..35564ca8cb --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Editor.h @@ -0,0 +1,527 @@ +// Scintilla source code edit control +/** @file Editor.h + ** Defines the main editor class. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITOR_H +#define EDITOR_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class Caret { +public: + bool active; + bool on; + int period; + + Caret(); +}; + +/** + */ +class Timer { +public: + bool ticking; + int ticksToWait; + enum {tickSize = 100}; + TickerID tickerID; + + Timer(); +}; + +/** + */ +class Idler { +public: + bool state; + IdlerID idlerID; + + Idler(); +}; + +/** + * Hold a piece of text selected for copying or dragging. + * The text is expected to hold a terminating '\0' and this is counted in len. + */ +class SelectionText { +public: + char *s; + int len; + bool rectangular; + bool lineCopy; + int codePage; + int characterSet; + SelectionText() : s(0), len(0), rectangular(false), lineCopy(false), codePage(0), characterSet(0) {} + ~SelectionText() { + Free(); + } + void Free() { + Set(0, 0, 0, 0, false, false); + } + void Set(char *s_, int len_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) { + delete []s; + s = s_; + if (s) + len = len_; + else + len = 0; + codePage = codePage_; + characterSet = characterSet_; + rectangular = rectangular_; + lineCopy = lineCopy_; + } + void Copy(const char *s_, int len_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) { + delete []s; + s = new char[len_]; + if (s) { + len = len_; + for (int i = 0; i < len_; i++) { + s[i] = s_[i]; + } + } else { + len = 0; + } + codePage = codePage_; + characterSet = characterSet_; + rectangular = rectangular_; + lineCopy = lineCopy_; + } + void Copy(const SelectionText &other) { + Copy(other.s, other.len, other.codePage, other.characterSet, other.rectangular, other.lineCopy); + } +}; + +/** + */ +class Editor : public DocWatcher { + // Private so Editor objects can not be copied + Editor(const Editor &) : DocWatcher() {} + Editor &operator=(const Editor &) { return *this; } + +protected: // ScintillaBase subclass needs access to much of Editor + + /** On GTK+, Scintilla is a container widget holding two scroll bars + * whereas on Windows there is just one window with both scroll bars turned on. */ + Window wMain; ///< The Scintilla parent window + + /** Style resources may be expensive to allocate so are cached between uses. + * When a style attribute is changed, this cache is flushed. */ + bool stylesValid; + ViewStyle vs; + Palette palette; + + int printMagnification; + int printColourMode; + int printWrapState; + int cursorMode; + int controlCharSymbol; + + bool hasFocus; + bool hideSelection; + bool inOverstrike; + int errorStatus; + bool mouseDownCaptures; + + /** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to + * the screen. This avoids flashing but is about 30% slower. */ + bool bufferedDraw; + /** In twoPhaseDraw mode, drawing is performed in two phases, first the background + * and then the foreground. This avoids chopping off characters that overlap the next run. */ + bool twoPhaseDraw; + + int xOffset; ///< Horizontal scrolled amount in pixels + int xCaretMargin; ///< Ensure this many pixels visible on both sides of caret + bool horizontalScrollBarVisible; + int scrollWidth; + bool trackLineWidth; + int lineWidthMaxSeen; + bool verticalScrollBarVisible; + bool endAtLastLine; + bool caretSticky; + + Surface *pixmapLine; + Surface *pixmapSelMargin; + Surface *pixmapSelPattern; + Surface *pixmapIndentGuide; + Surface *pixmapIndentGuideHighlight; + + LineLayoutCache llc; + PositionCache posCache; + + KeyMap kmap; + + Caret caret; + Timer timer; + Timer autoScrollTimer; + enum { autoScrollDelay = 200 }; + + Idler idler; + + Point lastClick; + unsigned int lastClickTime; + int dwellDelay; + int ticksToDwell; + bool dwelling; + enum { selChar, selWord, selLine } selectionType; + Point ptMouseLast; + enum { ddNone, ddInitial, ddDragging } inDragDrop; + bool dropWentOutside; + int posDrag; + int posDrop; + int lastXChosen; + int lineAnchor; + int originalAnchorPos; + int currentPos; + int anchor; + int targetStart; + int targetEnd; + int searchFlags; + int topLine; + int posTopLine; + int lengthForEncode; + + bool needUpdateUI; + Position braces[2]; + int bracesMatchStyle; + int highlightGuideColumn; + + int theEdge; + + enum { notPainting, painting, paintAbandoned } paintState; + PRectangle rcPaint; + bool paintingAllText; + + int modEventMask; + + SelectionText drag; + enum selTypes { noSel, selStream, selRectangle, selLines }; + selTypes selType; + bool moveExtendsSelection; + int xStartSelect; ///< x position of start of rectangular selection + int xEndSelect; ///< x position of end of rectangular selection + bool primarySelection; + + int caretXPolicy; + int caretXSlop; ///< Ensure this many pixels visible on both sides of caret + + int caretYPolicy; + int caretYSlop; ///< Ensure this many lines visible on both sides of caret + + int visiblePolicy; + int visibleSlop; + + int searchAnchor; + + bool recordingMacro; + + int foldFlags; + ContractionState cs; + + // Hotspot support + int hsStart; + int hsEnd; + + // Wrapping support + enum { eWrapNone, eWrapWord, eWrapChar } wrapState; + enum { wrapLineLarge = 0x7ffffff }; + int wrapWidth; + int wrapStart; + int wrapEnd; + int wrapVisualFlags; + int wrapVisualFlagsLocation; + int wrapVisualStartIndent; + int actualWrapVisualStartIndent; + + bool convertPastes; + + Document *pdoc; + + Editor(); + virtual ~Editor(); + virtual void Initialise() = 0; + virtual void Finalise(); + + void InvalidateStyleData(); + void InvalidateStyleRedraw(); + virtual void RefreshColourPalette(Palette &pal, bool want); + void RefreshStyleData(); + void DropGraphics(); + + virtual PRectangle GetClientRectangle(); + PRectangle GetTextRectangle(); + + int LinesOnScreen(); + int LinesToScroll(); + int MaxScrollPos(); + Point LocationFromPosition(int pos); + int XFromPosition(int pos); + int PositionFromLocation(Point pt); + int PositionFromLocationClose(Point pt); + int PositionFromLineX(int line, int x); + int LineFromLocation(Point pt); + void SetTopLine(int topLineNew); + + bool AbandonPaint(); + void RedrawRect(PRectangle rc); + void Redraw(); + void RedrawSelMargin(int line=-1); + PRectangle RectangleFromRange(int start, int end); + void InvalidateRange(int start, int end); + + int CurrentPosition(); + bool SelectionEmpty(); + int SelectionStart(); + int SelectionEnd(); + void SetRectangularRange(); + void InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection); + void SetSelection(int currentPos_, int anchor_); + void SetSelection(int currentPos_); + void SetEmptySelection(int currentPos_); + bool RangeContainsProtected(int start, int end) const; + bool SelectionContainsProtected(); + int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); + int MovePositionTo(int newPos, selTypes sel=noSel, bool ensureVisible=true); + int MovePositionSoVisible(int pos, int moveDir); + void SetLastXChosen(); + + void ScrollTo(int line, bool moveThumb=true); + virtual void ScrollText(int linesToMove); + void HorizontalScrollTo(int xPos); + void MoveCaretInsideView(bool ensureVisible=true); + int DisplayFromPosition(int pos); + void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true); + void ShowCaretAtCurrentPosition(); + void DropCaret(); + void InvalidateCaret(); + virtual void UpdateSystemCaret(); + + void NeedWrapping(int docLineStart = 0, int docLineEnd = wrapLineLarge); + bool WrapOneLine(Surface *surface, int lineToWrap); + bool WrapLines(bool fullWrap, int priorityWrapLineStart); + void LinesJoin(); + void LinesSplit(int pixelWidth); + + int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault); + void PaintSelMargin(Surface *surface, PRectangle &rc); + LineLayout *RetrieveLineLayout(int lineNumber); + void LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, + int width=LineLayout::wrapWidthInfinite); + ColourAllocated SelectionBackground(ViewStyle &vsDraw); + ColourAllocated TextBackground(ViewStyle &vsDraw, bool overrideBackground, ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll); + void DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight); + void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourAllocated wrapColour); + void DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, + int line, int lineEnd, int xStart, int subLine, int subLineStart, + bool overrideBackground, ColourAllocated background, + bool drawWrapMark, ColourAllocated wrapColour); + void DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under); + void DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine); + void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine=0); + void DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret); + void RefreshPixMaps(Surface *surfaceWindow); + void Paint(Surface *surfaceWindow, PRectangle rcArea); + long FormatRange(bool draw, RangeToFormat *pfr); + int TextWidth(int style, const char *text); + + virtual void SetVerticalScrollPos() = 0; + virtual void SetHorizontalScrollPos() = 0; + virtual bool ModifyScrollBars(int nMax, int nPage) = 0; + virtual void ReconfigureScrollBars(); + void SetScrollBars(); + void ChangeSize(); + + void AddChar(char ch); + virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); + void ClearSelection(); + void ClearAll(); + void ClearDocumentStyle(); + void Cut(); + void PasteRectangular(int pos, const char *ptr, int len); + virtual void Copy() = 0; + virtual void CopyAllowLine(); + virtual bool CanPaste(); + virtual void Paste() = 0; + void Clear(); + void SelectAll(); + void Undo(); + void Redo(); + void DelChar(); + void DelCharBack(bool allowLineStartDeletion); + virtual void ClaimSelection() = 0; + + virtual void NotifyChange() = 0; + virtual void NotifyFocus(bool focus); + virtual int GetCtrlID() { return ctrlID; } + virtual void NotifyParent(SCNotification scn) = 0; + virtual void NotifyStyleToNeeded(int endStyleNeeded); + void NotifyChar(int ch); + void NotifyMove(int position); + void NotifySavePoint(bool isSavePoint); + void NotifyModifyAttempt(); + virtual void NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt); + void NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt); + void NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt); + void NotifyUpdateUI(); + void NotifyPainted(); + void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt); + bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt); + void NotifyNeedShown(int pos, int len); + void NotifyDwelling(Point pt, bool state); + void NotifyZoom(); + + void NotifyModifyAttempt(Document *document, void *userData); + void NotifySavePoint(Document *document, void *userData, bool atSavePoint); + void CheckModificationForWrap(DocModification mh); + void NotifyModified(Document *document, DocModification mh, void *userData); + void NotifyDeleted(Document *document, void *userData); + void NotifyStyleNeeded(Document *doc, void *userData, int endPos); + void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + + void PageMove(int direction, selTypes sel=noSel, bool stuttered = false); + void ChangeCaseOfSelection(bool makeUpperCase); + void LineTranspose(); + void Duplicate(bool forLine); + virtual void CancelModes(); + void NewLine(); + void CursorUpOrDown(int direction, selTypes sel=noSel); + void ParaUpOrDown(int direction, selTypes sel=noSel); + int StartEndDisplayLine(int pos, bool start); + virtual int KeyCommand(unsigned int iMessage); + virtual int KeyDefault(int /* key */, int /*modifiers*/); + int KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed=0); + + int GetWhitespaceVisible(); + void SetWhitespaceVisible(int view); + + void Indent(bool forwards); + + long FindText(uptr_t wParam, sptr_t lParam); + void SearchAnchor(); + long SearchText(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + long SearchInTarget(const char *text, int length); + void GoToLine(int lineNo); + + virtual void CopyToClipboard(const SelectionText &selectedText) = 0; + char *CopyRange(int start, int end); + void CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end); + void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false); + void CopyRangeToClipboard(int start, int end); + void CopyText(int length, const char *text); + void SetDragPosition(int newPos); + virtual void DisplayCursor(Window::Cursor c); + virtual bool DragThreshold(Point ptStart, Point ptNow); + virtual void StartDrag(); + void DropAt(int position, const char *value, bool moving, bool rectangular); + /** PositionInSelection returns 0 if position in selection, -1 if position before selection, and 1 if after. + * Before means either before any line of selection or before selection on its line, with a similar meaning to after. */ + int PositionInSelection(int pos); + bool PointInSelection(Point pt); + bool PointInSelMargin(Point pt); + void LineSelection(int lineCurrent_, int lineAnchor_); + void DwellEnd(bool mouseMoved); + virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); + void ButtonMove(Point pt); + void ButtonUp(Point pt, unsigned int curTime, bool ctrl); + + void Tick(); + bool Idle(); + virtual void SetTicking(bool on) = 0; + virtual bool SetIdle(bool) { return false; } + virtual void SetMouseCapture(bool on) = 0; + virtual bool HaveMouseCapture() = 0; + void SetFocusState(bool focusState); + + virtual bool PaintContains(PRectangle rc); + bool PaintContainsMargin(); + void CheckForChangeOutsidePaint(Range r); + void SetBraceHighlight(Position pos0, Position pos1, int matchStyle); + + void SetAnnotationHeights(int start, int end); + void SetDocPointer(Document *document); + + void SetAnnotationVisible(int visible); + + void Expand(int &line, bool doExpand); + void ToggleContraction(int line); + void EnsureLineVisible(int lineDoc, bool enforcePolicy); + int ReplaceTarget(bool replacePatterns, const char *text, int length=-1); + + bool PositionIsHotspot(int position); + bool PointIsHotspot(Point pt); + void SetHotSpotRange(Point *pt); + void GetHotSpotRange(int& hsStart, int& hsEnd); + + int CodePage() const; + virtual bool ValidCodePage(int /* codePage */) const { return true; } + int WrapCount(int line); + void AddStyledText(char *buffer, int appendLength); + + virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) = 0; + void StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + sptr_t StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + + static const char *StringFromEOLMode(int eolMode); + +public: + // Public so the COM thunks can access it. + bool IsUnicodeMode() const; + // Public so scintilla_send_message can use it. + virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); + // Public so scintilla_set_id can use it. + int ctrlID; + friend class AutoSurface; + friend class SelectionLineIterator; +}; + +/** + * A smart pointer class to ensure Surfaces are set up and deleted correctly. + */ +class AutoSurface { +private: + Surface *surf; +public: + AutoSurface(Editor *ed) : surf(0) { + if (ed->wMain.GetID()) { + surf = Surface::Allocate(); + if (surf) { + surf->Init(ed->wMain.GetID()); + surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); + surf->SetDBCSMode(ed->CodePage()); + } + } + } + AutoSurface(SurfaceID sid, Editor *ed) : surf(0) { + if (ed->wMain.GetID()) { + surf = Surface::Allocate(); + if (surf) { + surf->Init(sid, ed->wMain.GetID()); + surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); + surf->SetDBCSMode(ed->CodePage()); + } + } + } + ~AutoSurface() { + delete surf; + } + Surface *operator->() const { + return surf; + } + operator Surface *() const { + return surf; + } +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/ExternalLexer.cpp b/harbour/contrib/hbide/qscintilla/ExternalLexer.cpp new file mode 100644 index 0000000000..a4e29e314a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ExternalLexer.cpp @@ -0,0 +1,263 @@ +// Scintilla source code edit control +/** @file ExternalLexer.cxx + ** Support external lexers in DLLs. + **/ +// Copyright 2001 Simon Steele , portions copyright Neil Hodgson. +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" + +#include "SciLexer.h" +#include "PropSet.h" +#include "Accessor.h" +#include "DocumentAccessor.h" +#include "KeyWords.h" +#include "ExternalLexer.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +LexerManager *LexerManager::theInstance = NULL; + +//------------------------------------------ +// +// ExternalLexerModule +// +//------------------------------------------ + +char **WordListsToStrings(WordList *val[]) { + int dim = 0; + while (val[dim]) + dim++; + char **wls = new char * [dim + 1]; + for (int i = 0;i < dim;i++) { + SString words; + words = ""; + for (int n = 0; n < val[i]->len; n++) { + words += val[i]->words[n]; + if (n != val[i]->len - 1) + words += " "; + } + wls[i] = new char[words.length() + 1]; + strcpy(wls[i], words.c_str()); + } + wls[dim] = 0; + return wls; +} + +void DeleteWLStrings(char *strs[]) { + int dim = 0; + while (strs[dim]) { + delete strs[dim]; + dim++; + } + delete [] strs; +} + +void ExternalLexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const { + if (!fneLexer) + return ; + + char **kwds = WordListsToStrings(keywordlists); + char *ps = styler.GetProperties(); + + // The accessor passed in is always a DocumentAccessor so this cast and the subsequent + // access will work. Can not use the stricter dynamic_cast as that requires RTTI. + DocumentAccessor &da = static_cast(styler); + WindowID wID = da.GetWindow(); + + fneLexer(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps); + + delete ps; + DeleteWLStrings(kwds); +} + +void ExternalLexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const { + if (!fneFolder) + return ; + + char **kwds = WordListsToStrings(keywordlists); + char *ps = styler.GetProperties(); + + // The accessor passed in is always a DocumentAccessor so this cast and the subsequent + // access will work. Can not use the stricter dynamic_cast as that requires RTTI. + DocumentAccessor &da = static_cast(styler); + WindowID wID = da.GetWindow(); + + fneFolder(externalLanguage, startPos, lengthDoc, initStyle, kwds, wID, ps); + + delete ps; + DeleteWLStrings(kwds); +} + +void ExternalLexerModule::SetExternal(ExtLexerFunction fLexer, ExtFoldFunction fFolder, int index) { + fneLexer = fLexer; + fneFolder = fFolder; + externalLanguage = index; +} + +//------------------------------------------ +// +// LexerLibrary +// +//------------------------------------------ + +LexerLibrary::LexerLibrary(const char* ModuleName) { + // Initialise some members... + first = NULL; + last = NULL; + + // Load the DLL + lib = DynamicLibrary::Load(ModuleName); + if (lib->IsValid()) { + m_sModuleName = ModuleName; + //Cannot use reinterpret_cast because: ANSI C++ forbids casting between pointers to functions and objects + GetLexerCountFn GetLexerCount = (GetLexerCountFn)(sptr_t)lib->FindFunction("GetLexerCount"); + + if (GetLexerCount) { + ExternalLexerModule *lex; + LexerMinder *lm; + + // Find functions in the DLL + GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName"); + ExtLexerFunction Lexer = (ExtLexerFunction)(sptr_t)lib->FindFunction("Lex"); + ExtFoldFunction Folder = (ExtFoldFunction)(sptr_t)lib->FindFunction("Fold"); + + // Assign a buffer for the lexer name. + char lexname[100]; + strcpy(lexname, ""); + + int nl = GetLexerCount(); + + for (int i = 0; i < nl; i++) { + GetLexerName(i, lexname, 100); + lex = new ExternalLexerModule(SCLEX_AUTOMATIC, NULL, lexname, NULL); + + // Create a LexerMinder so we don't leak the ExternalLexerModule... + lm = new LexerMinder; + lm->self = lex; + lm->next = NULL; + if (first != NULL) { + last->next = lm; + last = lm; + } else { + first = lm; + last = lm; + } + + // The external lexer needs to know how to call into its DLL to + // do its lexing and folding, we tell it here. Folder may be null. + lex->SetExternal(Lexer, Folder, i); + } + } + } + next = NULL; +} + +LexerLibrary::~LexerLibrary() { + Release(); + delete lib; +} + +void LexerLibrary::Release() { + //TODO maintain a list of lexers created, and delete them! + LexerMinder *lm; + LexerMinder *lmNext; + lm = first; + while (NULL != lm) { + lmNext = lm->next; + delete lm->self; + delete lm; + lm = lmNext; + } + + first = NULL; + last = NULL; +} + +//------------------------------------------ +// +// LexerManager +// +//------------------------------------------ + +/// Return the single LexerManager instance... +LexerManager *LexerManager::GetInstance() { + if(!theInstance) + theInstance = new LexerManager; + return theInstance; +} + +/// Delete any LexerManager instance... +void LexerManager::DeleteInstance() +{ + if(theInstance) { + delete theInstance; + theInstance = NULL; + } +} + +/// protected constructor - this is a singleton... +LexerManager::LexerManager() { + first = NULL; + last = NULL; +} + +LexerManager::~LexerManager() { + Clear(); +} + +void LexerManager::Load(const char* path) +{ + LoadLexerLibrary(path); +} + +void LexerManager::LoadLexerLibrary(const char* module) +{ + LexerLibrary *lib = new LexerLibrary(module); + if (NULL != first) { + last->next = lib; + last = lib; + } else { + first = lib; + last = lib; + } +} + +void LexerManager::Clear() +{ + if (NULL != first) { + LexerLibrary *cur = first; + LexerLibrary *next; + while (cur) { + next = cur->next; + delete cur; + cur = next; + } + first = NULL; + last = NULL; + } +} + +//------------------------------------------ +// +// LexerManager +// +//------------------------------------------ + +LMMinder::~LMMinder() +{ + LexerManager::DeleteInstance(); +} + +LMMinder minder; diff --git a/harbour/contrib/hbide/qscintilla/ExternalLexer.h b/harbour/contrib/hbide/qscintilla/ExternalLexer.h new file mode 100644 index 0000000000..942a001ae5 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ExternalLexer.h @@ -0,0 +1,110 @@ +// Scintilla source code edit control +/** @file ExternalLexer.h + ** Support external lexers in DLLs. + **/ +// Copyright 2001 Simon Steele , portions copyright Neil Hodgson. +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EXTERNALLEXER_H +#define EXTERNALLEXER_H + +#if PLAT_WIN +#define EXT_LEXER_DECL __stdcall +#elif PLAT_QT +#include +#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) +#define EXT_LEXER_DECL __stdcall +#else +#define EXT_LEXER_DECL +#endif +#else +#define EXT_LEXER_DECL +#endif + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +// External Lexer function definitions... +typedef void (EXT_LEXER_DECL *ExtLexerFunction)(unsigned int lexer, unsigned int startPos, int length, int initStyle, + char *words[], WindowID window, char *props); +typedef void (EXT_LEXER_DECL *ExtFoldFunction)(unsigned int lexer, unsigned int startPos, int length, int initStyle, + char *words[], WindowID window, char *props); +typedef void* (EXT_LEXER_DECL *GetLexerFunction)(unsigned int Index); +typedef int (EXT_LEXER_DECL *GetLexerCountFn)(); +typedef void (EXT_LEXER_DECL *GetLexerNameFn)(unsigned int Index, char *name, int buflength); + +//class DynamicLibrary; + +/// Sub-class of LexerModule to use an external lexer. +class ExternalLexerModule : protected LexerModule { +protected: + ExtLexerFunction fneLexer; + ExtFoldFunction fneFolder; + int externalLanguage; + char name[100]; +public: + ExternalLexerModule(int language_, LexerFunction fnLexer_, + const char *languageName_=0, LexerFunction fnFolder_=0) : LexerModule(language_, fnLexer_, 0, fnFolder_){ + strncpy(name, languageName_, sizeof(name)); + languageName = name; + }; + virtual void Lex(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const; + virtual void Fold(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const; + virtual void SetExternal(ExtLexerFunction fLexer, ExtFoldFunction fFolder, int index); +}; + +/// LexerMinder points to an ExternalLexerModule - so we don't leak them. +class LexerMinder { +public: + ExternalLexerModule *self; + LexerMinder *next; +}; + +/// LexerLibrary exists for every External Lexer DLL, contains LexerMinders. +class LexerLibrary { + DynamicLibrary *lib; + LexerMinder *first; + LexerMinder *last; + +public: + LexerLibrary(const char* ModuleName); + ~LexerLibrary(); + void Release(); + + LexerLibrary *next; + SString m_sModuleName; +}; + +/// LexerManager manages external lexers, contains LexerLibrarys. +class LexerManager { +public: + ~LexerManager(); + + static LexerManager *GetInstance(); + static void DeleteInstance(); + + void Load(const char* path); + void Clear(); + +private: + LexerManager(); + static LexerManager *theInstance; + + void LoadLexerLibrary(const char* module); + LexerLibrary *first; + LexerLibrary *last; +}; + +class LMMinder { +public: + ~LMMinder(); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Indicator.cpp b/harbour/contrib/hbide/qscintilla/Indicator.cpp new file mode 100644 index 0000000000..da9531224a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Indicator.cpp @@ -0,0 +1,81 @@ +// Scintilla source code edit control +/** @file Indicator.cxx + ** Defines the style of indicators which are text decorations such as underlining. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include "Platform.h" + +#include "Scintilla.h" +#include "Indicator.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine) { + surface->PenColour(fore.allocated); + int ymid = (rc.bottom + rc.top) / 2; + if (style == INDIC_SQUIGGLE) { + surface->MoveTo(rc.left, rc.top); + int x = rc.left + 2; + int y = 2; + while (x < rc.right) { + surface->LineTo(x, rc.top + y); + x += 2; + y = 2 - y; + } + surface->LineTo(rc.right, rc.top + y); // Finish the line + } else if (style == INDIC_TT) { + surface->MoveTo(rc.left, ymid); + int x = rc.left + 5; + while (x < rc.right) { + surface->LineTo(x, ymid); + surface->MoveTo(x-3, ymid); + surface->LineTo(x-3, ymid+2); + x++; + surface->MoveTo(x, ymid); + x += 5; + } + surface->LineTo(rc.right, ymid); // Finish the line + if (x - 3 <= rc.right) { + surface->MoveTo(x-3, ymid); + surface->LineTo(x-3, ymid+2); + } + } else if (style == INDIC_DIAGONAL) { + int x = rc.left; + while (x < rc.right) { + surface->MoveTo(x, rc.top+2); + int endX = x+3; + int endY = rc.top - 1; + if (endX > rc.right) { + endY += endX - rc.right; + endX = rc.right; + } + surface->LineTo(endX, endY); + x += 4; + } + } else if (style == INDIC_STRIKE) { + surface->MoveTo(rc.left, rc.top - 4); + surface->LineTo(rc.right, rc.top - 4); + } else if (style == INDIC_HIDDEN) { + // Draw nothing + } else if (style == INDIC_BOX) { + surface->MoveTo(rc.left, ymid+1); + surface->LineTo(rc.right, ymid+1); + surface->LineTo(rc.right, rcLine.top+1); + surface->LineTo(rc.left, rcLine.top+1); + surface->LineTo(rc.left, ymid+1); + } else if (style == INDIC_ROUNDBOX) { + PRectangle rcBox = rcLine; + rcBox.top = rcLine.top + 1; + rcBox.left = rc.left; + rcBox.right = rc.right; + surface->AlphaRectangle(rcBox, 1, fore.allocated, fillAlpha, fore.allocated, 50, 0); + } else { // Either INDIC_PLAIN or unknown + surface->MoveTo(rc.left, ymid); + surface->LineTo(rc.right, ymid); + } +} + diff --git a/harbour/contrib/hbide/qscintilla/Indicator.h b/harbour/contrib/hbide/qscintilla/Indicator.h new file mode 100644 index 0000000000..42b56f07e7 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Indicator.h @@ -0,0 +1,32 @@ +// Scintilla source code edit control +/** @file Indicator.h + ** Defines the style of indicators which are text decorations such as underlining. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef INDICATOR_H +#define INDICATOR_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class Indicator { +public: + int style; + bool under; + ColourPair fore; + int fillAlpha; + Indicator() : style(INDIC_PLAIN), under(false), fore(ColourDesired(0,0,0)), fillAlpha(30) { + } + void Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/KeyMap.cpp b/harbour/contrib/hbide/qscintilla/KeyMap.cpp new file mode 100644 index 0000000000..c223d5b59a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/KeyMap.cpp @@ -0,0 +1,152 @@ +// Scintilla source code edit control +/** @file KeyMap.cxx + ** Defines a mapping between keystrokes and commands. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include "Platform.h" + +#include "Scintilla.h" + +#include "KeyMap.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +KeyMap::KeyMap() : kmap(0), len(0), alloc(0) { + for (int i = 0; MapDefault[i].key; i++) { + AssignCmdKey(MapDefault[i].key, + MapDefault[i].modifiers, + MapDefault[i].msg); + } +} + +KeyMap::~KeyMap() { + Clear(); +} + +void KeyMap::Clear() { + delete []kmap; + kmap = 0; + len = 0; + alloc = 0; +} + +void KeyMap::AssignCmdKey(int key, int modifiers, unsigned int msg) { + if ((len+1) >= alloc) { + KeyToCommand *ktcNew = new KeyToCommand[alloc + 5]; + if (!ktcNew) + return; + for (int k = 0; k < len; k++) + ktcNew[k] = kmap[k]; + alloc += 5; + delete []kmap; + kmap = ktcNew; + } + for (int keyIndex = 0; keyIndex < len; keyIndex++) { + if ((key == kmap[keyIndex].key) && (modifiers == kmap[keyIndex].modifiers)) { + kmap[keyIndex].msg = msg; + return; + } + } + kmap[len].key = key; + kmap[len].modifiers = modifiers; + kmap[len].msg = msg; + len++; +} + +unsigned int KeyMap::Find(int key, int modifiers) { + for (int i = 0; i < len; i++) { + if ((key == kmap[i].key) && (modifiers == kmap[i].modifiers)) { + return kmap[i].msg; + } + } + return 0; +} + +const KeyToCommand KeyMap::MapDefault[] = { + {SCK_DOWN, SCI_NORM, SCI_LINEDOWN}, + {SCK_DOWN, SCI_SHIFT, SCI_LINEDOWNEXTEND}, + {SCK_DOWN, SCI_CTRL, SCI_LINESCROLLDOWN}, + {SCK_DOWN, SCI_ASHIFT, SCI_LINEDOWNRECTEXTEND}, + {SCK_UP, SCI_NORM, SCI_LINEUP}, + {SCK_UP, SCI_SHIFT, SCI_LINEUPEXTEND}, + {SCK_UP, SCI_CTRL, SCI_LINESCROLLUP}, + {SCK_UP, SCI_ASHIFT, SCI_LINEUPRECTEXTEND}, + {'[', SCI_CTRL, SCI_PARAUP}, + {'[', SCI_CSHIFT, SCI_PARAUPEXTEND}, + {']', SCI_CTRL, SCI_PARADOWN}, + {']', SCI_CSHIFT, SCI_PARADOWNEXTEND}, + {SCK_LEFT, SCI_NORM, SCI_CHARLEFT}, + {SCK_LEFT, SCI_SHIFT, SCI_CHARLEFTEXTEND}, + {SCK_LEFT, SCI_CTRL, SCI_WORDLEFT}, + {SCK_LEFT, SCI_CSHIFT, SCI_WORDLEFTEXTEND}, + {SCK_LEFT, SCI_ASHIFT, SCI_CHARLEFTRECTEXTEND}, + {SCK_RIGHT, SCI_NORM, SCI_CHARRIGHT}, + {SCK_RIGHT, SCI_SHIFT, SCI_CHARRIGHTEXTEND}, + {SCK_RIGHT, SCI_CTRL, SCI_WORDRIGHT}, + {SCK_RIGHT, SCI_CSHIFT, SCI_WORDRIGHTEXTEND}, + {SCK_RIGHT, SCI_ASHIFT, SCI_CHARRIGHTRECTEXTEND}, + {'/', SCI_CTRL, SCI_WORDPARTLEFT}, + {'/', SCI_CSHIFT, SCI_WORDPARTLEFTEXTEND}, + {'\\', SCI_CTRL, SCI_WORDPARTRIGHT}, + {'\\', SCI_CSHIFT, SCI_WORDPARTRIGHTEXTEND}, + {SCK_HOME, SCI_NORM, SCI_VCHOME}, + {SCK_HOME, SCI_SHIFT, SCI_VCHOMEEXTEND}, + {SCK_HOME, SCI_CTRL, SCI_DOCUMENTSTART}, + {SCK_HOME, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND}, + {SCK_HOME, SCI_ALT, SCI_HOMEDISPLAY}, +// {SCK_HOME, SCI_ASHIFT, SCI_HOMEDISPLAYEXTEND}, + {SCK_HOME, SCI_ASHIFT, SCI_VCHOMERECTEXTEND}, + {SCK_END, SCI_NORM, SCI_LINEEND}, + {SCK_END, SCI_SHIFT, SCI_LINEENDEXTEND}, + {SCK_END, SCI_CTRL, SCI_DOCUMENTEND}, + {SCK_END, SCI_CSHIFT, SCI_DOCUMENTENDEXTEND}, + {SCK_END, SCI_ALT, SCI_LINEENDDISPLAY}, +// {SCK_END, SCI_ASHIFT, SCI_LINEENDDISPLAYEXTEND}, + {SCK_END, SCI_ASHIFT, SCI_LINEENDRECTEXTEND}, + {SCK_PRIOR, SCI_NORM, SCI_PAGEUP}, + {SCK_PRIOR, SCI_SHIFT, SCI_PAGEUPEXTEND}, + {SCK_PRIOR, SCI_ASHIFT, SCI_PAGEUPRECTEXTEND}, + {SCK_NEXT, SCI_NORM, SCI_PAGEDOWN}, + {SCK_NEXT, SCI_SHIFT, SCI_PAGEDOWNEXTEND}, + {SCK_NEXT, SCI_ASHIFT, SCI_PAGEDOWNRECTEXTEND}, + {SCK_DELETE, SCI_NORM, SCI_CLEAR}, + {SCK_DELETE, SCI_SHIFT, SCI_CUT}, + {SCK_DELETE, SCI_CTRL, SCI_DELWORDRIGHT}, + {SCK_DELETE, SCI_CSHIFT, SCI_DELLINERIGHT}, + {SCK_INSERT, SCI_NORM, SCI_EDITTOGGLEOVERTYPE}, + {SCK_INSERT, SCI_SHIFT, SCI_PASTE}, + {SCK_INSERT, SCI_CTRL, SCI_COPY}, + {SCK_ESCAPE, SCI_NORM, SCI_CANCEL}, + {SCK_BACK, SCI_NORM, SCI_DELETEBACK}, + {SCK_BACK, SCI_SHIFT, SCI_DELETEBACK}, + {SCK_BACK, SCI_CTRL, SCI_DELWORDLEFT}, + {SCK_BACK, SCI_ALT, SCI_UNDO}, + {SCK_BACK, SCI_CSHIFT, SCI_DELLINELEFT}, + {'Z', SCI_CTRL, SCI_UNDO}, + {'Y', SCI_CTRL, SCI_REDO}, + {'X', SCI_CTRL, SCI_CUT}, + {'C', SCI_CTRL, SCI_COPY}, + {'V', SCI_CTRL, SCI_PASTE}, + {'A', SCI_CTRL, SCI_SELECTALL}, + {SCK_TAB, SCI_NORM, SCI_TAB}, + {SCK_TAB, SCI_SHIFT, SCI_BACKTAB}, + {SCK_RETURN, SCI_NORM, SCI_NEWLINE}, + {SCK_RETURN, SCI_SHIFT, SCI_NEWLINE}, + {SCK_ADD, SCI_CTRL, SCI_ZOOMIN}, + {SCK_SUBTRACT, SCI_CTRL, SCI_ZOOMOUT}, + {SCK_DIVIDE, SCI_CTRL, SCI_SETZOOM}, + //'L', SCI_CTRL, SCI_FORMFEED, + {'L', SCI_CTRL, SCI_LINECUT}, + {'L', SCI_CSHIFT, SCI_LINEDELETE}, + {'T', SCI_CSHIFT, SCI_LINECOPY}, + {'T', SCI_CTRL, SCI_LINETRANSPOSE}, + {'D', SCI_CTRL, SCI_SELECTIONDUPLICATE}, + {'U', SCI_CTRL, SCI_LOWERCASE}, + {'U', SCI_CSHIFT, SCI_UPPERCASE}, + {0,0,0}, +}; + diff --git a/harbour/contrib/hbide/qscintilla/KeyMap.h b/harbour/contrib/hbide/qscintilla/KeyMap.h new file mode 100644 index 0000000000..fd9005de84 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/KeyMap.h @@ -0,0 +1,51 @@ +// Scintilla source code edit control +/** @file KeyMap.h + ** Defines a mapping between keystrokes and commands. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef KEYTOCOMMAND_H +#define KEYTOCOMMAND_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +#define SCI_NORM 0 +#define SCI_SHIFT SCMOD_SHIFT +#define SCI_CTRL SCMOD_CTRL +#define SCI_ALT SCMOD_ALT +#define SCI_CSHIFT (SCI_CTRL | SCI_SHIFT) +#define SCI_ASHIFT (SCI_ALT | SCI_SHIFT) + +/** + */ +class KeyToCommand { +public: + int key; + int modifiers; + unsigned int msg; +}; + +/** + */ +class KeyMap { + KeyToCommand *kmap; + int len; + int alloc; + static const KeyToCommand MapDefault[]; + +public: + KeyMap(); + ~KeyMap(); + void Clear(); + void AssignCmdKey(int key, int modifiers, unsigned int msg); + unsigned int Find(int key, int modifiers); // 0 returned on failure +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/KeyWords.cpp b/harbour/contrib/hbide/qscintilla/KeyWords.cpp new file mode 100644 index 0000000000..9209424258 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/KeyWords.cpp @@ -0,0 +1,248 @@ +// Scintilla source code edit control +/** @file KeyWords.cxx + ** Colourise for particular languages. + **/ +// Copyright 1998-2002 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +const LexerModule *LexerModule::base = 0; +int LexerModule::nextLanguage = SCLEX_AUTOMATIC+1; + +LexerModule::LexerModule(int language_, + LexerFunction fnLexer_, + const char *languageName_, + LexerFunction fnFolder_, + const char * const wordListDescriptions_[], + int styleBits_) : + language(language_), + fnLexer(fnLexer_), + fnFolder(fnFolder_), + wordListDescriptions(wordListDescriptions_), + styleBits(styleBits_), + languageName(languageName_) { + next = base; + base = this; + if (language == SCLEX_AUTOMATIC) { + language = nextLanguage; + nextLanguage++; + } +} + +int LexerModule::GetNumWordLists() const { + if (wordListDescriptions == NULL) { + return -1; + } else { + int numWordLists = 0; + + while (wordListDescriptions[numWordLists]) { + ++numWordLists; + } + + return numWordLists; + } +} + +const char *LexerModule::GetWordListDescription(int index) const { + static const char *emptyStr = ""; + + PLATFORM_ASSERT(index < GetNumWordLists()); + if (index >= GetNumWordLists()) { + return emptyStr; + } else { + return wordListDescriptions[index]; + } +} + +int LexerModule::GetStyleBitsNeeded() const { + return styleBits; +} + +const LexerModule *LexerModule::Find(int language) { + const LexerModule *lm = base; + while (lm) { + if (lm->language == language) { + return lm; + } + lm = lm->next; + } + return 0; +} + +const LexerModule *LexerModule::Find(const char *languageName) { + if (languageName) { + const LexerModule *lm = base; + while (lm) { + if (lm->languageName && 0 == strcmp(lm->languageName, languageName)) { + return lm; + } + lm = lm->next; + } + } + return 0; +} + +void LexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const { + if (fnLexer) + fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler); +} + +void LexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const { + if (fnFolder) { + int lineCurrent = styler.GetLine(startPos); + // Move back one line in case deletion wrecked current line fold state + if (lineCurrent > 0) { + lineCurrent--; + int newStartPos = styler.LineStart(lineCurrent); + lengthDoc += startPos - newStartPos; + startPos = newStartPos; + initStyle = 0; + if (startPos > 0) { + initStyle = styler.StyleAt(startPos - 1); + } + } + fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler); + } +} + +// Alternative historical name for Scintilla_LinkLexers +int wxForceScintillaLexers(void) { + return Scintilla_LinkLexers(); +} + +// To add or remove a lexer, add or remove its file and run LexGen.py. + +// Force a reference to all of the Scintilla lexers so that the linker will +// not remove the code of the lexers. +int Scintilla_LinkLexers() { + static int forcer = 0; + +// Shorten the code that declares a lexer and ensures it is linked in by calling a method. +#define LINK_LEXER(lexer) extern LexerModule lexer; forcer += lexer.GetLanguage(); + + LINK_LEXER(lmCPP); + LINK_LEXER(lmFlagShip); + +#if 0 +//++Autogenerated -- run src/LexGen.py to regenerate +//**\(\tLINK_LEXER(\*);\n\) + LINK_LEXER(lmAbaqus); + LINK_LEXER(lmAda); + LINK_LEXER(lmAns1); + LINK_LEXER(lmAPDL); + LINK_LEXER(lmAsm); + LINK_LEXER(lmASP); + LINK_LEXER(lmASY); + LINK_LEXER(lmAU3); + LINK_LEXER(lmAVE); + LINK_LEXER(lmBaan); + LINK_LEXER(lmBash); + LINK_LEXER(lmBatch); + LINK_LEXER(lmBlitzBasic); + LINK_LEXER(lmBullant); + LINK_LEXER(lmCaml); + LINK_LEXER(lmClw); + LINK_LEXER(lmClwNoCase); + LINK_LEXER(lmCmake); + LINK_LEXER(lmCOBOL); + LINK_LEXER(lmConf); + LINK_LEXER(lmCPP); + LINK_LEXER(lmCPPNoCase); + LINK_LEXER(lmCsound); + LINK_LEXER(lmCss); + LINK_LEXER(lmD); + LINK_LEXER(lmDiff); + LINK_LEXER(lmEiffel); + LINK_LEXER(lmEiffelkw); + LINK_LEXER(lmErlang); + LINK_LEXER(lmErrorList); + LINK_LEXER(lmESCRIPT); + LINK_LEXER(lmF77); + LINK_LEXER(lmFlagShip); + LINK_LEXER(lmForth); + LINK_LEXER(lmFortran); + LINK_LEXER(lmFreeBasic); + LINK_LEXER(lmGAP); + LINK_LEXER(lmGui4Cli); + LINK_LEXER(lmHaskell); + LINK_LEXER(lmHTML); + LINK_LEXER(lmInno); + LINK_LEXER(lmKix); + LINK_LEXER(lmLatex); + LINK_LEXER(lmLISP); + LINK_LEXER(lmLot); + LINK_LEXER(lmLout); + LINK_LEXER(lmLua); + LINK_LEXER(lmMagikSF); + LINK_LEXER(lmMake); + LINK_LEXER(lmMatlab); + LINK_LEXER(lmMETAPOST); + LINK_LEXER(lmMMIXAL); + LINK_LEXER(lmMSSQL); + LINK_LEXER(lmMySQL); + LINK_LEXER(lmNimrod); + LINK_LEXER(lmNncrontab); + LINK_LEXER(lmNsis); + LINK_LEXER(lmNull); + LINK_LEXER(lmOctave); + LINK_LEXER(lmOpal); + LINK_LEXER(lmPascal); + LINK_LEXER(lmPB); + LINK_LEXER(lmPerl); + LINK_LEXER(lmPHP); + LINK_LEXER(lmPHPSCRIPT); + LINK_LEXER(lmPLM); + LINK_LEXER(lmPo); + LINK_LEXER(lmPOV); + LINK_LEXER(lmPowerPro); + LINK_LEXER(lmPowerShell); + LINK_LEXER(lmProgress); + LINK_LEXER(lmProps); + LINK_LEXER(lmPS); + LINK_LEXER(lmPureBasic); + LINK_LEXER(lmPython); + LINK_LEXER(lmR); + LINK_LEXER(lmREBOL); + LINK_LEXER(lmRuby); + LINK_LEXER(lmScriptol); + LINK_LEXER(lmSmalltalk); + LINK_LEXER(lmSML); + LINK_LEXER(lmSorc); + LINK_LEXER(lmSpecman); + LINK_LEXER(lmSpice); + LINK_LEXER(lmSQL); + LINK_LEXER(lmTACL); + LINK_LEXER(lmTADS3); + LINK_LEXER(lmTAL); + LINK_LEXER(lmTCL); + LINK_LEXER(lmTeX); + LINK_LEXER(lmVB); + LINK_LEXER(lmVBScript); + LINK_LEXER(lmVerilog); + LINK_LEXER(lmVHDL); + LINK_LEXER(lmXML); + LINK_LEXER(lmYAML); + +//--Autogenerated -- end of automatically generated section +#endif + return 1; +} diff --git a/harbour/contrib/hbide/qscintilla/KeyWords.h b/harbour/contrib/hbide/qscintilla/KeyWords.h new file mode 100644 index 0000000000..6abae59453 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/KeyWords.h @@ -0,0 +1,90 @@ +// Scintilla source code edit control +/** @file KeyWords.h + ** Colourise for particular languages. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +typedef void (*LexerFunction)(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler); + +/** + * A LexerModule is responsible for lexing and folding a particular language. + * The class maintains a list of LexerModules which can be searched to find a + * module appropriate to a particular language. + */ +class LexerModule { +protected: + const LexerModule *next; + int language; + LexerFunction fnLexer; + LexerFunction fnFolder; + const char * const * wordListDescriptions; + int styleBits; + + static const LexerModule *base; + static int nextLanguage; + +public: + const char *languageName; + LexerModule(int language_, + LexerFunction fnLexer_, + const char *languageName_=0, + LexerFunction fnFolder_=0, + const char * const wordListDescriptions_[] = NULL, + int styleBits_=5); + virtual ~LexerModule() { + } + int GetLanguage() const { return language; } + + // -1 is returned if no WordList information is available + int GetNumWordLists() const; + const char *GetWordListDescription(int index) const; + + int GetStyleBitsNeeded() const; + + virtual void Lex(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const; + virtual void Fold(unsigned int startPos, int lengthDoc, int initStyle, + WordList *keywordlists[], Accessor &styler) const; + static const LexerModule *Find(int language); + static const LexerModule *Find(const char *languageName); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +/** + * Check if a character is a space. + * This is ASCII specific but is safe with chars >= 0x80. + */ +inline bool isspacechar(unsigned char ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +inline bool iswordchar(char ch) { + return isascii(ch) && (isalnum(ch) || ch == '.' || ch == '_'); +} + +inline bool iswordstart(char ch) { + return isascii(ch) && (isalnum(ch) || ch == '_'); +} + +inline bool isoperator(char ch) { + if (isascii(ch) && isalnum(ch)) + return false; + // '.' left out as it is used to make up numbers + if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || + ch == '(' || ch == ')' || ch == '-' || ch == '+' || + ch == '=' || ch == '|' || ch == '{' || ch == '}' || + ch == '[' || ch == ']' || ch == ':' || ch == ';' || + ch == '<' || ch == '>' || ch == ',' || ch == '/' || + ch == '?' || ch == '!' || ch == '.' || ch == '~') + return true; + return false; +} diff --git a/harbour/contrib/hbide/qscintilla/LexCPP.cpp b/harbour/contrib/hbide/qscintilla/LexCPP.cpp new file mode 100644 index 0000000000..9a8d49bb63 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/LexCPP.cpp @@ -0,0 +1,502 @@ +// Scintilla source code edit control +/** @file LexCPP.cxx + ** Lexer for C++, C, Java, and JavaScript. + **/ +// Copyright 1998-2005 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" +#include "CharacterSet.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static bool IsSpaceEquiv(int state) { + return (state <= SCE_C_COMMENTDOC) || + // including SCE_C_DEFAULT, SCE_C_COMMENT, SCE_C_COMMENTLINE + (state == SCE_C_COMMENTLINEDOC) || (state == SCE_C_COMMENTDOCKEYWORD) || + (state == SCE_C_COMMENTDOCKEYWORDERROR); +} + +// Preconditions: sc.currentPos points to a character after '+' or '-'. +// The test for pos reaching 0 should be redundant, +// and is in only for safety measures. +// Limitation: this code will give the incorrect answer for code like +// a = b+++/ptn/... +// Putting a space between the '++' post-inc operator and the '+' binary op +// fixes this, and is highly recommended for readability anyway. +static bool FollowsPostfixOperator(StyleContext &sc, Accessor &styler) { + int pos = (int) sc.currentPos; + while (--pos > 0) { + char ch = styler[pos]; + if (ch == '+' || ch == '-') { + return styler[pos - 1] == ch; + } + } + return false; +} + +static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], + Accessor &styler, bool caseSensitive) { + + WordList &keywords = *keywordlists[0]; + WordList &keywords2 = *keywordlists[1]; + WordList &keywords3 = *keywordlists[2]; + WordList &keywords4 = *keywordlists[3]; + + // property styling.within.preprocessor + // For C++ code, determines whether all preprocessor code is styled in the preprocessor style (0, the default) + // or only from the initial # to the end of the command word(1). + bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0; + + CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-"); + CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-"); + + CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); + + CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true); + CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true); + + // property lexer.cpp.allow.dollars + // Set to 0 to disallow the '$' character in identifiers with the cpp lexer. + if (styler.GetPropertyInt("lexer.cpp.allow.dollars", 1) != 0) { + setWordStart.Add('$'); + setWord.Add('$'); + } + + int chPrevNonWhite = ' '; + int visibleChars = 0; + bool lastWordWasUUID = false; + int styleBeforeDCKeyword = SCE_C_DEFAULT; + bool continuationLine = false; + bool isIncludePreprocessor = false; + + if (initStyle == SCE_C_PREPROCESSOR) { + // Set continuationLine if last character of previous line is '\' + int lineCurrent = styler.GetLine(startPos); + if (lineCurrent > 0) { + int chBack = styler.SafeGetCharAt(startPos-1, 0); + int chBack2 = styler.SafeGetCharAt(startPos-2, 0); + int lineEndChar = '!'; + if (chBack2 == '\r' && chBack == '\n') { + lineEndChar = styler.SafeGetCharAt(startPos-3, 0); + } else if (chBack == '\n' || chBack == '\r') { + lineEndChar = chBack2; + } + continuationLine = lineEndChar == '\\'; + } + } + + // look back to set chPrevNonWhite properly for better regex colouring + if (startPos > 0) { + int back = startPos; + while (--back && IsSpaceEquiv(styler.StyleAt(back))) + ; + if (styler.StyleAt(back) == SCE_C_OPERATOR) { + chPrevNonWhite = styler.SafeGetCharAt(back); + } + } + + StyleContext sc(startPos, length, initStyle, styler); + + for (; sc.More(); sc.Forward()) { + + if (sc.atLineStart) { + if (sc.state == SCE_C_STRING) { + // Prevent SCE_C_STRINGEOL from leaking back to previous line which + // ends with a line continuation by locking in the state upto this position. + sc.SetState(SCE_C_STRING); + } + // Reset states to begining of colourise so no surprises + // if different sets of lines lexed. + visibleChars = 0; + lastWordWasUUID = false; + isIncludePreprocessor = false; + } + + // Handle line continuation generically. + if (sc.ch == '\\') { + if (sc.chNext == '\n' || sc.chNext == '\r') { + sc.Forward(); + if (sc.ch == '\r' && sc.chNext == '\n') { + sc.Forward(); + } + continuationLine = true; + continue; + } + } + + // Determine if the current state should terminate. + switch (sc.state) { + case SCE_C_OPERATOR: + sc.SetState(SCE_C_DEFAULT); + break; + case SCE_C_NUMBER: + // We accept almost anything because of hex. and number suffixes + if (!setWord.Contains(sc.ch)) { + sc.SetState(SCE_C_DEFAULT); + } + break; + case SCE_C_IDENTIFIER: + if (!setWord.Contains(sc.ch) || (sc.ch == '.')) { + char s[1000]; + if (caseSensitive) { + sc.GetCurrent(s, sizeof(s)); + } else { + sc.GetCurrentLowered(s, sizeof(s)); + } + if (keywords.InList(s)) { + lastWordWasUUID = strcmp(s, "uuid") == 0; + sc.ChangeState(SCE_C_WORD); + } else if (keywords2.InList(s)) { + sc.ChangeState(SCE_C_WORD2); + } else if (keywords4.InList(s)) { + sc.ChangeState(SCE_C_GLOBALCLASS); + } + sc.SetState(SCE_C_DEFAULT); + } + break; + case SCE_C_PREPROCESSOR: + if (sc.atLineStart && !continuationLine) { + sc.SetState(SCE_C_DEFAULT); + } else if (stylingWithinPreprocessor) { + if (IsASpace(sc.ch)) { + sc.SetState(SCE_C_DEFAULT); + } + } else { + if (sc.Match('/', '*') || sc.Match('/', '/')) { + sc.SetState(SCE_C_DEFAULT); + } + } + break; + case SCE_C_COMMENT: + if (sc.Match('*', '/')) { + sc.Forward(); + sc.ForwardSetState(SCE_C_DEFAULT); + } + break; + case SCE_C_COMMENTDOC: + if (sc.Match('*', '/')) { + sc.Forward(); + sc.ForwardSetState(SCE_C_DEFAULT); + } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support + // Verify that we have the conditions to mark a comment-doc-keyword + if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { + styleBeforeDCKeyword = SCE_C_COMMENTDOC; + sc.SetState(SCE_C_COMMENTDOCKEYWORD); + } + } + break; + case SCE_C_COMMENTLINE: + if (sc.atLineStart) { + sc.SetState(SCE_C_DEFAULT); + } + break; + case SCE_C_COMMENTLINEDOC: + if (sc.atLineStart) { + sc.SetState(SCE_C_DEFAULT); + } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support + // Verify that we have the conditions to mark a comment-doc-keyword + if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { + styleBeforeDCKeyword = SCE_C_COMMENTLINEDOC; + sc.SetState(SCE_C_COMMENTDOCKEYWORD); + } + } + break; + case SCE_C_COMMENTDOCKEYWORD: + if ((styleBeforeDCKeyword == SCE_C_COMMENTDOC) && sc.Match('*', '/')) { + sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR); + sc.Forward(); + sc.ForwardSetState(SCE_C_DEFAULT); + } else if (!setDoxygen.Contains(sc.ch)) { + char s[100]; + if (caseSensitive) { + sc.GetCurrent(s, sizeof(s)); + } else { + sc.GetCurrentLowered(s, sizeof(s)); + } + if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) { + sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR); + } + sc.SetState(styleBeforeDCKeyword); + } + break; + case SCE_C_STRING: + if (sc.atLineEnd) { + sc.ChangeState(SCE_C_STRINGEOL); + } else if (isIncludePreprocessor) { + if (sc.ch == '>') { + sc.ForwardSetState(SCE_C_DEFAULT); + isIncludePreprocessor = false; + } + } else if (sc.ch == '\\') { + if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { + sc.Forward(); + } + } else if (sc.ch == '\"') { + sc.ForwardSetState(SCE_C_DEFAULT); + } + break; + case SCE_C_CHARACTER: + if (sc.atLineEnd) { + sc.ChangeState(SCE_C_STRINGEOL); + } else if (sc.ch == '\\') { + if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { + sc.Forward(); + } + } else if (sc.ch == '\'') { + sc.ForwardSetState(SCE_C_DEFAULT); + } + break; + case SCE_C_REGEX: + if (sc.atLineStart) { + sc.SetState(SCE_C_DEFAULT); + } else if (sc.ch == '/') { + sc.Forward(); + while ((sc.ch < 0x80) && islower(sc.ch)) + sc.Forward(); // gobble regex flags + sc.SetState(SCE_C_DEFAULT); + } else if (sc.ch == '\\') { + // Gobble up the quoted character + if (sc.chNext == '\\' || sc.chNext == '/') { + sc.Forward(); + } + } + break; + case SCE_C_STRINGEOL: + if (sc.atLineStart) { + sc.SetState(SCE_C_DEFAULT); + } + break; + case SCE_C_VERBATIM: + if (sc.ch == '\"') { + if (sc.chNext == '\"') { + sc.Forward(); + } else { + sc.ForwardSetState(SCE_C_DEFAULT); + } + } + break; + case SCE_C_UUID: + if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') { + sc.SetState(SCE_C_DEFAULT); + } + } + + // Determine if a new state should be entered. + if (sc.state == SCE_C_DEFAULT) { + if (sc.Match('@', '\"')) { + sc.SetState(SCE_C_VERBATIM); + sc.Forward(); + } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + if (lastWordWasUUID) { + sc.SetState(SCE_C_UUID); + lastWordWasUUID = false; + } else { + sc.SetState(SCE_C_NUMBER); + } + } else if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) { + if (lastWordWasUUID) { + sc.SetState(SCE_C_UUID); + lastWordWasUUID = false; + } else { + sc.SetState(SCE_C_IDENTIFIER); + } + } else if (sc.Match('/', '*')) { + if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style + sc.SetState(SCE_C_COMMENTDOC); + } else { + sc.SetState(SCE_C_COMMENT); + } + sc.Forward(); // Eat the * so it isn't used for the end of the comment + } else if (sc.Match('/', '/')) { + if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!")) + // Support of Qt/Doxygen doc. style + sc.SetState(SCE_C_COMMENTLINEDOC); + else + sc.SetState(SCE_C_COMMENTLINE); + } else if (sc.ch == '/' && setOKBeforeRE.Contains(chPrevNonWhite) && + (!setCouldBePostOp.Contains(chPrevNonWhite) || !FollowsPostfixOperator(sc, styler))) { + sc.SetState(SCE_C_REGEX); // JavaScript's RegEx + } else if (sc.ch == '\"') { + sc.SetState(SCE_C_STRING); + isIncludePreprocessor = false; // ensure that '>' won't end the string + } else if (isIncludePreprocessor && sc.ch == '<') { + sc.SetState(SCE_C_STRING); + } else if (sc.ch == '\'') { + sc.SetState(SCE_C_CHARACTER); + } else if (sc.ch == '#' && visibleChars == 0) { + // Preprocessor commands are alone on their line + sc.SetState(SCE_C_PREPROCESSOR); + // Skip whitespace between # and preprocessor word + do { + sc.Forward(); + } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); + if (sc.atLineEnd) { + sc.SetState(SCE_C_DEFAULT); + } else if (sc.Match("include")) { + isIncludePreprocessor = true; + } + } else if (isoperator(static_cast(sc.ch))) { + sc.SetState(SCE_C_OPERATOR); + } + } + + if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) { + chPrevNonWhite = sc.ch; + visibleChars++; + } + continuationLine = false; + } + sc.Complete(); +} + +static bool IsStreamCommentStyle(int style) { + return style == SCE_C_COMMENT || + style == SCE_C_COMMENTDOC || + style == SCE_C_COMMENTDOCKEYWORD || + style == SCE_C_COMMENTDOCKEYWORDERROR; +} + +// Store both the current line's fold level and the next lines in the +// level store to make it easy to pick up with each increment +// and to make it possible to fiddle the current level for "} else {". +static void FoldCppDoc(unsigned int startPos, int length, int initStyle, + WordList *[], Accessor &styler) { + + // property fold.comment + // This option enables folding multi-line comments and explicit fold points when using the C++ lexer. + // Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //} + // at the end of a section that should fold. + bool foldComment = styler.GetPropertyInt("fold.comment") != 0; + + // property fold.preprocessor + // This option enables folding preprocessor directives when using the C++ lexer. + // Includes C#'s explicit #region and #endregion folding directives. + bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; + + bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + + // property fold.at.else + // This option enables C++ folding on a "} else {" line of an if statement. + bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; + + unsigned int endPos = startPos + length; + int visibleChars = 0; + int lineCurrent = styler.GetLine(startPos); + int levelCurrent = SC_FOLDLEVELBASE; + if (lineCurrent > 0) + levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; + int levelMinCurrent = levelCurrent; + int levelNext = levelCurrent; + char chNext = styler[startPos]; + int styleNext = styler.StyleAt(startPos); + int style = initStyle; + for (unsigned int i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + int stylePrev = style; + style = styleNext; + styleNext = styler.StyleAt(i + 1); + bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + if (foldComment && IsStreamCommentStyle(style)) { + if (!IsStreamCommentStyle(stylePrev) && (stylePrev != SCE_C_COMMENTLINEDOC)) { + levelNext++; + } else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_C_COMMENTLINEDOC) && !atEOL) { + // Comments don't end at end of line and the next character may be unstyled. + levelNext--; + } + } + if (foldComment && (style == SCE_C_COMMENTLINE)) { + if ((ch == '/') && (chNext == '/')) { + char chNext2 = styler.SafeGetCharAt(i + 2); + if (chNext2 == '{') { + levelNext++; + } else if (chNext2 == '}') { + levelNext--; + } + } + } + if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { + if (ch == '#') { + unsigned int j = i + 1; + while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { + j++; + } + if (styler.Match(j, "region") || styler.Match(j, "if")) { + levelNext++; + } else if (styler.Match(j, "end")) { + levelNext--; + } + } + } + if (style == SCE_C_OPERATOR) { + if (ch == '{') { + // Measure the minimum before a '{' to allow + // folding on "} else {" + if (levelMinCurrent > levelNext) { + levelMinCurrent = levelNext; + } + levelNext++; + } else if (ch == '}') { + levelNext--; + } + } + if (!IsASpace(ch)) + visibleChars++; + if (atEOL || (i == endPos-1)) { + int levelUse = levelCurrent; + if (foldAtElse) { + levelUse = levelMinCurrent; + } + int lev = levelUse | levelNext << 16; + if (visibleChars == 0 && foldCompact) + lev |= SC_FOLDLEVELWHITEFLAG; + if (levelUse < levelNext) + lev |= SC_FOLDLEVELHEADERFLAG; + if (lev != styler.LevelAt(lineCurrent)) { + styler.SetLevel(lineCurrent, lev); + } + lineCurrent++; + levelCurrent = levelNext; + levelMinCurrent = levelCurrent; + visibleChars = 0; + } + } +} + +static const char * const cppWordLists[] = { + "Primary keywords and identifiers", + "Secondary keywords and identifiers", + "Documentation comment keywords", + "Unused", + "Global classes and typedefs", + 0, + }; + +static void ColouriseCppDocSensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, true); +} + +static void ColouriseCppDocInsensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], + Accessor &styler) { + ColouriseCppDoc(startPos, length, initStyle, keywordlists, styler, false); +} + +LexerModule lmCPP(SCLEX_CPP, ColouriseCppDocSensitive, "cpp", FoldCppDoc, cppWordLists); +LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, ColouriseCppDocInsensitive, "cppnocase", FoldCppDoc, cppWordLists); diff --git a/harbour/contrib/hbide/qscintilla/LexFlagship.cpp b/harbour/contrib/hbide/qscintilla/LexFlagship.cpp new file mode 100644 index 0000000000..f0c794e766 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/LexFlagship.cpp @@ -0,0 +1,348 @@ +// Scintilla source code edit control +/** @file LexFlagShip.cxx + ** Lexer for Harbour and FlagShip. + ** (Syntactically compatible to other xBase dialects, like Clipper, dBase, Clip, FoxPro etc.) + **/ +// Copyright 2005 by Randy Butler +// Copyright 2010 by Xavi (Harbour) +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" +#include "CharacterSet.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +// Extended to accept accented characters +static inline bool IsAWordChar(int ch) +{ + return ch >= 0x80 || + (isalnum(ch) || ch == '_'); +} + +static void ColouriseFlagShipDoc(unsigned int startPos, int length, int initStyle, + WordList *keywordlists[], Accessor &styler) +{ + + WordList &keywords = *keywordlists[0]; + WordList &keywords2 = *keywordlists[1]; + WordList &keywords3 = *keywordlists[2]; + WordList &keywords4 = *keywordlists[3]; + WordList &keywords5 = *keywordlists[4]; + + // property lexer.flagship.styling.within.preprocessor + // For Harbour code, determines whether all preprocessor code is styled in the preprocessor style (0) or only from the + // initial # to the end of the command word(1, the default). It also determines how to present text, dump, and disabled code. + bool stylingWithinPreprocessor = styler.GetPropertyInt("lexer.flagship.styling.within.preprocessor", 1) != 0; + + CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); + + int visibleChars = 0; + int closeStringChar = 0; + int styleBeforeDCKeyword = SCE_FS_DEFAULT; + bool bEnableCode = initStyle < SCE_FS_DISABLEDCODE; + + StyleContext sc(startPos, length, initStyle, styler); + + for (; sc.More(); sc.Forward()) { + + // Determine if the current state should terminate. + switch (sc.state) { + case SCE_FS_OPERATOR: + case SCE_FS_OPERATOR_C: + case SCE_FS_WORDOPERATOR: + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + break; + case SCE_FS_IDENTIFIER: + case SCE_FS_IDENTIFIER_C: + if (!IsAWordChar(sc.ch)) { + char s[64]; + sc.GetCurrentLowered(s, sizeof(s)); + if (keywords.InList(s)) { + sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD : SCE_FS_KEYWORD_C); + } else if (keywords2.InList(s)) { + sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD2 : SCE_FS_KEYWORD2_C); + } else if (bEnableCode && keywords3.InList(s)) { + sc.ChangeState(SCE_FS_KEYWORD3); + } else if (bEnableCode && keywords4.InList(s)) { + sc.ChangeState(SCE_FS_KEYWORD4); + }// Else, it is really an identifier... + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_NUMBER: + case SCE_FS_NUMBER_C: + if (!IsAWordChar(sc.ch) && sc.ch != '.') { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_CONSTANT: + if (!IsAWordChar(sc.ch)) { + sc.SetState(SCE_FS_DEFAULT); + } + break; + case SCE_FS_STRING: + case SCE_FS_STRING_C: + if (sc.ch == closeStringChar) { + sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.atLineEnd) { + sc.ChangeState(bEnableCode ? SCE_FS_STRINGEOL : SCE_FS_STRINGEOL_C); + } + break; + case SCE_FS_STRINGEOL: + case SCE_FS_STRINGEOL_C: + if (sc.atLineStart) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_COMMENTDOC: + case SCE_FS_COMMENTDOC_C: + if (sc.Match('*', '/')) { + sc.Forward(); + sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support + // Verify that we have the conditions to mark a comment-doc-keyword + if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { + styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C; + sc.SetState(SCE_FS_COMMENTDOCKEYWORD); + } + } + break; + case SCE_FS_COMMENT: + case SCE_FS_COMMENTLINE: + if (sc.atLineStart) { + sc.SetState(SCE_FS_DEFAULT); + } + break; + case SCE_FS_COMMENTLINEDOC: + case SCE_FS_COMMENTLINEDOC_C: + if (sc.atLineStart) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support + // Verify that we have the conditions to mark a comment-doc-keyword + if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { + styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C; + sc.SetState(SCE_FS_COMMENTDOCKEYWORD); + } + } + break; + case SCE_FS_COMMENTDOCKEYWORD: + if ((styleBeforeDCKeyword == SCE_FS_COMMENTDOC || styleBeforeDCKeyword == SCE_FS_COMMENTDOC_C) && + sc.Match('*', '/')) { + sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR); + sc.Forward(); + sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (!setDoxygen.Contains(sc.ch)) { + char s[64]; + sc.GetCurrentLowered(s, sizeof(s)); + if (!IsASpace(sc.ch) || !keywords5.InList(s + 1)) { + sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR); + } + sc.SetState(styleBeforeDCKeyword); + } + break; + case SCE_FS_PREPROCESSOR: + case SCE_FS_PREPROCESSOR_C: + if (sc.atLineEnd) { + if (!(sc.chPrev == ';' || sc.GetRelative(-2) == ';')) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + } else if (stylingWithinPreprocessor) { + if (IsASpaceOrTab(sc.ch)) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + } else if (sc.Match('/', '*') || sc.Match('/', '/') || sc.Match('&', '&')) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } + break; + case SCE_FS_DISABLEDCODE: + if (sc.ch == '#' && visibleChars == 0) { + sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C); + do { // Skip whitespace between # and preprocessor word + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.MatchIgnoreCase("pragma")) { + sc.Forward(6); + do { // Skip more whitespace until keyword + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) { + bEnableCode = true; + sc.SetState(SCE_FS_DISABLEDCODE); + sc.Forward(sc.ch == '_' ? 8 : 6); + sc.ForwardSetState(SCE_FS_DEFAULT); + } else { + sc.ChangeState(SCE_FS_DISABLEDCODE); + } + } else { + sc.ChangeState(SCE_FS_DISABLEDCODE); + } + } + break; + case SCE_FS_DATE: + if (sc.ch == '}') { + sc.ForwardSetState(SCE_FS_DEFAULT); + } else if (sc.atLineEnd) { + sc.ChangeState(SCE_FS_STRINGEOL); + } + } + + // Determine if a new state should be entered. + if (sc.state == SCE_FS_DEFAULT || sc.state == SCE_FS_DEFAULT_C) { + if (bEnableCode && + (sc.MatchIgnoreCase(".and.") || sc.MatchIgnoreCase(".not."))) { + sc.SetState(SCE_FS_WORDOPERATOR); + sc.Forward(4); + } else if (bEnableCode && sc.MatchIgnoreCase(".or.")) { + sc.SetState(SCE_FS_WORDOPERATOR); + sc.Forward(3); + } else if (bEnableCode && + (sc.MatchIgnoreCase(".t.") || sc.MatchIgnoreCase(".f.") || + (!IsAWordChar(sc.GetRelative(3)) && sc.MatchIgnoreCase("nil")))) { + sc.SetState(SCE_FS_CONSTANT); + sc.Forward(2); + } else if (sc.Match('/', '*')) { + sc.SetState(bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C); + sc.Forward(); + } else if (bEnableCode && sc.Match('&', '&')) { + sc.SetState(SCE_FS_COMMENTLINE); + sc.Forward(); + } else if (sc.Match('/', '/')) { + sc.SetState(bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C); + sc.Forward(); + } else if (bEnableCode && sc.ch == '*' && visibleChars == 0) { + sc.SetState(SCE_FS_COMMENT); + } else if (sc.ch == '\"' || sc.ch == '\'') { + sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C); + closeStringChar = sc.ch; + } else if (closeStringChar == '>' && sc.ch == '<') { + sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C); + } else if (sc.ch == '#' && visibleChars == 0) { + sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C); + do { // Skip whitespace between # and preprocessor word + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.atLineEnd) { + sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); + } else if (sc.MatchIgnoreCase("include")) { + if (stylingWithinPreprocessor) { + closeStringChar = '>'; + } + } else if (sc.MatchIgnoreCase("pragma")) { + sc.Forward(6); + do { // Skip more whitespace until keyword + sc.Forward(); + } while (IsASpaceOrTab(sc.ch) && sc.More()); + if (sc.MatchIgnoreCase("begindump") || sc.MatchIgnoreCase("__cstream")) { + bEnableCode = false; + if (stylingWithinPreprocessor) { + sc.SetState(SCE_FS_DISABLEDCODE); + sc.Forward(8); + sc.ForwardSetState(SCE_FS_DEFAULT_C); + } else { + sc.SetState(SCE_FS_DISABLEDCODE); + } + } else if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) { + bEnableCode = true; + sc.SetState(SCE_FS_DISABLEDCODE); + sc.Forward(sc.ch == '_' ? 8 : 6); + sc.ForwardSetState(SCE_FS_DEFAULT); + } + } + } else if (bEnableCode && sc.ch == '{') { + int p = 0; + int chSeek; + unsigned int endPos(startPos + length); + do { // Skip whitespace + chSeek = sc.GetRelative(++p); + } while (IsASpaceOrTab(chSeek) && (sc.currentPos + p < endPos)); + if (chSeek == '^') { + sc.SetState(SCE_FS_DATE); + } else { + sc.SetState(SCE_FS_OPERATOR); + } + } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { + sc.SetState(bEnableCode ? SCE_FS_NUMBER : SCE_FS_NUMBER_C); + } else if (IsAWordChar(sc.ch)) { + sc.SetState(bEnableCode ? SCE_FS_IDENTIFIER : SCE_FS_IDENTIFIER_C); + } else if (isoperator(static_cast(sc.ch)) || (bEnableCode && sc.ch == '@')) { + sc.SetState(bEnableCode ? SCE_FS_OPERATOR : SCE_FS_OPERATOR_C); + } + } + + if (sc.atLineEnd) { + visibleChars = 0; + closeStringChar = 0; + } + if (!IsASpace(sc.ch)) { + visibleChars++; + } + } + sc.Complete(); +} + +static void FoldFlagShipDoc(unsigned int startPos, int length, int, + WordList *[], Accessor &styler) +{ + + int endPos = startPos + length; + + // Backtrack to previous line in case need to fix its fold status + int lineCurrent = styler.GetLine(startPos); + if (startPos > 0 && lineCurrent > 0) { + lineCurrent--; + startPos = styler.LineStart(lineCurrent); + } + int spaceFlags = 0; + int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags); + char chNext = styler[startPos]; + for (int i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos-1)) { + int lev = indentCurrent; + int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags); + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { + if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { + int spaceFlags2 = 0; + int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2); + if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + } + } + indentCurrent = indentNext; + styler.SetLevel(lineCurrent, lev); + lineCurrent++; + } + } +} + +static const char * const FSWordListDesc[] = { + "Keywords Commands", + "Std Library Functions", + "Procedure, return, exit", + "Class (oop)", + "Doxygen keywords", + 0 +}; + +LexerModule lmFlagShip(SCLEX_FLAGSHIP, ColouriseFlagShipDoc, "flagship", FoldFlagShipDoc, FSWordListDesc); diff --git a/harbour/contrib/hbide/qscintilla/License.txt b/harbour/contrib/hbide/qscintilla/License.txt new file mode 100644 index 0000000000..cbe25b2fc2 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/License.txt @@ -0,0 +1,20 @@ +License for Scintilla and SciTE + +Copyright 1998-2003 by Neil Hodgson + +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. + +NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/harbour/contrib/hbide/qscintilla/LineMarker.cpp b/harbour/contrib/hbide/qscintilla/LineMarker.cpp new file mode 100644 index 0000000000..4c5a1683ca --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/LineMarker.cpp @@ -0,0 +1,309 @@ +// Scintilla source code edit control +/** @file LineMarker.cxx + ** Defines the look of a line marker in the margin . + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "XPM.h" +#include "LineMarker.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +void LineMarker::RefreshColourPalette(Palette &pal, bool want) { + pal.WantFind(fore, want); + pal.WantFind(back, want); + if (pxpm) { + pxpm->RefreshColourPalette(pal, want); + } +} + +void LineMarker::SetXPM(const char *textForm) { + delete pxpm; + pxpm = new XPM(textForm); + markType = SC_MARK_PIXMAP; +} + +void LineMarker::SetXPM(const char * const *linesForm) { + delete pxpm; + pxpm = new XPM(linesForm); + markType = SC_MARK_PIXMAP; +} + +static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore, ColourAllocated back) { + PRectangle rc; + rc.left = centreX - armSize; + rc.top = centreY - armSize; + rc.right = centreX + armSize + 1; + rc.bottom = centreY + armSize + 1; + surface->RectangleDraw(rc, back, fore); +} + +static void DrawCircle(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore, ColourAllocated back) { + PRectangle rcCircle; + rcCircle.left = centreX - armSize; + rcCircle.top = centreY - armSize; + rcCircle.right = centreX + armSize + 1; + rcCircle.bottom = centreY + armSize + 1; + surface->Ellipse(rcCircle, back, fore); +} + +static void DrawPlus(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore) { + PRectangle rcV(centreX, centreY - armSize + 2, centreX + 1, centreY + armSize - 2 + 1); + surface->FillRectangle(rcV, fore); + PRectangle rcH(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY+1); + surface->FillRectangle(rcH, fore); +} + +static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore) { + PRectangle rcH(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY+1); + surface->FillRectangle(rcH, fore); +} + +void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter) { + if ((markType == SC_MARK_PIXMAP) && (pxpm)) { + pxpm->Draw(surface, rcWhole); + return; + } + // Restrict most shapes a bit + PRectangle rc = rcWhole; + rc.top++; + rc.bottom--; + int minDim = Platform::Minimum(rc.Width(), rc.Height()); + minDim--; // Ensure does not go beyond edge + int centreX = (rc.right + rc.left) / 2; + int centreY = (rc.bottom + rc.top) / 2; + int dimOn2 = minDim / 2; + int dimOn4 = minDim / 4; + int blobSize = dimOn2-1; + int armSize = dimOn2-2; + if (rc.Width() > (rc.Height() * 2)) { + // Wide column is line number so move to left to try to avoid overlapping number + centreX = rc.left + dimOn2 + 1; + } + if (markType == SC_MARK_ROUNDRECT) { + PRectangle rcRounded = rc; + rcRounded.left = rc.left + 1; + rcRounded.right = rc.right - 1; + surface->RoundedRectangle(rcRounded, fore.allocated, back.allocated); + } else if (markType == SC_MARK_CIRCLE) { + PRectangle rcCircle; + rcCircle.left = centreX - dimOn2; + rcCircle.top = centreY - dimOn2; + rcCircle.right = centreX + dimOn2; + rcCircle.bottom = centreY + dimOn2; + surface->Ellipse(rcCircle, fore.allocated, back.allocated); + } else if (markType == SC_MARK_ARROW) { + Point pts[] = { + Point(centreX - dimOn4, centreY - dimOn2), + Point(centreX - dimOn4, centreY + dimOn2), + Point(centreX + dimOn2 - dimOn4, centreY), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + fore.allocated, back.allocated); + + } else if (markType == SC_MARK_ARROWDOWN) { + Point pts[] = { + Point(centreX - dimOn2, centreY - dimOn4), + Point(centreX + dimOn2, centreY - dimOn4), + Point(centreX, centreY + dimOn2 - dimOn4), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + fore.allocated, back.allocated); + + } else if (markType == SC_MARK_PLUS) { + Point pts[] = { + Point(centreX - armSize, centreY - 1), + Point(centreX - 1, centreY - 1), + Point(centreX - 1, centreY - armSize), + Point(centreX + 1, centreY - armSize), + Point(centreX + 1, centreY - 1), + Point(centreX + armSize, centreY -1), + Point(centreX + armSize, centreY +1), + Point(centreX + 1, centreY + 1), + Point(centreX + 1, centreY + armSize), + Point(centreX - 1, centreY + armSize), + Point(centreX - 1, centreY + 1), + Point(centreX - armSize, centreY + 1), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + fore.allocated, back.allocated); + + } else if (markType == SC_MARK_MINUS) { + Point pts[] = { + Point(centreX - armSize, centreY - 1), + Point(centreX + armSize, centreY -1), + Point(centreX + armSize, centreY +1), + Point(centreX - armSize, centreY + 1), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + fore.allocated, back.allocated); + + } else if (markType == SC_MARK_SMALLRECT) { + PRectangle rcSmall; + rcSmall.left = rc.left + 1; + rcSmall.top = rc.top + 2; + rcSmall.right = rc.right - 1; + rcSmall.bottom = rc.bottom - 2; + surface->RectangleDraw(rcSmall, fore.allocated, back.allocated); + + } else if (markType == SC_MARK_EMPTY || markType == SC_MARK_BACKGROUND) { + // An invisible marker so don't draw anything + + } else if (markType == SC_MARK_VLINE) { + surface->PenColour(back.allocated); + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, rcWhole.bottom); + + } else if (markType == SC_MARK_LCORNER) { + surface->PenColour(back.allocated); + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, rc.top + dimOn2); + surface->LineTo(rc.right - 2, rc.top + dimOn2); + + } else if (markType == SC_MARK_TCORNER) { + surface->PenColour(back.allocated); + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, rcWhole.bottom); + surface->MoveTo(centreX, rc.top + dimOn2); + surface->LineTo(rc.right - 2, rc.top + dimOn2); + + } else if (markType == SC_MARK_LCORNERCURVE) { + surface->PenColour(back.allocated); + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, rc.top + dimOn2-3); + surface->LineTo(centreX+3, rc.top + dimOn2); + surface->LineTo(rc.right - 1, rc.top + dimOn2); + + } else if (markType == SC_MARK_TCORNERCURVE) { + surface->PenColour(back.allocated); + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, rcWhole.bottom); + + surface->MoveTo(centreX, rc.top + dimOn2-3); + surface->LineTo(centreX+3, rc.top + dimOn2); + surface->LineTo(rc.right - 1, rc.top + dimOn2); + + } else if (markType == SC_MARK_BOXPLUS) { + surface->PenColour(back.allocated); + DrawBox(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + DrawPlus(surface, centreX, centreY, blobSize, back.allocated); + + } else if (markType == SC_MARK_BOXPLUSCONNECTED) { + surface->PenColour(back.allocated); + DrawBox(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + DrawPlus(surface, centreX, centreY, blobSize, back.allocated); + + surface->MoveTo(centreX, centreY + blobSize); + surface->LineTo(centreX, rcWhole.bottom); + + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, centreY - blobSize); + + } else if (markType == SC_MARK_BOXMINUS) { + surface->PenColour(back.allocated); + DrawBox(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + DrawMinus(surface, centreX, centreY, blobSize, back.allocated); + + surface->MoveTo(centreX, centreY + blobSize); + surface->LineTo(centreX, rcWhole.bottom); + + } else if (markType == SC_MARK_BOXMINUSCONNECTED) { + surface->PenColour(back.allocated); + DrawBox(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + DrawMinus(surface, centreX, centreY, blobSize, back.allocated); + + surface->MoveTo(centreX, centreY + blobSize); + surface->LineTo(centreX, rcWhole.bottom); + + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, centreY - blobSize); + + } else if (markType == SC_MARK_CIRCLEPLUS) { + DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + surface->PenColour(back.allocated); + DrawPlus(surface, centreX, centreY, blobSize, back.allocated); + + } else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) { + DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + surface->PenColour(back.allocated); + DrawPlus(surface, centreX, centreY, blobSize, back.allocated); + + surface->MoveTo(centreX, centreY + blobSize); + surface->LineTo(centreX, rcWhole.bottom); + + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, centreY - blobSize); + + } else if (markType == SC_MARK_CIRCLEMINUS) { + DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + surface->PenColour(back.allocated); + DrawMinus(surface, centreX, centreY, blobSize, back.allocated); + + surface->MoveTo(centreX, centreY + blobSize); + surface->LineTo(centreX, rcWhole.bottom); + + } else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) { + DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, back.allocated); + surface->PenColour(back.allocated); + DrawMinus(surface, centreX, centreY, blobSize, back.allocated); + + surface->MoveTo(centreX, centreY + blobSize); + surface->LineTo(centreX, rcWhole.bottom); + + surface->MoveTo(centreX, rcWhole.top); + surface->LineTo(centreX, centreY - blobSize); + + } else if (markType >= SC_MARK_CHARACTER) { + char character[1]; + character[0] = static_cast(markType - SC_MARK_CHARACTER); + int width = surface->WidthText(fontForCharacter, character, 1); + rc.left += (rc.Width() - width) / 2; + rc.right = rc.left + width; + surface->DrawTextClipped(rc, fontForCharacter, rc.bottom - 2, + character, 1, fore.allocated, back.allocated); + + } else if (markType == SC_MARK_DOTDOTDOT) { + int right = centreX - 6; + for (int b=0; b<3; b++) { + PRectangle rcBlob(right, rc.bottom - 4, right + 2, rc.bottom-2); + surface->FillRectangle(rcBlob, fore.allocated); + right += 5; + } + } else if (markType == SC_MARK_ARROWS) { + surface->PenColour(fore.allocated); + int right = centreX - 2; + for (int b=0; b<3; b++) { + surface->MoveTo(right - 4, centreY - 4); + surface->LineTo(right, centreY); + surface->LineTo(right - 5, centreY + 5); + right += 4; + } + } else if (markType == SC_MARK_SHORTARROW) { + Point pts[] = { + Point(centreX, centreY + dimOn2), + Point(centreX + dimOn2, centreY), + Point(centreX, centreY - dimOn2), + Point(centreX, centreY - dimOn4), + Point(centreX - dimOn4, centreY - dimOn4), + Point(centreX - dimOn4, centreY + dimOn4), + Point(centreX, centreY + dimOn4), + Point(centreX, centreY + dimOn2), + }; + surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), + fore.allocated, back.allocated); + } else if (markType == SC_MARK_LEFTRECT) { + PRectangle rcLeft = rcWhole; + rcLeft.right = rcLeft.left + 4; + surface->FillRectangle(rcLeft, back.allocated); + } else { // SC_MARK_FULLRECT + surface->FillRectangle(rcWhole, back.allocated); + } +} diff --git a/harbour/contrib/hbide/qscintilla/LineMarker.h b/harbour/contrib/hbide/qscintilla/LineMarker.h new file mode 100644 index 0000000000..3cb4139f08 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/LineMarker.h @@ -0,0 +1,62 @@ +// Scintilla source code edit control +/** @file LineMarker.h + ** Defines the look of a line marker in the margin . + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef LINEMARKER_H +#define LINEMARKER_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class LineMarker { +public: + int markType; + ColourPair fore; + ColourPair back; + int alpha; + XPM *pxpm; + LineMarker() { + markType = SC_MARK_CIRCLE; + fore = ColourDesired(0,0,0); + back = ColourDesired(0xff,0xff,0xff); + alpha = SC_ALPHA_NOALPHA; + pxpm = NULL; + } + LineMarker(const LineMarker &) { + // Defined to avoid pxpm being blindly copied, not as real copy constructor + markType = SC_MARK_CIRCLE; + fore = ColourDesired(0,0,0); + back = ColourDesired(0xff,0xff,0xff); + alpha = SC_ALPHA_NOALPHA; + pxpm = NULL; + } + ~LineMarker() { + delete pxpm; + } + LineMarker &operator=(const LineMarker &) { + // Defined to avoid pxpm being blindly copied, not as real assignment operator + markType = SC_MARK_CIRCLE; + fore = ColourDesired(0,0,0); + back = ColourDesired(0xff,0xff,0xff); + alpha = SC_ALPHA_NOALPHA; + delete pxpm; + pxpm = NULL; + return *this; + } + void RefreshColourPalette(Palette &pal, bool want); + void SetXPM(const char *textForm); + void SetXPM(const char * const *linesForm); + void Draw(Surface *surface, PRectangle &rc, Font &fontForCharacter); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Partitioning.h b/harbour/contrib/hbide/qscintilla/Partitioning.h new file mode 100644 index 0000000000..752e69614c --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Partitioning.h @@ -0,0 +1,184 @@ +// Scintilla source code edit control +/** @file Partitioning.h + ** Data structure used to partition an interval. Used for holding line start/end positions. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PARTITIONING_H +#define PARTITIONING_H + +/// A split vector of integers with a method for adding a value to all elements +/// in a range. +/// Used by the Partitioning class. + +class SplitVectorWithRangeAdd : public SplitVector { +public: + SplitVectorWithRangeAdd(int growSize_) { + SetGrowSize(growSize_); + ReAllocate(growSize_); + } + ~SplitVectorWithRangeAdd() { + } + void RangeAddDelta(int start, int end, int delta) { + // end is 1 past end, so end-start is number of elements to change + int i = 0; + int rangeLength = end - start; + int range1Length = rangeLength; + int part1Left = part1Length - start; + if (range1Length > part1Left) + range1Length = part1Left; + while (i < range1Length) { + body[start++] += delta; + i++; + } + start += gapLength; + while (i < rangeLength) { + body[start++] += delta; + i++; + } + } +}; + +/// Divide an interval into multiple partitions. +/// Useful for breaking a document down into sections such as lines. + +class Partitioning { +private: + // To avoid calculating all the partition positions whenever any text is inserted + // there may be a step somewhere in the list. + int stepPartition; + int stepLength; + SplitVectorWithRangeAdd *body; + + // Move step forward + void ApplyStep(int partitionUpTo) { + if (stepLength != 0) { + body->RangeAddDelta(stepPartition+1, partitionUpTo + 1, stepLength); + } + stepPartition = partitionUpTo; + if (stepPartition >= body->Length()-1) { + stepPartition = body->Length()-1; + stepLength = 0; + } + } + + // Move step backward + void BackStep(int partitionDownTo) { + if (stepLength != 0) { + body->RangeAddDelta(partitionDownTo+1, stepPartition+1, -stepLength); + } + stepPartition = partitionDownTo; + } + + void Allocate(int growSize) { + body = new SplitVectorWithRangeAdd(growSize); + stepPartition = 0; + stepLength = 0; + body->Insert(0, 0); // This value stays 0 for ever + body->Insert(1, 0); // This is the end of the first partition and will be the start of the second + } + +public: + Partitioning(int growSize) { + Allocate(growSize); + } + + ~Partitioning() { + delete body; + body = 0; + } + + int Partitions() const { + return body->Length()-1; + } + + void InsertPartition(int partition, int pos) { + if (stepPartition < partition) { + ApplyStep(partition); + } + body->Insert(partition, pos); + stepPartition++; + } + + void SetPartitionStartPosition(int partition, int pos) { + ApplyStep(partition+1); + if ((partition < 0) || (partition > body->Length())) { + return; + } + body->SetValueAt(partition, pos); + } + + void InsertText(int partitionInsert, int delta) { + // Point all the partitions after the insertion point further along in the buffer + if (stepLength != 0) { + if (partitionInsert >= stepPartition) { + // Fill in up to the new insertion point + ApplyStep(partitionInsert); + stepLength += delta; + } else if (partitionInsert >= (stepPartition - body->Length() / 10)) { + // Close to step but before so move step back + BackStep(partitionInsert); + stepLength += delta; + } else { + ApplyStep(body->Length()-1); + stepPartition = partitionInsert; + stepLength = delta; + } + } else { + stepPartition = partitionInsert; + stepLength = delta; + } + } + + void RemovePartition(int partition) { + if (partition > stepPartition) { + ApplyStep(partition); + stepPartition--; + } else { + stepPartition--; + } + body->Delete(partition); + } + + int PositionFromPartition(int partition) const { + PLATFORM_ASSERT(partition >= 0); + PLATFORM_ASSERT(partition < body->Length()); + if ((partition < 0) || (partition >= body->Length())) { + return 0; + } + int pos = body->ValueAt(partition); + if (partition > stepPartition) + pos += stepLength; + return pos; + } + + int PartitionFromPosition(int pos) { + if (body->Length() <= 1) + return 0; + if (pos >= (PositionFromPartition(body->Length()-1))) + return body->Length() - 1 - 1; + int lower = 0; + int upper = body->Length()-1; + do { + int middle = (upper + lower + 1) / 2; // Round high + int posMiddle = body->ValueAt(middle); + if (middle > stepPartition) + posMiddle += stepLength; + if (pos < posMiddle) { + upper = middle - 1; + } else { + lower = middle; + } + } while (lower < upper); + return lower; + } + + void DeleteAll() { + int growSize = body->GetGrowSize(); + delete body; + Allocate(growSize); + } +}; + +#endif diff --git a/harbour/contrib/hbide/qscintilla/PerLine.cpp b/harbour/contrib/hbide/qscintilla/PerLine.cpp new file mode 100644 index 0000000000..29cdfbfa55 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/PerLine.cpp @@ -0,0 +1,464 @@ +// Scintilla source code edit control +/** @file PerLine.cxx + ** Manages data associated with each line of the document + **/ +// Copyright 1998-2009 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "CellBuffer.h" +#include "PerLine.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +MarkerHandleSet::MarkerHandleSet() { + root = 0; +} + +MarkerHandleSet::~MarkerHandleSet() { + MarkerHandleNumber *mhn = root; + while (mhn) { + MarkerHandleNumber *mhnToFree = mhn; + mhn = mhn->next; + delete mhnToFree; + } + root = 0; +} + +int MarkerHandleSet::Length() const { + int c = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + c++; + mhn = mhn->next; + } + return c; +} + +int MarkerHandleSet::NumberFromHandle(int handle) const { + MarkerHandleNumber *mhn = root; + while (mhn) { + if (mhn->handle == handle) { + return mhn->number; + } + mhn = mhn->next; + } + return - 1; +} + +int MarkerHandleSet::MarkValue() const { + unsigned int m = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + m |= (1 << mhn->number); + mhn = mhn->next; + } + return m; +} + +bool MarkerHandleSet::Contains(int handle) const { + MarkerHandleNumber *mhn = root; + while (mhn) { + if (mhn->handle == handle) { + return true; + } + mhn = mhn->next; + } + return false; +} + +bool MarkerHandleSet::InsertHandle(int handle, int markerNum) { + MarkerHandleNumber *mhn = new MarkerHandleNumber; + if (!mhn) + return false; + mhn->handle = handle; + mhn->number = markerNum; + mhn->next = root; + root = mhn; + return true; +} + +void MarkerHandleSet::RemoveHandle(int handle) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + MarkerHandleNumber *mhn = *pmhn; + if (mhn->handle == handle) { + *pmhn = mhn->next; + delete mhn; + return; + } + pmhn = &((*pmhn)->next); + } +} + +bool MarkerHandleSet::RemoveNumber(int markerNum) { + bool performedDeletion = false; + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + MarkerHandleNumber *mhn = *pmhn; + if (mhn->number == markerNum) { + *pmhn = mhn->next; + delete mhn; + performedDeletion = true; + } else { + pmhn = &((*pmhn)->next); + } + } + return performedDeletion; +} + +void MarkerHandleSet::CombineWith(MarkerHandleSet *other) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + pmhn = &((*pmhn)->next); + } + *pmhn = other->root; + other->root = 0; +} + +LineMarkers::~LineMarkers() { + for (int line = 0; line < markers.Length(); line++) { + delete markers[line]; + markers[line] = 0; + } + markers.DeleteAll(); +} + +void LineMarkers::InsertLine(int line) { + if (markers.Length()) { + markers.Insert(line, 0); + } +} + +void LineMarkers::RemoveLine(int line) { + // Retain the markers from the deleted line by oring them into the previous line + if (markers.Length()) { + if (line > 0) { + MergeMarkers(line - 1); + } + markers.Delete(line); + } +} + +int LineMarkers::LineFromHandle(int markerHandle) { + if (markers.Length()) { + for (int line = 0; line < markers.Length(); line++) { + if (markers[line]) { + if (markers[line]->Contains(markerHandle)) { + return line; + } + } + } + } + return -1; +} + +void LineMarkers::MergeMarkers(int pos) { + if (markers[pos + 1] != NULL) { + if (markers[pos] == NULL) + markers[pos] = new MarkerHandleSet; + markers[pos]->CombineWith(markers[pos + 1]); + delete markers[pos + 1]; + markers[pos + 1] = NULL; + } +} + +int LineMarkers::MarkValue(int line) { + if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) + return markers[line]->MarkValue(); + else + return 0; +} + +int LineMarkers::AddMark(int line, int markerNum, int lines) { + handleCurrent++; + if (!markers.Length()) { + // No existing markers so allocate one element per line + markers.InsertValue(0, lines, 0); + } + if (!markers[line]) { + // Need new structure to hold marker handle + markers[line] = new MarkerHandleSet(); + if (!markers[line]) + return - 1; + } + markers[line]->InsertHandle(handleCurrent, markerNum); + + return handleCurrent; +} + +void LineMarkers::DeleteMark(int line, int markerNum, bool all) { + if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { + if (markerNum == -1) { + delete markers[line]; + markers[line] = NULL; + } else { + bool performedDeletion = markers[line]->RemoveNumber(markerNum); + while (all && performedDeletion) { + performedDeletion = markers[line]->RemoveNumber(markerNum); + } + if (markers[line]->Length() == 0) { + delete markers[line]; + markers[line] = NULL; + } + } + } +} + +void LineMarkers::DeleteMarkFromHandle(int markerHandle) { + int line = LineFromHandle(markerHandle); + if (line >= 0) { + markers[line]->RemoveHandle(markerHandle); + if (markers[line]->Length() == 0) { + delete markers[line]; + markers[line] = NULL; + } + } +} + +LineLevels::~LineLevels() { +} + +void LineLevels::InsertLine(int line) { + if (levels.Length()) { + int level = SC_FOLDLEVELBASE; + if ((line > 0) && (line < levels.Length())) { + level = levels[line-1] & ~SC_FOLDLEVELWHITEFLAG; + } + levels.InsertValue(line, 1, level); + } +} + +void LineLevels::RemoveLine(int line) { + if (levels.Length()) { + // Move up following lines but merge header flag from this line + // to line before to avoid a temporary disappearence causing expansion. + int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG; + levels.Delete(line); + if (line > 0) + levels[line-1] |= firstHeader; + } +} + +void LineLevels::ExpandLevels(int sizeNew) { + levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE); +} + +void LineLevels::ClearLevels() { + levels.DeleteAll(); +} + +int LineLevels::SetLevel(int line, int level, int lines) { + int prev = 0; + if ((line >= 0) && (line < lines)) { + if (!levels.Length()) { + ExpandLevels(lines + 1); + } + prev = levels[line]; + if (prev != level) { + levels[line] = level; + } + } + return prev; +} + +int LineLevels::GetLevel(int line) { + if (levels.Length() && (line >= 0) && (line < levels.Length())) { + return levels[line]; + } else { + return SC_FOLDLEVELBASE; + } +} + +LineState::~LineState() { +} + +void LineState::InsertLine(int line) { + if (lineStates.Length()) { + lineStates.EnsureLength(line); + lineStates.Insert(line, 0); + } +} + +void LineState::RemoveLine(int line) { + if (lineStates.Length() > line) { + lineStates.Delete(line); + } +} + +int LineState::SetLineState(int line, int state) { + lineStates.EnsureLength(line + 1); + int stateOld = lineStates[line]; + lineStates[line] = state; + return stateOld; +} + +int LineState::GetLineState(int line) { + lineStates.EnsureLength(line + 1); + return lineStates[line]; +} + +int LineState::GetMaxLineState() { + return lineStates.Length(); +} + +static int NumberLines(const char *text) { + if (text) { + int newLines = 0; + while (*text) { + if (*text == '\n') + newLines++; + text++; + } + return newLines+1; + } else { + return 0; + } +} + +// Each allocated LineAnnotation is a char array which starts with an AnnotationHeader +// and then has text and optional styles. + +static const int IndividualStyles = 0x100; + +struct AnnotationHeader { + short style; // Style IndividualStyles implies array of styles + short lines; + int length; +}; + +LineAnnotation::~LineAnnotation() { + ClearAll(); +} + +void LineAnnotation::InsertLine(int line) { + if (annotations.Length()) { + annotations.Insert(line, 0); + } +} + +void LineAnnotation::RemoveLine(int line) { + if (annotations.Length() && (line < annotations.Length())) { + delete []annotations[line]; + annotations.Delete(line); + } +} + +bool LineAnnotation::AnySet() const { + return annotations.Length() > 0; +} + +bool LineAnnotation::MultipleStyles(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast(annotations[line])->style == IndividualStyles; + else + return 0; +} + +int LineAnnotation::Style(int line) { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast(annotations[line])->style; + else + return 0; +} + +const char *LineAnnotation::Text(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return annotations[line]+sizeof(AnnotationHeader); + else + return 0; +} + +const unsigned char *LineAnnotation::Styles(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line] && MultipleStyles(line)) + return reinterpret_cast(annotations[line] + sizeof(AnnotationHeader) + Length(line)); + else + return 0; +} + +static char *AllocateAnnotation(int length, int style) { + size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0); + char *ret = new char[len]; + memset(ret, 0, len); + return ret; +} + +void LineAnnotation::SetText(int line, const char *text) { + if (text) { + annotations.EnsureLength(line+1); + int style = Style(line); + if (annotations[line]) { + delete []annotations[line]; + } + annotations[line] = AllocateAnnotation(strlen(text), style); + AnnotationHeader *pah = reinterpret_cast(annotations[line]); + pah->style = static_cast(style); + pah->length = strlen(text); + pah->lines = static_cast(NumberLines(text)); + memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length); + } else { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) { + delete []annotations[line]; + annotations[line] = 0; + } + } +} + +void LineAnnotation::ClearAll() { + for (int line = 0; line < annotations.Length(); line++) { + delete []annotations[line]; + annotations[line] = 0; + } + annotations.DeleteAll(); +} + +void LineAnnotation::SetStyle(int line, int style) { + annotations.EnsureLength(line+1); + if (!annotations[line]) { + annotations[line] = AllocateAnnotation(0, style); + } + reinterpret_cast(annotations[line])->style = static_cast(style); +} + +void LineAnnotation::SetStyles(int line, const unsigned char *styles) { + annotations.EnsureLength(line+1); + if (!annotations[line]) { + annotations[line] = AllocateAnnotation(0, IndividualStyles); + } else { + AnnotationHeader *pahSource = reinterpret_cast(annotations[line]); + if (pahSource->style != IndividualStyles) { + char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles); + AnnotationHeader *pahAlloc = reinterpret_cast(allocation); + pahAlloc->length = pahSource->length; + pahAlloc->lines = pahSource->lines; + memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length); + delete []annotations[line]; + annotations[line] = allocation; + } + } + AnnotationHeader *pah = reinterpret_cast(annotations[line]); + pah->style = IndividualStyles; + memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length); +} + +int LineAnnotation::Length(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast(annotations[line])->length; + else + return 0; +} + +int LineAnnotation::Lines(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast(annotations[line])->lines; + else + return 0; +} diff --git a/harbour/contrib/hbide/qscintilla/PerLine.h b/harbour/contrib/hbide/qscintilla/PerLine.h new file mode 100644 index 0000000000..8f3368b826 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/PerLine.h @@ -0,0 +1,116 @@ +// Scintilla source code edit control +/** @file PerLine.h + ** Manages data associated with each line of the document + **/ +// Copyright 1998-2009 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PERLINE_H +#define PERLINE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + * This holds the marker identifier and the marker type to display. + * MarkerHandleNumbers are members of lists. + */ +struct MarkerHandleNumber { + int handle; + int number; + MarkerHandleNumber *next; +}; + +/** + * A marker handle set contains any number of MarkerHandleNumbers. + */ +class MarkerHandleSet { + MarkerHandleNumber *root; + +public: + MarkerHandleSet(); + ~MarkerHandleSet(); + int Length() const; + int NumberFromHandle(int handle) const; + int MarkValue() const; ///< Bit set of marker numbers. + bool Contains(int handle) const; + bool InsertHandle(int handle, int markerNum); + void RemoveHandle(int handle); + bool RemoveNumber(int markerNum); + void CombineWith(MarkerHandleSet *other); +}; + +class LineMarkers : public PerLine { + SplitVector markers; + /// Handles are allocated sequentially and should never have to be reused as 32 bit ints are very big. + int handleCurrent; +public: + LineMarkers() : handleCurrent(0) { + } + virtual ~LineMarkers(); + virtual void InsertLine(int line); + virtual void RemoveLine(int line); + + int MarkValue(int line); + int AddMark(int line, int marker, int lines); + void MergeMarkers(int pos); + void DeleteMark(int line, int markerNum, bool all); + void DeleteMarkFromHandle(int markerHandle); + int LineFromHandle(int markerHandle); +}; + +class LineLevels : public PerLine { + SplitVector levels; +public: + virtual ~LineLevels(); + virtual void InsertLine(int line); + virtual void RemoveLine(int line); + + void ExpandLevels(int sizeNew=-1); + void ClearLevels(); + int SetLevel(int line, int level, int lines); + int GetLevel(int line); +}; + +class LineState : public PerLine { + SplitVector lineStates; +public: + LineState() { + } + virtual ~LineState(); + virtual void InsertLine(int line); + virtual void RemoveLine(int line); + + int SetLineState(int line, int state); + int GetLineState(int line); + int GetMaxLineState(); +}; + +class LineAnnotation : public PerLine { + SplitVector annotations; +public: + LineAnnotation() { + } + virtual ~LineAnnotation(); + virtual void InsertLine(int line); + virtual void RemoveLine(int line); + + bool AnySet() const; + bool MultipleStyles(int line) const; + int Style(int line); + const char *Text(int line) const; + const unsigned char *Styles(int line) const; + void SetText(int line, const char *text); + void ClearAll(); + void SetStyle(int line, int style); + void SetStyles(int line, const unsigned char *styles); + int Length(int line) const; + int Lines(int line) const; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Platform.h b/harbour/contrib/hbide/qscintilla/Platform.h new file mode 100644 index 0000000000..9c93b22bcc --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Platform.h @@ -0,0 +1,573 @@ +// Scintilla source code edit control +/** @file Platform.h + ** Interface to platform facilities. Also includes some basic utilities. + ** Implemented in PlatGTK.cxx for GTK+/Linux, PlatWin.cxx for Windows, and PlatWX.cxx for wxWindows. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PLATFORM_H +#define PLATFORM_H + +// PLAT_QT is Qt on any supported platform +// PLAT_GTK = GTK+ on Linux or Win32 +// PLAT_GTK_WIN32 is defined additionally when running PLAT_GTK under Win32 +// PLAT_WIN = Win32 API on Win32 OS +// PLAT_WX is wxWindows on any supported platform + +#define PLAT_QT 0 +#define PLAT_GTK 0 +#define PLAT_GTK_WIN32 0 +#define PLAT_MACOSX 0 +#define PLAT_WIN 0 +#define PLAT_WX 0 +#define PLAT_FOX 0 + +#if defined(FOX) +#undef PLAT_FOX +#define PLAT_FOX 1 + +#elif defined(QT) +#undef PLAT_QT +#define PLAT_QT 1 +// This is needed to work around an HP-UX bug with Qt4. +#include + +#elif defined(__WX__) +#undef PLAT_WX +#define PLAT_WX 1 + +#elif defined(GTK) +#undef PLAT_GTK +#define PLAT_GTK 1 + +#if defined(__WIN32__) || defined(_MSC_VER) +#undef PLAT_GTK_WIN32 +#define PLAT_GTK_WIN32 1 +#endif + +#elif defined(MACOSX) +#undef PLAT_MACOSX +#define PLAT_MACOSX 1 + +#else +#undef PLAT_WIN +#define PLAT_WIN 1 + +#endif + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +// Underlying the implementation of the platform classes are platform specific types. +// Sometimes these need to be passed around by client code so they are defined here + +typedef void *FontID; +typedef void *SurfaceID; +typedef void *WindowID; +typedef void *MenuID; +typedef void *TickerID; +typedef void *Function; +typedef void *IdlerID; + +/** + * A geometric point class. + * Point is exactly the same as the Win32 POINT and GTK+ GdkPoint so can be used interchangeably. + */ +class Point { +public: + int x; + int y; + + explicit Point(int x_=0, int y_=0) : x(x_), y(y_) { + } + + // Other automatically defined methods (assignment, copy constructor, destructor) are fine + + static Point FromLong(long lpoint); +}; + +/** + * A geometric rectangle class. + * PRectangle is exactly the same as the Win32 RECT so can be used interchangeably. + * PRectangles contain their top and left sides, but not their right and bottom sides. + */ +class PRectangle { +public: + int left; + int top; + int right; + int bottom; + + PRectangle(int left_=0, int top_=0, int right_=0, int bottom_ = 0) : + left(left_), top(top_), right(right_), bottom(bottom_) { + } + + // Other automatically defined methods (assignment, copy constructor, destructor) are fine + + bool operator==(PRectangle &rc) { + return (rc.left == left) && (rc.right == right) && + (rc.top == top) && (rc.bottom == bottom); + } + bool Contains(Point pt) { + return (pt.x >= left) && (pt.x <= right) && + (pt.y >= top) && (pt.y <= bottom); + } + bool Contains(PRectangle rc) { + return (rc.left >= left) && (rc.right <= right) && + (rc.top >= top) && (rc.bottom <= bottom); + } + bool Intersects(PRectangle other) { + return (right > other.left) && (left < other.right) && + (bottom > other.top) && (top < other.bottom); + } + void Move(int xDelta, int yDelta) { + left += xDelta; + top += yDelta; + right += xDelta; + bottom += yDelta; + } + int Width() { return right - left; } + int Height() { return bottom - top; } + bool Empty() { + return (Height() <= 0) || (Width() <= 0); + } +}; + +/** + * In some circumstances, including Win32 in paletted mode and GTK+, each colour + * must be allocated before use. The desired colours are held in the ColourDesired class, + * and after allocation the allocation entry is stored in the ColourAllocated class. In other + * circumstances, such as Win32 in true colour mode, the allocation process just copies + * the RGB values from the desired to the allocated class. + * As each desired colour requires allocation before it can be used, the ColourPair class + * holds both a ColourDesired and a ColourAllocated + * The Palette class is responsible for managing the palette of colours which contains a + * list of ColourPair objects and performs the allocation. + */ + +/** + * Holds a desired RGB colour. + */ +class ColourDesired { + long co; +public: + ColourDesired(long lcol=0) { + co = lcol; + } + + ColourDesired(unsigned int red, unsigned int green, unsigned int blue) { + Set(red, green, blue); + } + + bool operator==(const ColourDesired &other) const { + return co == other.co; + } + + void Set(long lcol) { + co = lcol; + } + + void Set(unsigned int red, unsigned int green, unsigned int blue) { + co = red | (green << 8) | (blue << 16); + } + + static inline unsigned int ValueOfHex(const char ch) { + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else + return 0; + } + + void Set(const char *val) { + if (*val == '#') { + val++; + } + unsigned int r = ValueOfHex(val[0]) * 16 + ValueOfHex(val[1]); + unsigned int g = ValueOfHex(val[2]) * 16 + ValueOfHex(val[3]); + unsigned int b = ValueOfHex(val[4]) * 16 + ValueOfHex(val[5]); + Set(r, g, b); + } + + long AsLong() const { + return co; + } + + unsigned int GetRed() { + return co & 0xff; + } + + unsigned int GetGreen() { + return (co >> 8) & 0xff; + } + + unsigned int GetBlue() { + return (co >> 16) & 0xff; + } +}; + +/** + * Holds an allocated RGB colour which may be an approximation to the desired colour. + */ +class ColourAllocated { + long coAllocated; + +public: + + ColourAllocated(long lcol=0) { + coAllocated = lcol; + } + + void Set(long lcol) { + coAllocated = lcol; + } + + long AsLong() const { + return coAllocated; + } +}; + +/** + * Colour pairs hold a desired colour and an allocated colour. + */ +struct ColourPair { + ColourDesired desired; + ColourAllocated allocated; + + ColourPair(ColourDesired desired_=ColourDesired(0,0,0)) { + desired = desired_; + allocated.Set(desired.AsLong()); + } + void Copy() { + allocated.Set(desired.AsLong()); + } +}; + +class Window; // Forward declaration for Palette + +/** + * Colour palette management. + */ +class Palette { + int used; + int size; + ColourPair *entries; +#if PLAT_GTK + void *allocatedPalette; // GdkColor * + int allocatedLen; +#endif + // Private so Palette objects can not be copied + Palette(const Palette &) {} + Palette &operator=(const Palette &) { return *this; } +public: +#if PLAT_WIN + void *hpal; +#endif + bool allowRealization; + + Palette(); + ~Palette(); + + void Release(); + + /** + * This method either adds a colour to the list of wanted colours (want==true) + * or retrieves the allocated colour back to the ColourPair. + * This is one method to make it easier to keep the code for wanting and retrieving in sync. + */ + void WantFind(ColourPair &cp, bool want); + + void Allocate(Window &w); +}; + +/** + * Font management. + */ +class Font { +protected: + FontID id; +#if PLAT_WX + int ascent; +#endif + // Private so Font objects can not be copied + Font(const Font &) {} + Font &operator=(const Font &) { id=0; return *this; } +public: + Font(); + virtual ~Font(); + + virtual void Create(const char *faceName, int characterSet, int size, + bool bold, bool italic, bool extraFontFlag=false); + virtual void Release(); + + FontID GetID() { return id; } + // Alias another font - caller guarantees not to Release + void SetID(FontID id_) { id = id_; } + friend class Surface; + friend class SurfaceImpl; +}; + +/** + * A surface abstracts a place to draw. + */ +#if defined(PLAT_QT) +class XPM; +class QPainter; +#endif + +class Surface { +private: + // Private so Surface objects can not be copied + Surface(const Surface &) {} + Surface &operator=(const Surface &) { return *this; } +public: + Surface() {}; + virtual ~Surface() {}; + static Surface *Allocate(); + + virtual void Init(WindowID wid)=0; + virtual void Init(SurfaceID sid, WindowID wid)=0; + virtual void InitPixMap(int width, int height, Surface *surface_, WindowID wid)=0; + + virtual void Release()=0; + virtual bool Initialised()=0; + virtual void PenColour(ColourAllocated fore)=0; + virtual int LogPixelsY()=0; + virtual int DeviceHeightFont(int points)=0; + virtual void MoveTo(int x_, int y_)=0; + virtual void LineTo(int x_, int y_)=0; + virtual void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back)=0; + virtual void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back)=0; + virtual void FillRectangle(PRectangle rc, ColourAllocated back)=0; + virtual void FillRectangle(PRectangle rc, Surface &surfacePattern)=0; + virtual void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back)=0; + virtual void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int flags)=0; + virtual void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back)=0; + virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0; + + virtual void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0; + virtual void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0; + virtual void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore)=0; + virtual void MeasureWidths(Font &font_, const char *s, int len, int *positions)=0; + virtual int WidthText(Font &font_, const char *s, int len)=0; + virtual int WidthChar(Font &font_, char ch)=0; + virtual int Ascent(Font &font_)=0; + virtual int Descent(Font &font_)=0; + virtual int InternalLeading(Font &font_)=0; + virtual int ExternalLeading(Font &font_)=0; + virtual int Height(Font &font_)=0; + virtual int AverageCharWidth(Font &font_)=0; + + virtual int SetPalette(Palette *pal, bool inBackGround)=0; + virtual void SetClip(PRectangle rc)=0; + virtual void FlushCachedState()=0; + + virtual void SetUnicodeMode(bool unicodeMode_)=0; + virtual void SetDBCSMode(int codePage)=0; + +#if defined(PLAT_QT) + virtual void Init(QPainter *p)=0; + virtual void DrawXPM(PRectangle rc, const XPM *xpm)=0; +#endif +}; + +/** + * A simple callback action passing one piece of untyped user data. + */ +typedef void (*CallBackAction)(void*); + +/** + * Class to hide the details of window manipulation. + * Does not own the window which will normally have a longer life than this object. + */ +class Window { +protected: + WindowID id; +#if PLAT_MACOSX + void *windowRef; + void *control; +#endif +public: + Window() : id(0), cursorLast(cursorInvalid) { +#if PLAT_MACOSX + windowRef = 0; + control = 0; +#endif + } + Window(const Window &source) : id(source.id), cursorLast(cursorInvalid) { +#if PLAT_MACOSX + windowRef = 0; + control = 0; +#endif + } + virtual ~Window(); + Window &operator=(WindowID id_) { + id = id_; + return *this; + } + WindowID GetID() const { return id; } + bool Created() const { return id != 0; } + void Destroy(); + bool HasFocus(); + PRectangle GetPosition(); + void SetPosition(PRectangle rc); + void SetPositionRelative(PRectangle rc, Window relativeTo); + PRectangle GetClientPosition(); + void Show(bool show=true); + void InvalidateAll(); + void InvalidateRectangle(PRectangle rc); + virtual void SetFont(Font &font); + enum Cursor { cursorInvalid, cursorText, cursorArrow, cursorUp, cursorWait, cursorHoriz, cursorVert, cursorReverseArrow, cursorHand }; + void SetCursor(Cursor curs); + void SetTitle(const char *s); + PRectangle GetMonitorRect(Point pt); +#if PLAT_MACOSX + void SetWindow(void *ref) { windowRef = ref; }; + void SetControl(void *_control) { control = _control; }; +#endif +private: + Cursor cursorLast; +}; + +/** + * Listbox management. + */ + +class ListBox : public Window { +public: + ListBox(); + virtual ~ListBox(); + static ListBox *Allocate(); + + virtual void SetFont(Font &font)=0; + virtual void Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_)=0; + virtual void SetAverageCharWidth(int width)=0; + virtual void SetVisibleRows(int rows)=0; + virtual int GetVisibleRows() const=0; + virtual PRectangle GetDesiredRect()=0; + virtual int CaretFromEdge()=0; + virtual void Clear()=0; + virtual void Append(char *s, int type = -1)=0; + virtual int Length()=0; + virtual void Select(int n)=0; + virtual int GetSelection()=0; + virtual int Find(const char *prefix)=0; + virtual void GetValue(int n, char *value, int len)=0; + virtual void RegisterImage(int type, const char *xpm_data)=0; + virtual void ClearRegisteredImages()=0; + virtual void SetDoubleClickAction(CallBackAction, void *)=0; + virtual void SetList(const char* list, char separator, char typesep)=0; +}; + +/** + * Menu management. + */ +class Menu { + MenuID id; +public: + Menu(); + MenuID GetID() { return id; } + void CreatePopUp(); + void Destroy(); + void Show(Point pt, Window &w); +}; + +class ElapsedTime { + long bigBit; + long littleBit; +public: + ElapsedTime(); + double Duration(bool reset=false); +}; + +/** + * Dynamic Library (DLL/SO/...) loading + */ +class DynamicLibrary { +public: + virtual ~DynamicLibrary() {}; + + /// @return Pointer to function "name", or NULL on failure. + virtual Function FindFunction(const char *name) = 0; + + /// @return true if the library was loaded successfully. + virtual bool IsValid() = 0; + + /// @return An instance of a DynamicLibrary subclass with "modulePath" loaded. + static DynamicLibrary *Load(const char *modulePath); +}; + +/** + * Platform class used to retrieve system wide parameters such as double click speed + * and chrome colour. Not a creatable object, more of a module with several functions. + */ +class Platform { + // Private so Platform objects can not be copied + Platform(const Platform &) {} + Platform &operator=(const Platform &) { return *this; } +public: + // Should be private because no new Platforms are ever created + // but gcc warns about this + Platform() {} + ~Platform() {} + static ColourDesired Chrome(); + static ColourDesired ChromeHighlight(); + static const char *DefaultFont(); + static int DefaultFontSize(); + static unsigned int DoubleClickTime(); + static bool MouseButtonBounce(); + static void DebugDisplay(const char *s); + static bool IsKeyDown(int key); + static long SendScintilla( + WindowID w, unsigned int msg, unsigned long wParam=0, long lParam=0); + static long SendScintillaPointer( + WindowID w, unsigned int msg, unsigned long wParam=0, void *lParam=0); + static bool IsDBCSLeadByte(int codePage, char ch); + static int DBCSCharLength(int codePage, const char *s); + static int DBCSCharMaxLength(); + + // These are utility functions not really tied to a platform + static int Minimum(int a, int b); + static int Maximum(int a, int b); + // Next three assume 16 bit shorts and 32 bit longs + static long LongFromTwoShorts(short a,short b) { + return (a) | ((b) << 16); + } + static short HighShortFromLong(long x) { + return static_cast(x >> 16); + } + static short LowShortFromLong(long x) { + return static_cast(x & 0xffff); + } + static void DebugPrintf(const char *format, ...); + static bool ShowAssertionPopUps(bool assertionPopUps_); + static void Assert(const char *c, const char *file, int line); + static int Clamp(int val, int minVal, int maxVal); +}; + +#ifdef QT_NO_DEBUG +#define PLATFORM_ASSERT(c) ((void)0) +#else +#ifdef SCI_NAMESPACE +#define PLATFORM_ASSERT(c) ((c) ? (void)(0) : Scintilla::Platform::Assert(#c, __FILE__, __LINE__)) +#else +#define PLATFORM_ASSERT(c) ((c) ? (void)(0) : Platform::Assert(#c, __FILE__, __LINE__)) +#endif +#endif + +#ifdef SCI_NAMESPACE +} +#endif + +// Shut up annoying Visual C++ warnings: +#ifdef _MSC_VER +#pragma warning(disable: 4244 4309 4514 4710) +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/PositionCache.cpp b/harbour/contrib/hbide/qscintilla/PositionCache.cpp new file mode 100644 index 0000000000..e83d6f4eb2 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/PositionCache.cpp @@ -0,0 +1,635 @@ +// Scintilla source code edit control +/** @file PositionCache.cxx + ** Classes for caching layout information. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" + +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "Document.h" +#include "PositionCache.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static inline bool IsControlCharacter(int ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +LineLayout::LineLayout(int maxLineLength_) : + lineStarts(0), + lenLineStarts(0), + lineNumber(-1), + inCache(false), + maxLineLength(-1), + numCharsInLine(0), + validity(llInvalid), + xHighlightGuide(0), + highlightColumn(0), + selStart(0), + selEnd(0), + containsCaret(false), + edgeColumn(0), + chars(0), + styles(0), + styleBitsSet(0), + indicators(0), + positions(0), + hsStart(0), + hsEnd(0), + widthLine(wrapWidthInfinite), + lines(1) { + Resize(maxLineLength_); +} + +LineLayout::~LineLayout() { + Free(); +} + +void LineLayout::Resize(int maxLineLength_) { + if (maxLineLength_ > maxLineLength) { + Free(); + chars = new char[maxLineLength_ + 1]; + styles = new unsigned char[maxLineLength_ + 1]; + indicators = new char[maxLineLength_ + 1]; + // Extra position allocated as sometimes the Windows + // GetTextExtentExPoint API writes an extra element. + positions = new int[maxLineLength_ + 1 + 1]; + maxLineLength = maxLineLength_; + } +} + +void LineLayout::Free() { + delete []chars; + chars = 0; + delete []styles; + styles = 0; + delete []indicators; + indicators = 0; + delete []positions; + positions = 0; + delete []lineStarts; + lineStarts = 0; +} + +void LineLayout::Invalidate(validLevel validity_) { + if (validity > validity_) + validity = validity_; +} + +int LineLayout::LineStart(int line) const { + if (line <= 0) { + return 0; + } else if ((line >= lines) || !lineStarts) { + return numCharsInLine; + } else { + return lineStarts[line]; + } +} + +int LineLayout::LineLastVisible(int line) const { + if (line < 0) { + return 0; + } else if ((line >= lines-1) || !lineStarts) { + int startLine = LineStart(line); + int endLine = numCharsInLine; + while ((endLine > startLine) && IsEOLChar(chars[endLine-1])) { + endLine--; + } + return endLine; + } else { + return lineStarts[line+1]; + } +} + +bool LineLayout::InLine(int offset, int line) const { + return ((offset >= LineStart(line)) && (offset < LineStart(line + 1))) || + ((offset == numCharsInLine) && (line == (lines-1))); +} + +void LineLayout::SetLineStart(int line, int start) { + if ((line >= lenLineStarts) && (line != 0)) { + int newMaxLines = line + 20; + int *newLineStarts = new int[newMaxLines]; + if (!newLineStarts) + return; + for (int i = 0; i < newMaxLines; i++) { + if (i < lenLineStarts) + newLineStarts[i] = lineStarts[i]; + else + newLineStarts[i] = 0; + } + delete []lineStarts; + lineStarts = newLineStarts; + lenLineStarts = newMaxLines; + } + lineStarts[line] = start; +} + +void LineLayout::SetBracesHighlight(Range rangeLine, Position braces[], + char bracesMatchStyle, int xHighlight) { + if (rangeLine.ContainsCharacter(braces[0])) { + int braceOffset = braces[0] - rangeLine.start; + if (braceOffset < numCharsInLine) { + bracePreviousStyles[0] = styles[braceOffset]; + styles[braceOffset] = bracesMatchStyle; + } + } + if (rangeLine.ContainsCharacter(braces[1])) { + int braceOffset = braces[1] - rangeLine.start; + if (braceOffset < numCharsInLine) { + bracePreviousStyles[1] = styles[braceOffset]; + styles[braceOffset] = bracesMatchStyle; + } + } + if ((braces[0] >= rangeLine.start && braces[1] <= rangeLine.end) || + (braces[1] >= rangeLine.start && braces[0] <= rangeLine.end)) { + xHighlightGuide = xHighlight; + } +} + +void LineLayout::RestoreBracesHighlight(Range rangeLine, Position braces[]) { + if (rangeLine.ContainsCharacter(braces[0])) { + int braceOffset = braces[0] - rangeLine.start; + if (braceOffset < numCharsInLine) { + styles[braceOffset] = bracePreviousStyles[0]; + } + } + if (rangeLine.ContainsCharacter(braces[1])) { + int braceOffset = braces[1] - rangeLine.start; + if (braceOffset < numCharsInLine) { + styles[braceOffset] = bracePreviousStyles[1]; + } + } + xHighlightGuide = 0; +} + +int LineLayout::FindBefore(int x, int lower, int upper) const { + do { + int middle = (upper + lower + 1) / 2; // Round high + int posMiddle = positions[middle]; + if (x < posMiddle) { + upper = middle - 1; + } else { + lower = middle; + } + } while (lower < upper); + return lower; +} + +LineLayoutCache::LineLayoutCache() : + level(0), length(0), size(0), cache(0), + allInvalidated(false), styleClock(-1), useCount(0) { + Allocate(0); +} + +LineLayoutCache::~LineLayoutCache() { + Deallocate(); +} + +void LineLayoutCache::Allocate(int length_) { + PLATFORM_ASSERT(cache == NULL); + allInvalidated = false; + length = length_; + size = length; + if (size > 1) { + size = (size / 16 + 1) * 16; + } + if (size > 0) { + cache = new LineLayout * [size]; + } + for (int i = 0; i < size; i++) + cache[i] = 0; +} + +void LineLayoutCache::AllocateForLevel(int linesOnScreen, int linesInDoc) { + PLATFORM_ASSERT(useCount == 0); + int lengthForLevel = 0; + if (level == llcCaret) { + lengthForLevel = 1; + } else if (level == llcPage) { + lengthForLevel = linesOnScreen + 1; + } else if (level == llcDocument) { + lengthForLevel = linesInDoc; + } + if (lengthForLevel > size) { + Deallocate(); + Allocate(lengthForLevel); + } else { + if (lengthForLevel < length) { + for (int i = lengthForLevel; i < length; i++) { + delete cache[i]; + cache[i] = 0; + } + } + length = lengthForLevel; + } + PLATFORM_ASSERT(length == lengthForLevel); + PLATFORM_ASSERT(cache != NULL || length == 0); +} + +void LineLayoutCache::Deallocate() { + PLATFORM_ASSERT(useCount == 0); + for (int i = 0; i < length; i++) + delete cache[i]; + delete []cache; + cache = 0; + length = 0; + size = 0; +} + +void LineLayoutCache::Invalidate(LineLayout::validLevel validity_) { + if (cache && !allInvalidated) { + for (int i = 0; i < length; i++) { + if (cache[i]) { + cache[i]->Invalidate(validity_); + } + } + if (validity_ == LineLayout::llInvalid) { + allInvalidated = true; + } + } +} + +void LineLayoutCache::SetLevel(int level_) { + allInvalidated = false; + if ((level_ != -1) && (level != level_)) { + level = level_; + Deallocate(); + } +} + +LineLayout *LineLayoutCache::Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_, + int linesOnScreen, int linesInDoc) { + AllocateForLevel(linesOnScreen, linesInDoc); + if (styleClock != styleClock_) { + Invalidate(LineLayout::llCheckTextAndStyle); + styleClock = styleClock_; + } + allInvalidated = false; + int pos = -1; + LineLayout *ret = 0; + if (level == llcCaret) { + pos = 0; + } else if (level == llcPage) { + if (lineNumber == lineCaret) { + pos = 0; + } else if (length > 1) { + pos = 1 + (lineNumber % (length - 1)); + } + } else if (level == llcDocument) { + pos = lineNumber; + } + if (pos >= 0) { + PLATFORM_ASSERT(useCount == 0); + if (cache && (pos < length)) { + if (cache[pos]) { + if ((cache[pos]->lineNumber != lineNumber) || + (cache[pos]->maxLineLength < maxChars)) { + delete cache[pos]; + cache[pos] = 0; + } + } + if (!cache[pos]) { + cache[pos] = new LineLayout(maxChars); + } + if (cache[pos]) { + cache[pos]->lineNumber = lineNumber; + cache[pos]->inCache = true; + ret = cache[pos]; + useCount++; + } + } + } + + if (!ret) { + ret = new LineLayout(maxChars); + ret->lineNumber = lineNumber; + } + + return ret; +} + +void LineLayoutCache::Dispose(LineLayout *ll) { + allInvalidated = false; + if (ll) { + if (!ll->inCache) { + delete ll; + } else { + useCount--; + } + } +} + +void BreakFinder::Insert(int val) { + // Expand if needed + if (saeLen >= saeSize) { + saeSize *= 2; + int *selAndEdgeNew = new int[saeSize]; + for (unsigned int j = 0; j= nextBreak) { + for (unsigned int j = 0; jj; k--) { + selAndEdge[k] = selAndEdge[k-1]; + } + saeLen++; + selAndEdge[j] = val; + return; + } + } + // Not less than any so append + selAndEdge[saeLen++] = val; + } +} + +extern bool BadUTF(const char *s, int len, int &trailBytes); + +static int NextBadU(const char *s, int p, int len, int &trailBytes) { + while (p < len) { + p++; + if (BadUTF(s + p, len - p, trailBytes)) + return p; + } + return -1; +} + +BreakFinder::BreakFinder(LineLayout *ll_, int lineStart_, int lineEnd_, int posLineStart_, bool utf8_, int xStart) : + ll(ll_), + lineStart(lineStart_), + lineEnd(lineEnd_), + posLineStart(posLineStart_), + utf8(utf8_), + nextBreak(lineStart_), + saeSize(0), + saeLen(0), + saeCurrentPos(0), + saeNext(0), + subBreak(-1) { + saeSize = 8; + selAndEdge = new int[saeSize]; + for (unsigned int j=0; j < saeSize; j++) { + selAndEdge[j] = 0; + } + + // Search for first visible break + // First find the first visible character + nextBreak = ll->FindBefore(xStart, lineStart, lineEnd); + // Now back to a style break + while ((nextBreak > lineStart) && (ll->styles[nextBreak] == ll->styles[nextBreak - 1])) { + nextBreak--; + } + + if (ll->selStart != ll->selEnd) { + Insert(ll->selStart - posLineStart - 1); + Insert(ll->selEnd - posLineStart - 1); + } + + Insert(ll->edgeColumn - 1); + Insert(lineEnd - 1); + + if (utf8) { + int trailBytes=0; + for (int pos = -1;;) { + pos = NextBadU(ll->chars, pos, lineEnd, trailBytes); + if (pos < 0) + break; + Insert(pos-1); + Insert(pos); + } + } + saeNext = (saeLen > 0) ? selAndEdge[0] : -1; +} + +BreakFinder::~BreakFinder() { + delete []selAndEdge; +} + +int BreakFinder::First() { + return nextBreak; +} + +int BreakFinder::Next() { + if (subBreak == -1) { + int prev = nextBreak; + while (nextBreak < lineEnd) { + if ((ll->styles[nextBreak] != ll->styles[nextBreak + 1]) || + (nextBreak == saeNext) || + IsControlCharacter(ll->chars[nextBreak]) || IsControlCharacter(ll->chars[nextBreak + 1])) { + if (nextBreak == saeNext) { + saeCurrentPos++; + saeNext = (saeLen > saeCurrentPos) ? selAndEdge[saeCurrentPos] : -1; + } + nextBreak++; + if ((nextBreak - prev) < lengthStartSubdivision) { + return nextBreak; + } + break; + } + nextBreak++; + } + if ((nextBreak - prev) < lengthStartSubdivision) { + return nextBreak; + } + subBreak = prev; + } + // Splitting up a long run from prev to nextBreak in lots of approximately lengthEachSubdivision. + // For very long runs add extra breaks after spaces or if no spaces before low punctuation. + if ((nextBreak - subBreak) <= lengthEachSubdivision) { + subBreak = -1; + return nextBreak; + } else { + int lastGoodBreak = -1; + int lastOKBreak = -1; + int j; + for (j = subBreak + 1; j <= nextBreak; j++) { + if (IsSpaceOrTab(ll->chars[j - 1]) && !IsSpaceOrTab(ll->chars[j])) { + lastGoodBreak = j; + } + if (ll->chars[j] < 'A') { + lastOKBreak = j; + } + if (((j - subBreak) >= lengthEachSubdivision) && ((lastGoodBreak >= 0) || (lastOKBreak >= 0))) { + break; + } + } + if (lastGoodBreak >= 0) { + subBreak = lastGoodBreak; + } else if (lastOKBreak >= 0) { + subBreak = lastOKBreak; + } else { + subBreak = nextBreak; + } + if (subBreak >= nextBreak) { + subBreak = -1; + return nextBreak; + } else { + return subBreak; + } + } +} + +PositionCacheEntry::PositionCacheEntry() : + styleNumber(0), len(0), clock(0), positions(0) { +} + +void PositionCacheEntry::Set(unsigned int styleNumber_, const char *s_, + unsigned int len_, int *positions_, unsigned int clock_) { + Clear(); + styleNumber = styleNumber_; + len = len_; + clock = clock_; + if (s_ && positions_) { + positions = new short[len + (len + 1) / 2]; + for (unsigned int i=0;i(positions_[i]); + } + memcpy(reinterpret_cast(positions + len), s_, len); + } +} + +PositionCacheEntry::~PositionCacheEntry() { + Clear(); +} + +void PositionCacheEntry::Clear() { + delete []positions; + positions = 0; + styleNumber = 0; + len = 0; + clock = 0; +} + +bool PositionCacheEntry::Retrieve(unsigned int styleNumber_, const char *s_, + unsigned int len_, int *positions_) const { + if ((styleNumber == styleNumber_) && (len == len_) && + (memcmp(reinterpret_cast(positions + len), s_, len)== 0)) { + for (unsigned int i=0;i other.clock; +} + +void PositionCacheEntry::ResetClock() { + if (clock > 0) { + clock = 1; + } +} + +PositionCache::PositionCache() { + size = 0x400; + clock = 1; + pces = new PositionCacheEntry[size]; + allClear = true; +} + +PositionCache::~PositionCache() { + Clear(); + delete []pces; +} + +void PositionCache::Clear() { + if (!allClear) { + for (size_t i=0;i 0) && (len < 30)) { + // Only store short strings in the cache so it doesn't churn with + // long comments with only a single comment. + + // Two way associative: try two probe positions. + int hashValue = PositionCacheEntry::Hash(styleNumber, s, len); + probe = hashValue % size; + if (pces[probe].Retrieve(styleNumber, s, len, positions)) { + return; + } + int probe2 = (hashValue * 37) % size; + if (pces[probe2].Retrieve(styleNumber, s, len, positions)) { + return; + } + // Not found. Choose the oldest of the two slots to replace + if (pces[probe].NewerThan(pces[probe2])) { + probe = probe2; + } + } + surface->MeasureWidths(vstyle.styles[styleNumber].font, s, len, positions); + if (probe >= 0) { + clock++; + if (clock > 60000) { + // Since there are only 16 bits for the clock, wrap it round and + // reset all cache entries so none get stuck with a high clock. + for (size_t i=0;i +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef POSITIONCACHE_H +#define POSITIONCACHE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +static inline bool IsEOLChar(char ch) { + return (ch == '\r') || (ch == '\n'); +} + +/** + */ +class LineLayout { +private: + friend class LineLayoutCache; + int *lineStarts; + int lenLineStarts; + /// Drawing is only performed for @a maxLineLength characters on each line. + int lineNumber; + bool inCache; +public: + enum { wrapWidthInfinite = 0x7ffffff }; + int maxLineLength; + int numCharsInLine; + enum validLevel { llInvalid, llCheckTextAndStyle, llPositions, llLines } validity; + int xHighlightGuide; + bool highlightColumn; + int selStart; + int selEnd; + bool containsCaret; + int edgeColumn; + char *chars; + unsigned char *styles; + int styleBitsSet; + char *indicators; + int *positions; + char bracePreviousStyles[2]; + + // Hotspot support + int hsStart; + int hsEnd; + + // Wrapped line support + int widthLine; + int lines; + + LineLayout(int maxLineLength_); + virtual ~LineLayout(); + void Resize(int maxLineLength_); + void Free(); + void Invalidate(validLevel validity_); + int LineStart(int line) const; + int LineLastVisible(int line) const; + bool InLine(int offset, int line) const; + void SetLineStart(int line, int start); + void SetBracesHighlight(Range rangeLine, Position braces[], + char bracesMatchStyle, int xHighlight); + void RestoreBracesHighlight(Range rangeLine, Position braces[]); + int FindBefore(int x, int lower, int upper) const; +}; + +/** + */ +class LineLayoutCache { + int level; + int length; + int size; + LineLayout **cache; + bool allInvalidated; + int styleClock; + int useCount; + void Allocate(int length_); + void AllocateForLevel(int linesOnScreen, int linesInDoc); +public: + LineLayoutCache(); + virtual ~LineLayoutCache(); + void Deallocate(); + enum { + llcNone=SC_CACHE_NONE, + llcCaret=SC_CACHE_CARET, + llcPage=SC_CACHE_PAGE, + llcDocument=SC_CACHE_DOCUMENT + }; + void Invalidate(LineLayout::validLevel validity_); + void SetLevel(int level_); + int GetLevel() { return level; } + LineLayout *Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_, + int linesOnScreen, int linesInDoc); + void Dispose(LineLayout *ll); +}; + +class PositionCacheEntry { + unsigned int styleNumber:8; + unsigned int len:8; + unsigned int clock:16; + short *positions; +public: + PositionCacheEntry(); + ~PositionCacheEntry(); + void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, int *positions_, unsigned int clock); + void Clear(); + bool Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, int *positions_) const; + static int Hash(unsigned int styleNumber, const char *s, unsigned int len); + bool NewerThan(const PositionCacheEntry &other); + void ResetClock(); +}; + +// Class to break a line of text into shorter runs at sensible places. +class BreakFinder { + // If a whole run is longer than lengthStartSubdivision then subdivide + // into smaller runs at spaces or punctuation. + enum { lengthStartSubdivision = 300 }; + // Try to make each subdivided run lengthEachSubdivision or shorter. + enum { lengthEachSubdivision = 100 }; + LineLayout *ll; + int lineStart; + int lineEnd; + int posLineStart; + bool utf8; + int nextBreak; + int *selAndEdge; + unsigned int saeSize; + unsigned int saeLen; + unsigned int saeCurrentPos; + int saeNext; + int subBreak; + void Insert(int val); +public: + BreakFinder(LineLayout *ll_, int lineStart_, int lineEnd_, int posLineStart_, bool utf8_, int xStart); + ~BreakFinder(); + int First(); + int Next(); +}; + +class PositionCache { + PositionCacheEntry *pces; + size_t size; + unsigned int clock; + bool allClear; +public: + PositionCache(); + ~PositionCache(); + void Clear(); + void SetSize(size_t size_); + int GetSize() { return size; } + void MeasureWidths(Surface *surface, ViewStyle &vstyle, unsigned int styleNumber, + const char *s, unsigned int len, int *positions); +}; + +inline bool IsSpaceOrTab(int ch) { + return ch == ' ' || ch == '\t'; +} + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/PropSet.cpp b/harbour/contrib/hbide/qscintilla/PropSet.cpp new file mode 100644 index 0000000000..daaeb0a85d --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/PropSet.cpp @@ -0,0 +1,755 @@ +// SciTE - Scintilla based Text Editor +/** @file PropSet.cxx + ** A Java style properties file module. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +// Maintain a dictionary of properties + +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +// The comparison and case changing functions here assume ASCII +// or extended ASCII such as the normal Windows code page. + +static inline char MakeUpperCase(char ch) { + if (ch < 'a' || ch > 'z') + return ch; + else + return static_cast(ch - 'a' + 'A'); +} + +static inline bool IsLetter(char ch) { + return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')); +} + +inline bool IsASpace(unsigned int ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +int CompareCaseInsensitive(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + } + // Either *a or *b is nul + return *a - *b; +} + +int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { + while (*a && *b && len) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + len--; + } + if (len == 0) + return 0; + else + // Either *a or *b is nul + return *a - *b; +} + +bool EqualCaseInsensitive(const char *a, const char *b) { + return 0 == CompareCaseInsensitive(a, b); +} + +// Since the CaseInsensitive functions declared in SString +// are implemented here, I will for now put the non-inline +// implementations of the SString members here as well, so +// that I can quickly see what effect this has. + +SString::SString(int i) : sizeGrowth(sizeGrowthDefault) { + char number[32]; + sprintf(number, "%0d", i); + s = StringAllocate(number); + sSize = sLen = (s) ? strlen(s) : 0; +} + +SString::SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) { + char number[32]; + sprintf(number, "%.*f", precision, d); + s = StringAllocate(number); + sSize = sLen = (s) ? strlen(s) : 0; +} + +bool SString::grow(lenpos_t lenNew) { + while (sizeGrowth * 6 < lenNew) { + sizeGrowth *= 2; + } + char *sNew = new char[lenNew + sizeGrowth + 1]; + if (sNew) { + if (s) { + memcpy(sNew, s, sLen); + delete []s; + } + s = sNew; + s[sLen] = '\0'; + sSize = lenNew + sizeGrowth; + } + return sNew != 0; +} + +SString &SString::assign(const char *sOther, lenpos_t sSize_) { + if (!sOther) { + sSize_ = 0; + } else if (sSize_ == measure_length) { + sSize_ = strlen(sOther); + } + if (sSize > 0 && sSize_ <= sSize) { // Does not allocate new buffer if the current is big enough + if (s && sSize_) { + memcpy(s, sOther, sSize_); + } + s[sSize_] = '\0'; + sLen = sSize_; + } else { + delete []s; + s = StringAllocate(sOther, sSize_); + if (s) { + sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow + sLen = sSize_; + } else { + sSize = sLen = 0; + } + } + return *this; +} + +bool SString::operator==(const SString &sOther) const { + if ((s == 0) && (sOther.s == 0)) + return true; + if ((s == 0) || (sOther.s == 0)) + return false; + return strcmp(s, sOther.s) == 0; +} + +bool SString::operator==(const char *sOther) const { + if ((s == 0) && (sOther == 0)) + return true; + if ((s == 0) || (sOther == 0)) + return false; + return strcmp(s, sOther) == 0; +} + +SString SString::substr(lenpos_t subPos, lenpos_t subLen) const { + if (subPos >= sLen) { + return SString(); // return a null string if start index is out of bounds + } + if ((subLen == measure_length) || (subPos + subLen > sLen)) { + subLen = sLen - subPos; // can't substr past end of source string + } + return SString(s, subPos, subPos + subLen); +} + +SString &SString::lowercase(lenpos_t subPos, lenpos_t subLen) { + if ((subLen == measure_length) || (subPos + subLen > sLen)) { + subLen = sLen - subPos; // don't apply past end of string + } + for (lenpos_t i = subPos; i < subPos + subLen; i++) { + if (s[i] < 'A' || s[i] > 'Z') + continue; + else + s[i] = static_cast(s[i] - 'A' + 'a'); + } + return *this; +} + +SString &SString::uppercase(lenpos_t subPos, lenpos_t subLen) { + if ((subLen == measure_length) || (subPos + subLen > sLen)) { + subLen = sLen - subPos; // don't apply past end of string + } + for (lenpos_t i = subPos; i < subPos + subLen; i++) { + if (s[i] < 'a' || s[i] > 'z') + continue; + else + s[i] = static_cast(s[i] - 'a' + 'A'); + } + return *this; +} + +SString &SString::append(const char *sOther, lenpos_t sLenOther, char sep) { + if (!sOther) { + return *this; + } + if (sLenOther == measure_length) { + sLenOther = strlen(sOther); + } + int lenSep = 0; + if (sLen && sep) { // Only add a separator if not empty + lenSep = 1; + } + lenpos_t lenNew = sLen + sLenOther + lenSep; + // Conservative about growing the buffer: don't do it, unless really needed + if ((lenNew < sSize) || (grow(lenNew))) { + if (lenSep) { + s[sLen] = sep; + sLen++; + } + memcpy(&s[sLen], sOther, sLenOther); + sLen += sLenOther; + s[sLen] = '\0'; + } + return *this; +} + +SString &SString::insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther) { + if (!sOther || pos > sLen) { + return *this; + } + if (sLenOther == measure_length) { + sLenOther = strlen(sOther); + } + lenpos_t lenNew = sLen + sLenOther; + // Conservative about growing the buffer: don't do it, unless really needed + if ((lenNew < sSize) || grow(lenNew)) { + lenpos_t moveChars = sLen - pos + 1; + for (lenpos_t i = moveChars; i > 0; i--) { + s[pos + sLenOther + i - 1] = s[pos + i - 1]; + } + memcpy(s + pos, sOther, sLenOther); + sLen = lenNew; + } + return *this; +} + +/** + * Remove @a len characters from the @a pos position, included. + * Characters at pos + len and beyond replace characters at pos. + * If @a len is 0, or greater than the length of the string + * starting at @a pos, the string is just truncated at @a pos. + */ +void SString::remove(lenpos_t pos, lenpos_t len) { + if (pos >= sLen) { + return; + } + if (len < 1 || pos + len >= sLen) { + s[pos] = '\0'; + sLen = pos; + } else { + for (lenpos_t i = pos; i < sLen - len + 1; i++) { + s[i] = s[i+len]; + } + sLen -= len; + } +} + +bool SString::startswith(const char *prefix) { + lenpos_t lenPrefix = strlen(prefix); + if (lenPrefix > sLen) { + return false; + } + return strncmp(s, prefix, lenPrefix) == 0; +} + +bool SString::endswith(const char *suffix) { + lenpos_t lenSuffix = strlen(suffix); + if (lenSuffix > sLen) { + return false; + } + return strncmp(s + sLen - lenSuffix, suffix, lenSuffix) == 0; +} + +int SString::search(const char *sFind, lenpos_t start) const { + if (start < sLen) { + const char *sFound = strstr(s + start, sFind); + if (sFound) { + return sFound - s; + } + } + return -1; +} + +int SString::substitute(char chFind, char chReplace) { + int c = 0; + char *t = s; + while (t) { + t = strchr(t, chFind); + if (t) { + *t = chReplace; + t++; + c++; + } + } + return c; +} + +int SString::substitute(const char *sFind, const char *sReplace) { + int c = 0; + lenpos_t lenFind = strlen(sFind); + lenpos_t lenReplace = strlen(sReplace); + int posFound = search(sFind); + while (posFound >= 0) { + remove(posFound, lenFind); + insert(posFound, sReplace, lenReplace); + posFound = search(sFind, posFound + lenReplace); + c++; + } + return c; +} + +char *SContainer::StringAllocate(lenpos_t len) { + if (len != measure_length) { + return new char[len + 1]; + } else { + return 0; + } +} + +char *SContainer::StringAllocate(const char *s, lenpos_t len) { + if (s == 0) { + return 0; + } + if (len == measure_length) { + len = strlen(s); + } + char *sNew = new char[len + 1]; + if (sNew) { + memcpy(sNew, s, len); + sNew[len] = '\0'; + } + return sNew; +} + +// End SString functions + +PropSet::PropSet() { + superPS = 0; + for (int root = 0; root < hashRoots; root++) + props[root] = 0; +} + +PropSet::~PropSet() { + superPS = 0; + Clear(); +} + +void PropSet::Set(const char *key, const char *val, int lenKey, int lenVal) { + if (!*key) // Empty keys are not supported + return; + if (lenKey == -1) + lenKey = static_cast(strlen(key)); + if (lenVal == -1) + lenVal = static_cast(strlen(val)); + unsigned int hash = HashString(key, lenKey); + for (Property *p = props[hash % hashRoots]; p; p = p->next) { + if ((hash == p->hash) && + ((strlen(p->key) == static_cast(lenKey)) && + (0 == strncmp(p->key, key, lenKey)))) { + // Replace current value + delete [](p->val); + p->val = StringDup(val, lenVal); + return; + } + } + // Not found + Property *pNew = new Property; + if (pNew) { + pNew->hash = hash; + pNew->key = StringDup(key, lenKey); + pNew->val = StringDup(val, lenVal); + pNew->next = props[hash % hashRoots]; + props[hash % hashRoots] = pNew; + } +} + +void PropSet::Set(const char *keyVal) { + while (IsASpace(*keyVal)) + keyVal++; + const char *endVal = keyVal; + while (*endVal && (*endVal != '\n')) + endVal++; + const char *eqAt = strchr(keyVal, '='); + if (eqAt) { + Set(keyVal, eqAt + 1, eqAt-keyVal, endVal - eqAt - 1); + } else if (*keyVal) { // No '=' so assume '=1' + Set(keyVal, "1", endVal-keyVal, 1); + } +} + +void PropSet::Unset(const char *key, int lenKey) { + if (!*key) // Empty keys are not supported + return; + if (lenKey == -1) + lenKey = static_cast(strlen(key)); + unsigned int hash = HashString(key, lenKey); + Property *pPrev = NULL; + for (Property *p = props[hash % hashRoots]; p; p = p->next) { + if ((hash == p->hash) && + ((strlen(p->key) == static_cast(lenKey)) && + (0 == strncmp(p->key, key, lenKey)))) { + if (pPrev) + pPrev->next = p->next; + else + props[hash % hashRoots] = p->next; + if (p == enumnext) + enumnext = p->next; // Not that anyone should mix enum and Set / Unset. + delete [](p->key); + delete [](p->val); + delete p; + return; + } else { + pPrev = p; + } + } +} + +void PropSet::SetMultiple(const char *s) { + const char *eol = strchr(s, '\n'); + while (eol) { + Set(s); + s = eol + 1; + eol = strchr(s, '\n'); + } + Set(s); +} + +SString PropSet::Get(const char *key) const { + unsigned int hash = HashString(key, strlen(key)); + for (Property *p = props[hash % hashRoots]; p; p = p->next) { + if ((hash == p->hash) && (0 == strcmp(p->key, key))) { + return p->val; + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->Get(key); + } else { + return ""; + } +} + +// There is some inconsistency between GetExpanded("foo") and Expand("$(foo)"). +// A solution is to keep a stack of variables that have been expanded, so that +// recursive expansions can be skipped. For now I'll just use the C++ stack +// for that, through a recursive function and a simple chain of pointers. + +struct VarChain { + VarChain(const char*var_=NULL, const VarChain *link_=NULL): var(var_), link(link_) {} + + bool contains(const char *testVar) const { + return (var && (0 == strcmp(var, testVar))) + || (link && link->contains(testVar)); + } + + const char *var; + const VarChain *link; +}; + +static int ExpandAllInPlace(const PropSet &props, SString &withVars, int maxExpands, const VarChain &blankVars = VarChain()) { + int varStart = withVars.search("$("); + while ((varStart >= 0) && (maxExpands > 0)) { + int varEnd = withVars.search(")", varStart+2); + if (varEnd < 0) { + break; + } + + // For consistency, when we see '$(ab$(cde))', expand the inner variable first, + // regardless whether there is actually a degenerate variable named 'ab$(cde'. + int innerVarStart = withVars.search("$(", varStart+2); + while ((innerVarStart > varStart) && (innerVarStart < varEnd)) { + varStart = innerVarStart; + innerVarStart = withVars.search("$(", varStart+2); + } + + SString var(withVars.c_str(), varStart + 2, varEnd); + SString val = props.Get(var.c_str()); + + if (blankVars.contains(var.c_str())) { + val.clear(); // treat blankVar as an empty string (e.g. to block self-reference) + } + + if (--maxExpands >= 0) { + maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars)); + } + + withVars.remove(varStart, varEnd-varStart+1); + withVars.insert(varStart, val.c_str(), val.length()); + + varStart = withVars.search("$("); + } + + return maxExpands; +} + +SString PropSet::GetExpanded(const char *key) const { + SString val = Get(key); + ExpandAllInPlace(*this, val, 100, VarChain(key)); + return val; +} + +SString PropSet::Expand(const char *withVars, int maxExpands) const { + SString val = withVars; + ExpandAllInPlace(*this, val, maxExpands); + return val; +} + +int PropSet::GetInt(const char *key, int defaultValue) const { + SString val = GetExpanded(key); + if (val.length()) + return val.value(); + return defaultValue; +} + +bool isprefix(const char *target, const char *prefix) { + while (*target && *prefix) { + if (*target != *prefix) + return false; + target++; + prefix++; + } + if (*prefix) + return false; + else + return true; +} + +void PropSet::Clear() { + for (int root = 0; root < hashRoots; root++) { + Property *p = props[root]; + while (p) { + Property *pNext = p->next; + p->hash = 0; + delete []p->key; + p->key = 0; + delete []p->val; + p->val = 0; + delete p; + p = pNext; + } + props[root] = 0; + } +} + +char *PropSet::ToString() const { + size_t len=0; + for (int r = 0; r < hashRoots; r++) { + for (Property *p = props[r]; p; p = p->next) { + len += strlen(p->key) + 1; + len += strlen(p->val) + 1; + } + } + if (len == 0) + len = 1; // Return as empty string + char *ret = new char [len]; + if (ret) { + char *w = ret; + for (int root = 0; root < hashRoots; root++) { + for (Property *p = props[root]; p; p = p->next) { + strcpy(w, p->key); + w += strlen(p->key); + *w++ = '='; + strcpy(w, p->val); + w += strlen(p->val); + *w++ = '\n'; + } + } + ret[len-1] = '\0'; + } + return ret; +} + +/** + * Creates an array that points into each word in the string and puts \0 terminators + * after each word. + */ +static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) { + int prev = '\n'; + int words = 0; + // For rapid determination of whether a character is a separator, build + // a look up table. + bool wordSeparator[256]; + for (int i=0;i<256; i++) { + wordSeparator[i] = false; + } + wordSeparator[(int) '\r'] = true; + wordSeparator[(int) '\n'] = true; + if (!onlyLineEnds) { + wordSeparator[(int) ' '] = true; + wordSeparator[(int) '\t'] = true; + } + for (int j = 0; wordlist[j]; j++) { + int curr = static_cast(wordlist[j]); + if (!wordSeparator[curr] && wordSeparator[prev]) + words++; + prev = curr; + } + char **keywords = new char *[words + 1]; + if (keywords) { + words = 0; + prev = '\0'; + size_t slen = strlen(wordlist); + for (size_t k = 0; k < slen; k++) { + if (!wordSeparator[static_cast(wordlist[k])]) { + if (!prev) { + keywords[words] = &wordlist[k]; + words++; + } + } else { + wordlist[k] = '\0'; + } + prev = wordlist[k]; + } + keywords[words] = &wordlist[slen]; + *len = words; + } else { + *len = 0; + } + return keywords; +} + +void WordList::Clear() { + if (words) { + delete []list; + delete []words; + } + words = 0; + list = 0; + len = 0; + sorted = false; +} + +void WordList::Set(const char *s) { + list = StringDup(s); + sorted = false; + words = ArrayFromWordList(list, &len, onlyLineEnds); +} + +extern "C" int cmpString(const void *a1, const void *a2) { + // Can't work out the correct incantation to use modern casts here + return strcmp(*(char**)(a1), *(char**)(a2)); +} + +static void SortWordList(char **words, unsigned int len) { + qsort(reinterpret_cast(words), len, sizeof(*words), + cmpString); +} + +bool WordList::InList(const char *s) { + if (0 == words) + return false; + if (!sorted) { + sorted = true; + SortWordList(words, len); + for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) + starts[k] = -1; + for (int l = len - 1; l >= 0; l--) { + unsigned char indexChar = words[l][0]; + starts[indexChar] = l; + } + } + unsigned char firstChar = s[0]; + int j = starts[firstChar]; + if (j >= 0) { + while ((unsigned char)words[j][0] == firstChar) { + if (s[1] == words[j][1]) { + const char *a = words[j] + 1; + const char *b = s + 1; + while (*a && *a == *b) { + a++; + b++; + } + if (!*a && !*b) + return true; + } + j++; + } + } + j = starts[(int) '^']; + if (j >= 0) { + while (words[j][0] == '^') { + const char *a = words[j] + 1; + const char *b = s; + while (*a && *a == *b) { + a++; + b++; + } + if (!*a) + return true; + j++; + } + } + return false; +} + +/** similar to InList, but word s can be a substring of keyword. + * eg. the keyword define is defined as def~ine. This means the word must start + * with def to be a keyword, but also defi, defin and define are valid. + * The marker is ~ in this case. + */ +bool WordList::InListAbbreviated(const char *s, const char marker) { + if (0 == words) + return false; + if (!sorted) { + sorted = true; + SortWordList(words, len); + for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) + starts[k] = -1; + for (int l = len - 1; l >= 0; l--) { + unsigned char indexChar = words[l][0]; + starts[indexChar] = l; + } + } + unsigned char firstChar = s[0]; + int j = starts[firstChar]; + if (j >= 0) { + while (words[j][0] == firstChar) { + bool isSubword = false; + int start = 1; + if (words[j][1] == marker) { + isSubword = true; + start++; + } + if (s[1] == words[j][start]) { + const char *a = words[j] + start; + const char *b = s + 1; + while (*a && *a == *b) { + a++; + if (*a == marker) { + isSubword = true; + a++; + } + b++; + } + if ((!*a || isSubword) && !*b) + return true; + } + j++; + } + } + j = starts[(int) '^']; + if (j >= 0) { + while (words[j][0] == '^') { + const char *a = words[j] + 1; + const char *b = s; + while (*a && *a == *b) { + a++; + b++; + } + if (!*a) + return true; + j++; + } + } + return false; +} diff --git a/harbour/contrib/hbide/qscintilla/PropSet.h b/harbour/contrib/hbide/qscintilla/PropSet.h new file mode 100644 index 0000000000..91bc7072ba --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/PropSet.h @@ -0,0 +1,104 @@ +// Scintilla source code edit control +/** @file PropSet.h + ** A Java style properties file module. + **/ +// Copyright 1998-2002 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PROPSET_H +#define PROPSET_H +#include "SString.h" + +bool EqualCaseInsensitive(const char *a, const char *b); + +bool isprefix(const char *target, const char *prefix); + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +struct Property { + unsigned int hash; + char *key; + char *val; + Property *next; + Property() : hash(0), key(0), val(0), next(0) {} +}; + +/** + */ +class PropSet { +protected: + enum { hashRoots=31 }; + Property *props[hashRoots]; + Property *enumnext; + int enumhash; + static unsigned int HashString(const char *s, size_t len) { + unsigned int ret = 0; + while (len--) { + ret <<= 4; + ret ^= *s; + s++; + } + return ret; + } + +public: + PropSet *superPS; + PropSet(); + ~PropSet(); + void Set(const char *key, const char *val, int lenKey=-1, int lenVal=-1); + void Set(const char *keyVal); + void Unset(const char *key, int lenKey=-1); + void SetMultiple(const char *s); + SString Get(const char *key) const; + SString GetExpanded(const char *key) const; + SString Expand(const char *withVars, int maxExpands=100) const; + int GetInt(const char *key, int defaultValue=0) const; + void Clear(); + char *ToString() const; // Caller must delete[] the return value + +private: + // copy-value semantics not implemented + PropSet(const PropSet ©); + void operator=(const PropSet &assign); +}; + +/** + */ +class WordList { +public: + // Each word contains at least one character - a empty word acts as sentinel at the end. + char **words; + char *list; + int len; + bool onlyLineEnds; ///< Delimited by any white space or only line ends + bool sorted; + int starts[256]; + WordList(bool onlyLineEnds_ = false) : + words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_), + sorted(false) + {} + ~WordList() { Clear(); } + operator bool() { return len ? true : false; } + void Clear(); + void Set(const char *s); + bool InList(const char *s); + bool InListAbbreviated(const char *s, const char marker); +}; + +inline bool IsAlphabetic(unsigned int ch) { + return ((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')); +} + +#ifdef SCI_NAMESPACE +} +#endif + +#ifdef _MSC_VER +// Visual C++ doesn't like the private copy idiom for disabling +// the default copy constructor and operator=, but it's fine. +#pragma warning(disable: 4511 4512) +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/RESearch.cpp b/harbour/contrib/hbide/qscintilla/RESearch.cpp new file mode 100644 index 0000000000..44f1de91c1 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/RESearch.cpp @@ -0,0 +1,983 @@ +// Scintilla source code edit control +/** @file RESearch.cxx + ** Regular expression search library. + **/ + +/* + * regex - Regular expression pattern matching and replacement + * + * By: Ozan S. Yigit (oz) + * Dept. of Computer Science + * York University + * + * Original code available from http://www.cs.yorku.ca/~oz/ + * Translation to C++ by Neil Hodgson neilh@scintilla.org + * Removed all use of register. + * Converted to modern function prototypes. + * Put all global/static variables into an object so this code can be + * used from multiple threads, etc. + * Some extensions by Philippe Lhoste PhiLho(a)GMX.net + * + * These routines are the PUBLIC DOMAIN equivalents of regex + * routines as found in 4.nBSD UN*X, with minor extensions. + * + * These routines are derived from various implementations found + * in software tools books, and Conroy's grep. They are NOT derived + * from licensed/restricted software. + * For more interesting/academic/complicated implementations, + * see Henry Spencer's regexp routines, or GNU Emacs pattern + * matching module. + * + * Modification history removed. + * + * Interfaces: + * RESearch::Compile: compile a regular expression into a NFA. + * + * const char *RESearch::Compile(const char *pattern, int length, + * bool caseSensitive, bool posix) + * + * Returns a short error string if they fail. + * + * RESearch::Execute: execute the NFA to match a pattern. + * + * int RESearch::Execute(characterIndexer &ci, int lp, int endp) + * + * RESearch::Substitute: substitute the matched portions in a new string. + * + * int RESearch::Substitute(CharacterIndexer &ci, char *src, char *dst) + * + * re_fail: failure routine for RESearch::Execute. (no longer used) + * + * void re_fail(char *msg, char op) + * + * Regular Expressions: + * + * [1] char matches itself, unless it is a special + * character (metachar): . \ [ ] * + ^ $ + * and ( ) if posix option. + * + * [2] . matches any character. + * + * [3] \ matches the character following it, except: + * - \a, \b, \f, \n, \r, \t, \v match the corresponding C + * escape char, respectively BEL, BS, FF, LF, CR, TAB and VT; + * Note that \r and \n are never matched because Scintilla + * regex searches are made line per line + * (stripped of end-of-line chars). + * - if not in posix mode, when followed by a + * left or right round bracket (see [7]); + * - when followed by a digit 1 to 9 (see [8]); + * - when followed by a left or right angle bracket + * (see [9]); + * - when followed by d, D, s, S, w or W (see [10]); + * - when followed by x and two hexa digits (see [11]. + * Backslash is used as an escape character for all + * other meta-characters, and itself. + * + * [4] [set] matches one of the characters in the set. + * If the first character in the set is "^", + * it matches the characters NOT in the set, i.e. + * complements the set. A shorthand S-E (start dash end) + * is used to specify a set of characters S up to + * E, inclusive. S and E must be characters, otherwise + * the dash is taken literally (eg. in expression [\d-a]). + * The special characters "]" and "-" have no special + * meaning if they appear as the first chars in the set. + * To include both, put - first: [-]A-Z] + * (or just backslash them). + * examples: match: + * + * [-]|] matches these 3 chars, + * + * []-|] matches from ] to | chars + * + * [a-z] any lowercase alpha + * + * [^-]] any char except - and ] + * + * [^A-Z] any char except uppercase + * alpha + * + * [a-zA-Z] any alpha + * + * [5] * any regular expression form [1] to [4] + * (except [7], [8] and [9] forms of [3]), + * followed by closure char (*) + * matches zero or more matches of that form. + * + * [6] + same as [5], except it matches one or more. + * Both [5] and [6] are greedy (they match as much as possible). + * + * [7] a regular expression in the form [1] to [12], enclosed + * as \(form\) (or (form) with posix flag) matches what + * form matches. The enclosure creates a set of tags, + * used for [8] and for pattern substitution. + * The tagged forms are numbered starting from 1. + * + * [8] a \ followed by a digit 1 to 9 matches whatever a + * previously tagged regular expression ([7]) matched. + * + * [9] \< a regular expression starting with a \< construct + * \> and/or ending with a \> construct, restricts the + * pattern matching to the beginning of a word, and/or + * the end of a word. A word is defined to be a character + * string beginning and/or ending with the characters + * A-Z a-z 0-9 and _. Scintilla extends this definition + * by user setting. The word must also be preceded and/or + * followed by any character outside those mentioned. + * + * [10] \l a backslash followed by d, D, s, S, w or W, + * becomes a character class (both inside and + * outside sets []). + * d: decimal digits + * D: any char except decimal digits + * s: whitespace (space, \t \n \r \f \v) + * S: any char except whitespace (see above) + * w: alphanumeric & underscore (changed by user setting) + * W: any char except alphanumeric & underscore (see above) + * + * [11] \xHH a backslash followed by x and two hexa digits, + * becomes the character whose Ascii code is equal + * to these digits. If not followed by two digits, + * it is 'x' char itself. + * + * [12] a composite regular expression xy where x and y + * are in the form [1] to [11] matches the longest + * match of x followed by a match for y. + * + * [13] ^ a regular expression starting with a ^ character + * $ and/or ending with a $ character, restricts the + * pattern matching to the beginning of the line, + * or the end of line. [anchors] Elsewhere in the + * pattern, ^ and $ are treated as ordinary characters. + * + * + * Acknowledgements: + * + * HCR's Hugh Redelmeier has been most helpful in various + * stages of development. He convinced me to include BOW + * and EOW constructs, originally invented by Rob Pike at + * the University of Toronto. + * + * References: + * Software tools Kernighan & Plauger + * Software tools in Pascal Kernighan & Plauger + * Grep [rsx-11 C dist] David Conroy + * ed - text editor Un*x Programmer's Manual + * Advanced editing on Un*x B. W. Kernighan + * RegExp routines Henry Spencer + * + * Notes: + * + * This implementation uses a bit-set representation for character + * classes for speed and compactness. Each character is represented + * by one bit in a 256-bit block. Thus, CCL always takes a + * constant 32 bytes in the internal nfa, and RESearch::Execute does a single + * bit comparison to locate the character in the set. + * + * Examples: + * + * pattern: foo*.* + * compile: CHR f CHR o CLO CHR o END CLO ANY END END + * matches: fo foo fooo foobar fobar foxx ... + * + * pattern: fo[ob]a[rz] + * compile: CHR f CHR o CCL bitset CHR a CCL bitset END + * matches: fobar fooar fobaz fooaz + * + * pattern: foo\\+ + * compile: CHR f CHR o CHR o CHR \ CLO CHR \ END END + * matches: foo\ foo\\ foo\\\ ... + * + * pattern: \(foo\)[1-3]\1 (same as foo[1-3]foo) + * compile: BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END + * matches: foo1foo foo2foo foo3foo + * + * pattern: \(fo.*\)-\1 + * compile: BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END + * matches: foo-foo fo-fo fob-fob foobar-foobar ... + */ + +#include "CharClassify.h" +#include "RESearch.h" + +// Shut up annoying Visual C++ warnings: +#ifdef _MSC_VER +#pragma warning(disable: 4514) +#endif + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +#define OKP 1 +#define NOP 0 + +#define CHR 1 +#define ANY 2 +#define CCL 3 +#define BOL 4 +#define EOL 5 +#define BOT 6 +#define EOT 7 +#define BOW 8 +#define EOW 9 +#define REF 10 +#define CLO 11 + +#define END 0 + +/* + * The following defines are not meant to be changeable. + * They are for readability only. + */ +#define BLKIND 0370 +#define BITIND 07 + +const char bitarr[] = { 1, 2, 4, 8, 16, 32, 64, '\200' }; + +#define badpat(x) (*nfa = END, x) + +/* + * Character classification table for word boundary operators BOW + * and EOW is passed in by the creator of this object (Scintilla + * Document). The Document default state is that word chars are: + * 0-9, a-z, A-Z and _ + */ + +RESearch::RESearch(CharClassify *charClassTable) { + charClass = charClassTable; + Init(); +} + +RESearch::~RESearch() { + Clear(); +} + +void RESearch::Init() { + sta = NOP; /* status of lastpat */ + bol = 0; + for (int i = 0; i < MAXTAG; i++) + pat[i] = 0; + for (int j = 0; j < BITBLK; j++) + bittab[j] = 0; +} + +void RESearch::Clear() { + for (int i = 0; i < MAXTAG; i++) { + delete []pat[i]; + pat[i] = 0; + bopat[i] = NOTFOUND; + eopat[i] = NOTFOUND; + } +} + +bool RESearch::GrabMatches(CharacterIndexer &ci) { + bool success = true; + for (unsigned int i = 0; i < MAXTAG; i++) { + if ((bopat[i] != NOTFOUND) && (eopat[i] != NOTFOUND)) { + unsigned int len = eopat[i] - bopat[i]; + pat[i] = new char[len + 1]; + if (pat[i]) { + for (unsigned int j = 0; j < len; j++) + pat[i][j] = ci.CharAt(bopat[i] + j); + pat[i][len] = '\0'; + } else { + success = false; + } + } + } + return success; +} + +void RESearch::ChSet(unsigned char c) { + bittab[((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND]; +} + +void RESearch::ChSetWithCase(unsigned char c, bool caseSensitive) { + if (caseSensitive) { + ChSet(c); + } else { + if ((c >= 'a') && (c <= 'z')) { + ChSet(c); + ChSet(static_cast(c - 'a' + 'A')); + } else if ((c >= 'A') && (c <= 'Z')) { + ChSet(c); + ChSet(static_cast(c - 'A' + 'a')); + } else { + ChSet(c); + } + } +} + +const unsigned char escapeValue(unsigned char ch) { + switch (ch) { + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + } + return 0; +} + +static int GetHexaChar(unsigned char hd1, unsigned char hd2) { + int hexValue = 0; + if (hd1 >= '0' && hd1 <= '9') { + hexValue += 16 * (hd1 - '0'); + } else if (hd1 >= 'A' && hd1 <= 'F') { + hexValue += 16 * (hd1 - 'A' + 10); + } else if (hd1 >= 'a' && hd1 <= 'f') { + hexValue += 16 * (hd1 - 'a' + 10); + } else + return -1; + if (hd2 >= '0' && hd2 <= '9') { + hexValue += hd2 - '0'; + } else if (hd2 >= 'A' && hd2 <= 'F') { + hexValue += hd2 - 'A' + 10; + } else if (hd2 >= 'a' && hd2 <= 'f') { + hexValue += hd2 - 'a' + 10; + } else + return -1; + return hexValue; +} + +/** + * Called when the parser finds a backslash not followed + * by a valid expression (like \( in non-Posix mode). + * @param pattern: pointer on the char after the backslash. + * @param incr: (out) number of chars to skip after expression evaluation. + * @return the char if it resolves to a simple char, + * or -1 for a char class. In this case, bittab is changed. + */ +int RESearch::GetBackslashExpression( + const char *pattern, + int &incr) { + // Since error reporting is primitive and messages are not used anyway, + // I choose to interpret unexpected syntax in a logical way instead + // of reporting errors. Otherwise, we can stick on, eg., PCRE behavior. + incr = 0; // Most of the time, will skip the char "naturally". + int c; + int result = -1; + unsigned char bsc = *pattern; + if (!bsc) { + // Avoid overrun + result = '\\'; // \ at end of pattern, take it literally + return result; + } + + switch (bsc) { + case 'a': + case 'b': + case 'n': + case 'f': + case 'r': + case 't': + case 'v': + result = escapeValue(bsc); + break; + case 'x': { + unsigned char hd1 = *(pattern + 1); + unsigned char hd2 = *(pattern + 2); + int hexValue = GetHexaChar(hd1, hd2); + if (hexValue >= 0) { + result = hexValue; + incr = 2; // Must skip the digits + } else { + result = 'x'; // \x without 2 digits: see it as 'x' + } + } + break; + case 'd': + for (c = '0'; c <= '9'; c++) { + ChSet(static_cast(c)); + } + break; + case 'D': + for (c = 0; c < MAXCHR; c++) { + if (c < '0' || c > '9') { + ChSet(static_cast(c)); + } + } + break; + case 's': + ChSet(' '); + ChSet('\t'); + ChSet('\n'); + ChSet('\r'); + ChSet('\f'); + ChSet('\v'); + break; + case 'S': + for (c = 0; c < MAXCHR; c++) { + if (c != ' ' && !(c >= 0x09 && c <= 0x0D)) { + ChSet(static_cast(c)); + } + } + case 'w': + for (c = 0; c < MAXCHR; c++) { + if (iswordc(static_cast(c))) { + ChSet(static_cast(c)); + } + } + break; + case 'W': + for (c = 0; c < MAXCHR; c++) { + if (!iswordc(static_cast(c))) { + ChSet(static_cast(c)); + } + } + break; + default: + result = bsc; + } + return result; +} + +const char *RESearch::Compile(const char *pattern, int length, bool caseSensitive, bool posix) { + char *mp=nfa; /* nfa pointer */ + char *lp; /* saved pointer */ + char *sp=nfa; /* another one */ + char *mpMax = mp + MAXNFA - BITBLK - 10; + + int tagi = 0; /* tag stack index */ + int tagc = 1; /* actual tag count */ + + int n; + char mask; /* xor mask -CCL/NCL */ + int c1, c2, prevChar; + + if (!pattern || !length) { + if (sta) + return 0; + else + return badpat("No previous regular expression"); + } + sta = NOP; + + const char *p=pattern; /* pattern pointer */ + for (int i=0; i mpMax) + return badpat("Pattern too long"); + lp = mp; + switch (*p) { + + case '.': /* match any char */ + *mp++ = ANY; + break; + + case '^': /* match beginning */ + if (p == pattern) + *mp++ = BOL; + else { + *mp++ = CHR; + *mp++ = *p; + } + break; + + case '$': /* match endofline */ + if (!*(p+1)) + *mp++ = EOL; + else { + *mp++ = CHR; + *mp++ = *p; + } + break; + + case '[': /* match char class */ + *mp++ = CCL; + prevChar = 0; + + i++; + if (*++p == '^') { + mask = '\377'; + i++; + p++; + } else + mask = 0; + + if (*p == '-') { /* real dash */ + i++; + prevChar = *p; + ChSet(*p++); + } + if (*p == ']') { /* real brace */ + i++; + prevChar = *p; + ChSet(*p++); + } + while (*p && *p != ']') { + if (*p == '-') { + if (prevChar < 0) { + // Previous def. was a char class like \d, take dash literally + prevChar = *p; + ChSet(*p); + } else if (*(p+1)) { + if (*(p+1) != ']') { + c1 = prevChar + 1; + i++; + c2 = *++p; + if (c2 == '\\') { + if (!*(p+1)) // End of RE + return badpat("Missing ]"); + else { + i++; + p++; + int incr; + c2 = GetBackslashExpression(p, incr); + i += incr; + p += incr; + if (c2 >= 0) { + // Convention: \c (c is any char) is case sensitive, whatever the option + ChSet(static_cast(c2)); + prevChar = c2; + } else { + // bittab is already changed + prevChar = -1; + } + } + } + if (prevChar < 0) { + // Char after dash is char class like \d, take dash literally + prevChar = '-'; + ChSet('-'); + } else { + // Put all chars between c1 and c2 included in the char set + while (c1 <= c2) { + ChSetWithCase(static_cast(c1++), caseSensitive); + } + } + } else { + // Dash before the ], take it literally + prevChar = *p; + ChSet(*p); + } + } else { + return badpat("Missing ]"); + } + } else if (*p == '\\' && *(p+1)) { + i++; + p++; + int incr; + int c = GetBackslashExpression(p, incr); + i += incr; + p += incr; + if (c >= 0) { + // Convention: \c (c is any char) is case sensitive, whatever the option + ChSet(static_cast(c)); + prevChar = c; + } else { + // bittab is already changed + prevChar = -1; + } + } else { + prevChar = *p; + ChSetWithCase(*p, caseSensitive); + } + i++; + p++; + } + if (!*p) + return badpat("Missing ]"); + + for (n = 0; n < BITBLK; bittab[n++] = 0) + *mp++ = static_cast(mask ^ bittab[n]); + + break; + + case '*': /* match 0 or more... */ + case '+': /* match 1 or more... */ + if (p == pattern) + return badpat("Empty closure"); + lp = sp; /* previous opcode */ + if (*lp == CLO) /* equivalence... */ + break; + switch (*lp) { + + case BOL: + case BOT: + case EOT: + case BOW: + case EOW: + case REF: + return badpat("Illegal closure"); + default: + break; + } + + if (*p == '+') + for (sp = mp; lp < sp; lp++) + *mp++ = *lp; + + *mp++ = END; + *mp++ = END; + sp = mp; + while (--mp > lp) + *mp = mp[-1]; + *mp = CLO; + mp = sp; + break; + + case '\\': /* tags, backrefs... */ + i++; + switch (*++p) { + case '<': + *mp++ = BOW; + break; + case '>': + if (*sp == BOW) + return badpat("Null pattern inside \\<\\>"); + *mp++ = EOW; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = *p-'0'; + if (tagi > 0 && tagstk[tagi] == n) + return badpat("Cyclical reference"); + if (tagc > n) { + *mp++ = static_cast(REF); + *mp++ = static_cast(n); + } else + return badpat("Undetermined reference"); + break; + default: + if (!posix && *p == '(') { + if (tagc < MAXTAG) { + tagstk[++tagi] = tagc; + *mp++ = BOT; + *mp++ = static_cast(tagc++); + } else + return badpat("Too many \\(\\) pairs"); + } else if (!posix && *p == ')') { + if (*sp == BOT) + return badpat("Null pattern inside \\(\\)"); + if (tagi > 0) { + *mp++ = static_cast(EOT); + *mp++ = static_cast(tagstk[tagi--]); + } else + return badpat("Unmatched \\)"); + } else { + int incr; + int c = GetBackslashExpression(p, incr); + i += incr; + p += incr; + if (c >= 0) { + *mp++ = CHR; + *mp++ = static_cast(c); + } else { + *mp++ = CCL; + mask = 0; + for (n = 0; n < BITBLK; bittab[n++] = 0) + *mp++ = static_cast(mask ^ bittab[n]); + } + } + } + break; + + default : /* an ordinary char */ + if (posix && *p == '(') { + if (tagc < MAXTAG) { + tagstk[++tagi] = tagc; + *mp++ = BOT; + *mp++ = static_cast(tagc++); + } else + return badpat("Too many () pairs"); + } else if (posix && *p == ')') { + if (*sp == BOT) + return badpat("Null pattern inside ()"); + if (tagi > 0) { + *mp++ = static_cast(EOT); + *mp++ = static_cast(tagstk[tagi--]); + } else + return badpat("Unmatched )"); + } else { + unsigned char c = *p; + if (!c) // End of RE + c = '\\'; // We take it as raw backslash + if (caseSensitive || !iswordc(c)) { + *mp++ = CHR; + *mp++ = c; + } else { + *mp++ = CCL; + mask = 0; + ChSetWithCase(c, false); + for (n = 0; n < BITBLK; bittab[n++] = 0) + *mp++ = static_cast(mask ^ bittab[n]); + } + } + break; + } + sp = lp; + } + if (tagi > 0) + return badpat((posix ? "Unmatched (" : "Unmatched \\(")); + *mp = END; + sta = OKP; + return 0; +} + +/* + * RESearch::Execute: + * execute nfa to find a match. + * + * special cases: (nfa[0]) + * BOL + * Match only once, starting from the + * beginning. + * CHR + * First locate the character without + * calling PMatch, and if found, call + * PMatch for the remaining string. + * END + * RESearch::Compile failed, poor luser did not + * check for it. Fail fast. + * + * If a match is found, bopat[0] and eopat[0] are set + * to the beginning and the end of the matched fragment, + * respectively. + * + */ +int RESearch::Execute(CharacterIndexer &ci, int lp, int endp) { + unsigned char c; + int ep = NOTFOUND; + char *ap = nfa; + + bol = lp; + failure = 0; + + Clear(); + + switch (*ap) { + + case BOL: /* anchored: match from BOL only */ + ep = PMatch(ci, lp, endp, ap); + break; + case EOL: /* just searching for end of line normal path doesn't work */ + if (*(ap+1) == END) { + lp = endp; + ep = lp; + break; + } else { + return 0; + } + case CHR: /* ordinary char: locate it fast */ + c = *(ap+1); + while ((lp < endp) && (ci.CharAt(lp) != c)) + lp++; + if (lp >= endp) /* if EOS, fail, else fall thru. */ + return 0; + default: /* regular matching all the way. */ + while (lp < endp) { + ep = PMatch(ci, lp, endp, ap); + if (ep != NOTFOUND) + break; + lp++; + } + break; + case END: /* munged automaton. fail always */ + return 0; + } + if (ep == NOTFOUND) + return 0; + + bopat[0] = lp; + eopat[0] = ep; + return 1; +} + +/* + * PMatch: internal routine for the hard part + * + * This code is partly snarfed from an early grep written by + * David Conroy. The backref and tag stuff, and various other + * innovations are by oz. + * + * special case optimizations: (nfa[n], nfa[n+1]) + * CLO ANY + * We KNOW .* will match everything upto the + * end of line. Thus, directly go to the end of + * line, without recursive PMatch calls. As in + * the other closure cases, the remaining pattern + * must be matched by moving backwards on the + * string recursively, to find a match for xy + * (x is ".*" and y is the remaining pattern) + * where the match satisfies the LONGEST match for + * x followed by a match for y. + * CLO CHR + * We can again scan the string forward for the + * single char and at the point of failure, we + * execute the remaining nfa recursively, same as + * above. + * + * At the end of a successful match, bopat[n] and eopat[n] + * are set to the beginning and end of subpatterns matched + * by tagged expressions (n = 1 to 9). + */ + +extern void re_fail(char *,char); + +#define isinset(x,y) ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND]) + +/* + * skip values for CLO XXX to skip past the closure + */ + +#define ANYSKIP 2 /* [CLO] ANY END */ +#define CHRSKIP 3 /* [CLO] CHR chr END */ +#define CCLSKIP 34 /* [CLO] CCL 32 bytes END */ + +int RESearch::PMatch(CharacterIndexer &ci, int lp, int endp, char *ap) { + int op, c, n; + int e; /* extra pointer for CLO */ + int bp; /* beginning of subpat... */ + int ep; /* ending of subpat... */ + int are; /* to save the line ptr. */ + + while ((op = *ap++) != END) + switch (op) { + + case CHR: + if (ci.CharAt(lp++) != *ap++) + return NOTFOUND; + break; + case ANY: + if (lp++ >= endp) + return NOTFOUND; + break; + case CCL: + if (lp >= endp) + return NOTFOUND; + c = ci.CharAt(lp++); + if (!isinset(ap,c)) + return NOTFOUND; + ap += BITBLK; + break; + case BOL: + if (lp != bol) + return NOTFOUND; + break; + case EOL: + if (lp < endp) + return NOTFOUND; + break; + case BOT: + bopat[(int)*ap++] = lp; + break; + case EOT: + eopat[(int)*ap++] = lp; + break; + case BOW: + if ((lp!=bol && iswordc(ci.CharAt(lp-1))) || !iswordc(ci.CharAt(lp))) + return NOTFOUND; + break; + case EOW: + if (lp==bol || !iswordc(ci.CharAt(lp-1)) || iswordc(ci.CharAt(lp))) + return NOTFOUND; + break; + case REF: + n = *ap++; + bp = bopat[n]; + ep = eopat[n]; + while (bp < ep) + if (ci.CharAt(bp++) != ci.CharAt(lp++)) + return NOTFOUND; + break; + case CLO: + are = lp; + switch (*ap) { + + case ANY: + while (lp < endp) + lp++; + n = ANYSKIP; + break; + case CHR: + c = *(ap+1); + while ((lp < endp) && (c == ci.CharAt(lp))) + lp++; + n = CHRSKIP; + break; + case CCL: + while ((lp < endp) && isinset(ap+1,ci.CharAt(lp))) + lp++; + n = CCLSKIP; + break; + default: + failure = true; + //re_fail("closure: bad nfa.", *ap); + return NOTFOUND; + } + + ap += n; + + while (lp >= are) { + if ((e = PMatch(ci, lp, endp, ap)) != NOTFOUND) + return e; + --lp; + } + return NOTFOUND; + default: + //re_fail("RESearch::Execute: bad nfa.", static_cast(op)); + return NOTFOUND; + } + return lp; +} + +/* + * RESearch::Substitute: + * substitute the matched portions of the src in dst. + * + * & substitute the entire matched pattern. + * + * \digit substitute a subpattern, with the given tag number. + * Tags are numbered from 1 to 9. If the particular + * tagged subpattern does not exist, null is substituted. + */ +int RESearch::Substitute(CharacterIndexer &ci, char *src, char *dst) { + unsigned char c; + int pin; + int bp; + int ep; + + if (!*src || !bopat[0]) + return 0; + + while ((c = *src++) != 0) { + switch (c) { + + case '&': + pin = 0; + break; + + case '\\': + c = *src++; + if (c >= '0' && c <= '9') { + pin = c - '0'; + break; + } + + default: + *dst++ = c; + continue; + } + + if ((bp = bopat[pin]) != 0 && (ep = eopat[pin]) != 0) { + while (ci.CharAt(bp) && bp < ep) + *dst++ = ci.CharAt(bp++); + if (bp < ep) + return 0; + } + } + *dst = '\0'; + return 1; +} + diff --git a/harbour/contrib/hbide/qscintilla/RESearch.h b/harbour/contrib/hbide/qscintilla/RESearch.h new file mode 100644 index 0000000000..ef8c3e11b2 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/RESearch.h @@ -0,0 +1,75 @@ +// Scintilla source code edit control +/** @file RESearch.h + ** Interface to the regular expression search library. + **/ +// Written by Neil Hodgson +// Based on the work of Ozan S. Yigit. +// This file is in the public domain. + +#ifndef RESEARCH_H +#define RESEARCH_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/* + * The following defines are not meant to be changeable. + * They are for readability only. + */ +#define MAXCHR 256 +#define CHRBIT 8 +#define BITBLK MAXCHR/CHRBIT + +class CharacterIndexer { +public: + virtual char CharAt(int index)=0; + virtual ~CharacterIndexer() { + } +}; + +class RESearch { + +public: + RESearch(CharClassify *charClassTable); + ~RESearch(); + bool GrabMatches(CharacterIndexer &ci); + const char *Compile(const char *pattern, int length, bool caseSensitive, bool posix); + int Execute(CharacterIndexer &ci, int lp, int endp); + int Substitute(CharacterIndexer &ci, char *src, char *dst); + + enum { MAXTAG=10 }; + enum { MAXNFA=2048 }; + enum { NOTFOUND=-1 }; + + int bopat[MAXTAG]; + int eopat[MAXTAG]; + char *pat[MAXTAG]; + +private: + void Init(); + void Clear(); + void ChSet(unsigned char c); + void ChSetWithCase(unsigned char c, bool caseSensitive); + int GetBackslashExpression(const char *pattern, int &incr); + + int PMatch(CharacterIndexer &ci, int lp, int endp, char *ap); + + int bol; + int tagstk[MAXTAG]; /* subpat tag stack */ + char nfa[MAXNFA]; /* automaton */ + int sta; + unsigned char bittab[BITBLK]; /* bit table for CCL pre-set bits */ + int failure; + CharClassify *charClass; + bool iswordc(unsigned char x) { + return charClass->IsWord(x); + } +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif + diff --git a/harbour/contrib/hbide/qscintilla/RunStyles.cpp b/harbour/contrib/hbide/qscintilla/RunStyles.cpp new file mode 100644 index 0000000000..04a6e32dc9 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/RunStyles.cpp @@ -0,0 +1,216 @@ +/** @file RunStyles.cxx + ** Data structure used to store sparse styles. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +// Find the first run at a position +int RunStyles::RunFromPosition(int position) { + int run = starts->PartitionFromPosition(position); + // Go to first element with this position + while ((run > 0) && (position == starts->PositionFromPartition(run-1))) { + run--; + } + return run; +} + +// If there is no run boundary at position, insert one continuing style. +int RunStyles::SplitRun(int position) { + int run = RunFromPosition(position); + int posRun = starts->PositionFromPartition(run); + if (posRun < position) { + int runStyle = ValueAt(position); + run++; + starts->InsertPartition(run, position); + styles->InsertValue(run, 1, runStyle); + } + return run; +} + +void RunStyles::RemoveRun(int run) { + starts->RemovePartition(run); + styles->DeleteRange(run, 1); +} + +void RunStyles::RemoveRunIfEmpty(int run) { + if ((run < starts->Partitions()) && (starts->Partitions() > 1)) { + if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) { + RemoveRun(run); + } + } +} + +void RunStyles::RemoveRunIfSameAsPrevious(int run) { + if ((run > 0) && (run < starts->Partitions())) { + if (styles->ValueAt(run-1) == styles->ValueAt(run)) { + RemoveRun(run); + } + } +} + +RunStyles::RunStyles() { + starts = new Partitioning(8); + styles = new SplitVector(); + styles->InsertValue(0, 2, 0); +} + +RunStyles::~RunStyles() { + delete starts; + starts = NULL; + delete styles; + styles = NULL; +} + +int RunStyles::Length() const { + return starts->PositionFromPartition(starts->Partitions()); +} + +int RunStyles::ValueAt(int position) const { + return styles->ValueAt(starts->PartitionFromPosition(position)); +} + +int RunStyles::FindNextChange(int position, int end) { + int run = starts->PartitionFromPosition(position); + if (run < starts->Partitions()) { + int runChange = starts->PositionFromPartition(run); + if (runChange > position) + return runChange; + int nextChange = starts->PositionFromPartition(run + 1); + if (nextChange > position) { + return nextChange; + } else if (position < end) { + return end; + } else { + return end + 1; + } + } else { + return end + 1; + } +} + +int RunStyles::StartRun(int position) { + return starts->PositionFromPartition(starts->PartitionFromPosition(position)); +} + +int RunStyles::EndRun(int position) { + return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1); +} + +bool RunStyles::FillRange(int &position, int value, int &fillLength) { + int end = position + fillLength; + int runEnd = RunFromPosition(end); + if (styles->ValueAt(runEnd) == value) { + // End already has value so trim range. + end = starts->PositionFromPartition(runEnd); + if (position >= end) { + // Whole range is already same as value so no action + return false; + } + fillLength = end - position; + } else { + runEnd = SplitRun(end); + } + int runStart = RunFromPosition(position); + if (styles->ValueAt(runStart) == value) { + // Start is in expected value so trim range. + runStart++; + position = starts->PositionFromPartition(runStart); + fillLength = end - position; + } else { + if (starts->PositionFromPartition(runStart) < position) { + runStart = SplitRun(position); + runEnd++; + } + } + if (runStart < runEnd) { + styles->SetValueAt(runStart, value); + // Remove each old run over the range + for (int run=runStart+1; runPositionFromPartition(runStart) == position) { + int runStyle = ValueAt(position); + // Inserting at start of run so make previous longer + if (runStart == 0) { + // Inserting at start of document so ensure 0 + if (runStyle) { + styles->SetValueAt(0, 0); + starts->InsertPartition(1, 0); + styles->InsertValue(1, 1, runStyle); + starts->InsertText(0, insertLength); + } else { + starts->InsertText(runStart, insertLength); + } + } else { + if (runStyle) { + starts->InsertText(runStart-1, insertLength); + } else { + // Insert at end of run so do not extend style + starts->InsertText(runStart, insertLength); + } + } + } else { + starts->InsertText(runStart, insertLength); + } +} + +void RunStyles::DeleteAll() { + delete starts; + starts = NULL; + delete styles; + styles = NULL; + starts = new Partitioning(8); + styles = new SplitVector(); + styles->InsertValue(0, 2, 0); +} + +void RunStyles::DeleteRange(int position, int deleteLength) { + int end = position + deleteLength; + int runStart = RunFromPosition(position); + int runEnd = RunFromPosition(end); + if (runStart == runEnd) { + // Deleting from inside one run + starts->InsertText(runStart, -deleteLength); + } else { + runStart = SplitRun(position); + runEnd = SplitRun(end); + starts->InsertText(runStart, -deleteLength); + // Remove each old run over the range + for (int run=runStart; run +// The License.txt file describes the conditions under which this software may be distributed. + +/// Styling buffer using one element for each run rather than using +/// a filled buffer. + +#ifndef RUNSTYLES_H +#define RUNSTYLES_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class RunStyles { +public: + Partitioning *starts; + SplitVector *styles; + int RunFromPosition(int position); + int SplitRun(int position); + void RemoveRun(int run); + void RemoveRunIfEmpty(int run); + void RemoveRunIfSameAsPrevious(int run); +public: + RunStyles(); + ~RunStyles(); + int Length() const; + int ValueAt(int position) const; + int FindNextChange(int position, int end); + int StartRun(int position); + int EndRun(int position); + // Returns true if some values may have changed + bool FillRange(int &position, int value, int &fillLength); + void SetValueAt(int position, int value); + void InsertSpace(int position, int insertLength); + void DeleteAll(); + void DeleteRange(int position, int deleteLength); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/SString.h b/harbour/contrib/hbide/qscintilla/SString.h new file mode 100644 index 0000000000..b770afebee --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/SString.h @@ -0,0 +1,289 @@ +// SciTE - Scintilla based Text Editor +/** @file SString.h + ** A simple string class. + **/ +// Copyright 1998-2004 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SSTRING_H +#define SSTRING_H + + +// These functions are implemented because each platform calls them something different. +int CompareCaseInsensitive(const char *a, const char *b); +int CompareNCaseInsensitive(const char *a, const char *b, size_t len); +bool EqualCaseInsensitive(const char *a, const char *b); + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +// Define another string class. +// While it would be 'better' to use std::string, that doubles the executable size. +// An SString may contain embedded nul characters. + +/** + * Base class from which the two other classes (SBuffer & SString) + * are derived. + */ +class SContainer { +public: + /** Type of string lengths (sizes) and positions (indexes). */ + typedef size_t lenpos_t; + /** Out of bounds value indicating that the string argument should be measured. */ + enum { measure_length=0xffffffffU}; + +protected: + char *s; ///< The C string + lenpos_t sSize; ///< The size of the buffer, less 1: ie. the maximum size of the string + + SContainer() : s(0), sSize(0) {} + ~SContainer() { + delete []s; // Suppose it was allocated using StringAllocate + s = 0; + sSize = 0; + } + /** Size of buffer. */ + lenpos_t size() const { + if (s) { + return sSize; + } else { + return 0; + } + } +public: + /** + * Allocate uninitialized memory big enough to fit a string of the given length. + * @return the pointer to the new string + */ + static char *StringAllocate(lenpos_t len); + /** + * Duplicate a buffer/C string. + * Allocate memory of the given size, or big enough to fit the string if length isn't given; + * then copy the given string in the allocated memory. + * @return the pointer to the new string + */ + static char *StringAllocate( + const char *s, ///< The string to duplicate + lenpos_t len=measure_length); ///< The length of memory to allocate. Optional. +}; + + +/** + * @brief A string buffer class. + * + * Main use is to ask an API the length of a string it can provide, + * then to allocate a buffer of the given size, and to provide this buffer + * to the API to put the string. + * This class is intended to be shortlived, to be transformed as SString + * as soon as it holds the string, so it has little members. + * Note: we assume the buffer is filled by the API. If the length can be shorter, + * we should set sLen to strlen(sb.ptr()) in related SString constructor and assignment. + */ +class SBuffer : protected SContainer { +public: + SBuffer(lenpos_t len) { + s = StringAllocate(len); + if (s) { + *s = '\0'; + sSize = len; + } else { + sSize = 0; + } + } +private: + /// Copy constructor + // Here only to be on the safe size, user should avoid returning SBuffer values. + SBuffer(const SBuffer &source) : SContainer() { + s = StringAllocate(source.s, source.sSize); + sSize = (s) ? source.sSize : 0; + } + /// Default assignment operator + // Same here, shouldn't be used + SBuffer &operator=(const SBuffer &source) { + if (this != &source) { + delete []s; + s = StringAllocate(source.s, source.sSize); + sSize = (s) ? source.sSize : 0; + } + return *this; + } +public: + /** Provide direct read/write access to buffer. */ + char *ptr() { + return s; + } + /** Ownership of the buffer have been taken, so release it. */ + void reset() { + s = 0; + sSize = 0; + } + /** Size of buffer. */ + lenpos_t size() const { + return SContainer::size(); + } +}; + + +/** + * @brief A simple string class. + * + * Hold the length of the string for quick operations, + * can have a buffer bigger than the string to avoid too many memory allocations and copies. + * May have embedded zeroes as a result of @a substitute, but relies too heavily on C string + * functions to allow reliable manipulations of these strings, other than simple appends, etc. + */ +class SString : protected SContainer { + lenpos_t sLen; ///< The size of the string in s + lenpos_t sizeGrowth; ///< Minimum growth size when appending strings + enum { sizeGrowthDefault = 64 }; + + bool grow(lenpos_t lenNew); + SString &assign(const char *sOther, lenpos_t sSize_=measure_length); + +public: + SString() : sLen(0), sizeGrowth(sizeGrowthDefault) {} + SString(const SString &source) : SContainer(), sizeGrowth(sizeGrowthDefault) { + s = StringAllocate(source.s, source.sLen); + sSize = sLen = (s) ? source.sLen : 0; + } + SString(const char *s_) : sizeGrowth(sizeGrowthDefault) { + s = StringAllocate(s_); + sSize = sLen = (s) ? strlen(s) : 0; + } + SString(SBuffer &buf) : sizeGrowth(sizeGrowthDefault) { + s = buf.ptr(); + sSize = sLen = buf.size(); + // Consumes the given buffer! + buf.reset(); + } + SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) { + // note: expects the "last" argument to point one beyond the range end (a la STL iterators) + s = StringAllocate(s_ + first, last - first); + sSize = sLen = (s) ? last - first : 0; + } + SString(int i); + SString(double d, int precision); + ~SString() { + sLen = 0; + } + void clear() { + if (s) { + *s = '\0'; + } + sLen = 0; + } + /** Size of buffer. */ + lenpos_t size() const { + return SContainer::size(); + } + /** Size of string in buffer. */ + lenpos_t length() const { + return sLen; + } + /** Read access to a character of the string. */ + char operator[](lenpos_t i) const { + return (s && i < sSize) ? s[i] : '\0'; + } + SString &operator=(const char *source) { + return assign(source); + } + SString &operator=(const SString &source) { + if (this != &source) { + assign(source.s, source.sLen); + } + return *this; + } + bool operator==(const SString &sOther) const; + bool operator!=(const SString &sOther) const { + return !operator==(sOther); + } + bool operator==(const char *sOther) const; + bool operator!=(const char *sOther) const { + return !operator==(sOther); + } + bool contains(char ch) const { + return (s && *s) ? strchr(s, ch) != 0 : false; + } + void setsizegrowth(lenpos_t sizeGrowth_) { + sizeGrowth = sizeGrowth_; + } + const char *c_str() const { + return s ? s : ""; + } + /** Give ownership of buffer to caller which must use delete[] to free buffer. */ + char *detach() { + char *sRet = s; + s = 0; + sSize = 0; + sLen = 0; + return sRet; + } + SString substr(lenpos_t subPos, lenpos_t subLen=measure_length) const; + SString &lowercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length); + SString &uppercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length); + SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0'); + SString &operator+=(const char *sOther) { + return append(sOther, static_cast(measure_length)); + } + SString &operator+=(const SString &sOther) { + return append(sOther.s, sOther.sLen); + } + SString &operator+=(char ch) { + return append(&ch, 1); + } + SString &appendwithseparator(const char *sOther, char sep) { + return append(sOther, strlen(sOther), sep); + } + SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length); + + /** + * Remove @a len characters from the @a pos position, included. + * Characters at pos + len and beyond replace characters at pos. + * If @a len is 0, or greater than the length of the string + * starting at @a pos, the string is just truncated at @a pos. + */ + void remove(lenpos_t pos, lenpos_t len); + + SString &change(lenpos_t pos, char ch) { + if (pos < sLen) { // character changed must be in string bounds + *(s + pos) = ch; + } + return *this; + } + /** Read an integral numeric value from the string. */ + int value() const { + return s ? atoi(s) : 0; + } + bool startswith(const char *prefix); + bool endswith(const char *suffix); + int search(const char *sFind, lenpos_t start=0) const; + bool contains(const char *sFind) const { + return search(sFind) >= 0; + } + int substitute(char chFind, char chReplace); + int substitute(const char *sFind, const char *sReplace); + int remove(const char *sFind) { + return substitute(sFind, ""); + } +}; + + +/** + * Duplicate a C string. + * Allocate memory of the given size, or big enough to fit the string if length isn't given; + * then copy the given string in the allocated memory. + * @return the pointer to the new string + */ +inline char *StringDup( + const char *s, ///< The string to duplicate + SContainer::lenpos_t len=SContainer::measure_length) ///< The length of memory to allocate. Optional. +{ + return SContainer::StringAllocate(s, len); +} + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/SVector.h b/harbour/contrib/hbide/qscintilla/SVector.h new file mode 100644 index 0000000000..9f56da5289 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/SVector.h @@ -0,0 +1,135 @@ +// Scintilla source code edit control +/** @file SVector.h + ** A simple expandable vector. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SVECTOR_H +#define SVECTOR_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + * A simple expandable integer vector. + * Storage not allocated for elements until an element is used. + * This makes it very lightweight unless used so is a good match for optional features. + */ +class SVector { + enum { allocSize = 4000 }; + + int *v; ///< The vector + unsigned int size; ///< Number of elements allocated + unsigned int len; ///< Number of elements used in vector + bool allocFailure; ///< A memory allocation call has failed + + /** Internally allocate more elements than the user wants + * to avoid thrashing the memory allocator. */ + void SizeTo(int newSize) { + if (newSize < allocSize) + newSize += allocSize; + else + newSize = (newSize * 3) / 2; + int* newv = new int[newSize]; + if (!newv) { + allocFailure = true; + return; + } + size = newSize; + unsigned int i=0; + for (; i 0) { + SizeTo(other.Length()); + if (!allocFailure) { + for (int i=0;i 0) { + SizeTo(other.Length()); + if (!allocFailure) { + for (int i=0;i= len) { + if (i >= size) { + SizeTo(i); + } + len = i+1; + } + return v[i]; + } + /// Reset vector. + void Free() { + delete []v; + v = 0; + size = 0; + len = 0; + } + /** @brief Grow vector size. + * Doesn't allow a vector to be shrinked. */ + void SetLength(unsigned int newLength) { + if (newLength > len) { + if (newLength >= size) { + SizeTo(newLength); + } + } + len = newLength; + } + /// Get the current length (number of used elements) of the vector. + int Length() const { + return len; + } +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/SciLexer.h b/harbour/contrib/hbide/qscintilla/SciLexer.h new file mode 100644 index 0000000000..12700b67b9 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/SciLexer.h @@ -0,0 +1,1390 @@ +/* Scintilla source code edit control */ +/** @file SciLexer.h + ** Interface to the added lexer functions in the SciLexer version of the edit control. + **/ +/* Copyright 1998-2002 by Neil Hodgson + * The License.txt file describes the conditions under which this software may be distributed. */ + +/* Most of this file is automatically generated from the Scintilla.iface interface definition + * file which contains any comments about the definitions. HFacer.py does the generation. */ + +#ifndef SCILEXER_H +#define SCILEXER_H + +/* SciLexer features - not in standard Scintilla */ + +/* ++Autogenerated -- start of section automatically generated from Scintilla.iface */ +#define SCLEX_CONTAINER 0 +#define SCLEX_NULL 1 +#define SCLEX_PYTHON 2 +#define SCLEX_CPP 3 +#define SCLEX_HTML 4 +#define SCLEX_XML 5 +#define SCLEX_PERL 6 +#define SCLEX_SQL 7 +#define SCLEX_VB 8 +#define SCLEX_PROPERTIES 9 +#define SCLEX_ERRORLIST 10 +#define SCLEX_MAKEFILE 11 +#define SCLEX_BATCH 12 +#define SCLEX_XCODE 13 +#define SCLEX_LATEX 14 +#define SCLEX_LUA 15 +#define SCLEX_DIFF 16 +#define SCLEX_CONF 17 +#define SCLEX_PASCAL 18 +#define SCLEX_AVE 19 +#define SCLEX_ADA 20 +#define SCLEX_LISP 21 +#define SCLEX_RUBY 22 +#define SCLEX_EIFFEL 23 +#define SCLEX_EIFFELKW 24 +#define SCLEX_TCL 25 +#define SCLEX_NNCRONTAB 26 +#define SCLEX_BULLANT 27 +#define SCLEX_VBSCRIPT 28 +#define SCLEX_BAAN 31 +#define SCLEX_MATLAB 32 +#define SCLEX_SCRIPTOL 33 +#define SCLEX_ASM 34 +#define SCLEX_CPPNOCASE 35 +#define SCLEX_FORTRAN 36 +#define SCLEX_F77 37 +#define SCLEX_CSS 38 +#define SCLEX_POV 39 +#define SCLEX_LOUT 40 +#define SCLEX_ESCRIPT 41 +#define SCLEX_PS 42 +#define SCLEX_NSIS 43 +#define SCLEX_MMIXAL 44 +#define SCLEX_CLW 45 +#define SCLEX_CLWNOCASE 46 +#define SCLEX_LOT 47 +#define SCLEX_YAML 48 +#define SCLEX_TEX 49 +#define SCLEX_METAPOST 50 +#define SCLEX_POWERBASIC 51 +#define SCLEX_FORTH 52 +#define SCLEX_ERLANG 53 +#define SCLEX_OCTAVE 54 +#define SCLEX_MSSQL 55 +#define SCLEX_VERILOG 56 +#define SCLEX_KIX 57 +#define SCLEX_GUI4CLI 58 +#define SCLEX_SPECMAN 59 +#define SCLEX_AU3 60 +#define SCLEX_APDL 61 +#define SCLEX_BASH 62 +#define SCLEX_ASN1 63 +#define SCLEX_VHDL 64 +#define SCLEX_CAML 65 +#define SCLEX_BLITZBASIC 66 +#define SCLEX_PUREBASIC 67 +#define SCLEX_HASKELL 68 +#define SCLEX_PHPSCRIPT 69 +#define SCLEX_TADS3 70 +#define SCLEX_REBOL 71 +#define SCLEX_SMALLTALK 72 +#define SCLEX_FLAGSHIP 73 +#define SCLEX_CSOUND 74 +#define SCLEX_FREEBASIC 75 +#define SCLEX_INNOSETUP 76 +#define SCLEX_OPAL 77 +#define SCLEX_SPICE 78 +#define SCLEX_D 79 +#define SCLEX_CMAKE 80 +#define SCLEX_GAP 81 +#define SCLEX_PLM 82 +#define SCLEX_PROGRESS 83 +#define SCLEX_ABAQUS 84 +#define SCLEX_ASYMPTOTE 85 +#define SCLEX_R 86 +#define SCLEX_MAGIK 87 +#define SCLEX_POWERSHELL 88 +#define SCLEX_MYSQL 89 +#define SCLEX_PO 90 +#define SCLEX_TAL 91 +#define SCLEX_COBOL 92 +#define SCLEX_TACL 93 +#define SCLEX_SORCUS 94 +#define SCLEX_POWERPRO 95 +#define SCLEX_NIMROD 96 +#define SCLEX_SML 97 +#define SCLEX_MARKDOWN 98 +#define SCLEX_AUTOMATIC 1000 +#define SCE_P_DEFAULT 0 +#define SCE_P_COMMENTLINE 1 +#define SCE_P_NUMBER 2 +#define SCE_P_STRING 3 +#define SCE_P_CHARACTER 4 +#define SCE_P_WORD 5 +#define SCE_P_TRIPLE 6 +#define SCE_P_TRIPLEDOUBLE 7 +#define SCE_P_CLASSNAME 8 +#define SCE_P_DEFNAME 9 +#define SCE_P_OPERATOR 10 +#define SCE_P_IDENTIFIER 11 +#define SCE_P_COMMENTBLOCK 12 +#define SCE_P_STRINGEOL 13 +#define SCE_P_WORD2 14 +#define SCE_P_DECORATOR 15 +#define SCE_C_DEFAULT 0 +#define SCE_C_COMMENT 1 +#define SCE_C_COMMENTLINE 2 +#define SCE_C_COMMENTDOC 3 +#define SCE_C_NUMBER 4 +#define SCE_C_WORD 5 +#define SCE_C_STRING 6 +#define SCE_C_CHARACTER 7 +#define SCE_C_UUID 8 +#define SCE_C_PREPROCESSOR 9 +#define SCE_C_OPERATOR 10 +#define SCE_C_IDENTIFIER 11 +#define SCE_C_STRINGEOL 12 +#define SCE_C_VERBATIM 13 +#define SCE_C_REGEX 14 +#define SCE_C_COMMENTLINEDOC 15 +#define SCE_C_WORD2 16 +#define SCE_C_COMMENTDOCKEYWORD 17 +#define SCE_C_COMMENTDOCKEYWORDERROR 18 +#define SCE_C_GLOBALCLASS 19 +#define SCE_D_DEFAULT 0 +#define SCE_D_COMMENT 1 +#define SCE_D_COMMENTLINE 2 +#define SCE_D_COMMENTDOC 3 +#define SCE_D_COMMENTNESTED 4 +#define SCE_D_NUMBER 5 +#define SCE_D_WORD 6 +#define SCE_D_WORD2 7 +#define SCE_D_WORD3 8 +#define SCE_D_TYPEDEF 9 +#define SCE_D_STRING 10 +#define SCE_D_STRINGEOL 11 +#define SCE_D_CHARACTER 12 +#define SCE_D_OPERATOR 13 +#define SCE_D_IDENTIFIER 14 +#define SCE_D_COMMENTLINEDOC 15 +#define SCE_D_COMMENTDOCKEYWORD 16 +#define SCE_D_COMMENTDOCKEYWORDERROR 17 +#define SCE_D_STRINGB 18 +#define SCE_D_STRINGR 19 +#define SCE_D_WORD5 20 +#define SCE_D_WORD6 21 +#define SCE_D_WORD7 22 +#define SCE_TCL_DEFAULT 0 +#define SCE_TCL_COMMENT 1 +#define SCE_TCL_COMMENTLINE 2 +#define SCE_TCL_NUMBER 3 +#define SCE_TCL_WORD_IN_QUOTE 4 +#define SCE_TCL_IN_QUOTE 5 +#define SCE_TCL_OPERATOR 6 +#define SCE_TCL_IDENTIFIER 7 +#define SCE_TCL_SUBSTITUTION 8 +#define SCE_TCL_SUB_BRACE 9 +#define SCE_TCL_MODIFIER 10 +#define SCE_TCL_EXPAND 11 +#define SCE_TCL_WORD 12 +#define SCE_TCL_WORD2 13 +#define SCE_TCL_WORD3 14 +#define SCE_TCL_WORD4 15 +#define SCE_TCL_WORD5 16 +#define SCE_TCL_WORD6 17 +#define SCE_TCL_WORD7 18 +#define SCE_TCL_WORD8 19 +#define SCE_TCL_COMMENT_BOX 20 +#define SCE_TCL_BLOCK_COMMENT 21 +#define SCE_H_DEFAULT 0 +#define SCE_H_TAG 1 +#define SCE_H_TAGUNKNOWN 2 +#define SCE_H_ATTRIBUTE 3 +#define SCE_H_ATTRIBUTEUNKNOWN 4 +#define SCE_H_NUMBER 5 +#define SCE_H_DOUBLESTRING 6 +#define SCE_H_SINGLESTRING 7 +#define SCE_H_OTHER 8 +#define SCE_H_COMMENT 9 +#define SCE_H_ENTITY 10 +#define SCE_H_TAGEND 11 +#define SCE_H_XMLSTART 12 +#define SCE_H_XMLEND 13 +#define SCE_H_SCRIPT 14 +#define SCE_H_ASP 15 +#define SCE_H_ASPAT 16 +#define SCE_H_CDATA 17 +#define SCE_H_QUESTION 18 +#define SCE_H_VALUE 19 +#define SCE_H_XCCOMMENT 20 +#define SCE_H_SGML_DEFAULT 21 +#define SCE_H_SGML_COMMAND 22 +#define SCE_H_SGML_1ST_PARAM 23 +#define SCE_H_SGML_DOUBLESTRING 24 +#define SCE_H_SGML_SIMPLESTRING 25 +#define SCE_H_SGML_ERROR 26 +#define SCE_H_SGML_SPECIAL 27 +#define SCE_H_SGML_ENTITY 28 +#define SCE_H_SGML_COMMENT 29 +#define SCE_H_SGML_1ST_PARAM_COMMENT 30 +#define SCE_H_SGML_BLOCK_DEFAULT 31 +#define SCE_HJ_START 40 +#define SCE_HJ_DEFAULT 41 +#define SCE_HJ_COMMENT 42 +#define SCE_HJ_COMMENTLINE 43 +#define SCE_HJ_COMMENTDOC 44 +#define SCE_HJ_NUMBER 45 +#define SCE_HJ_WORD 46 +#define SCE_HJ_KEYWORD 47 +#define SCE_HJ_DOUBLESTRING 48 +#define SCE_HJ_SINGLESTRING 49 +#define SCE_HJ_SYMBOLS 50 +#define SCE_HJ_STRINGEOL 51 +#define SCE_HJ_REGEX 52 +#define SCE_HJA_START 55 +#define SCE_HJA_DEFAULT 56 +#define SCE_HJA_COMMENT 57 +#define SCE_HJA_COMMENTLINE 58 +#define SCE_HJA_COMMENTDOC 59 +#define SCE_HJA_NUMBER 60 +#define SCE_HJA_WORD 61 +#define SCE_HJA_KEYWORD 62 +#define SCE_HJA_DOUBLESTRING 63 +#define SCE_HJA_SINGLESTRING 64 +#define SCE_HJA_SYMBOLS 65 +#define SCE_HJA_STRINGEOL 66 +#define SCE_HJA_REGEX 67 +#define SCE_HB_START 70 +#define SCE_HB_DEFAULT 71 +#define SCE_HB_COMMENTLINE 72 +#define SCE_HB_NUMBER 73 +#define SCE_HB_WORD 74 +#define SCE_HB_STRING 75 +#define SCE_HB_IDENTIFIER 76 +#define SCE_HB_STRINGEOL 77 +#define SCE_HBA_START 80 +#define SCE_HBA_DEFAULT 81 +#define SCE_HBA_COMMENTLINE 82 +#define SCE_HBA_NUMBER 83 +#define SCE_HBA_WORD 84 +#define SCE_HBA_STRING 85 +#define SCE_HBA_IDENTIFIER 86 +#define SCE_HBA_STRINGEOL 87 +#define SCE_HP_START 90 +#define SCE_HP_DEFAULT 91 +#define SCE_HP_COMMENTLINE 92 +#define SCE_HP_NUMBER 93 +#define SCE_HP_STRING 94 +#define SCE_HP_CHARACTER 95 +#define SCE_HP_WORD 96 +#define SCE_HP_TRIPLE 97 +#define SCE_HP_TRIPLEDOUBLE 98 +#define SCE_HP_CLASSNAME 99 +#define SCE_HP_DEFNAME 100 +#define SCE_HP_OPERATOR 101 +#define SCE_HP_IDENTIFIER 102 +#define SCE_HPHP_COMPLEX_VARIABLE 104 +#define SCE_HPA_START 105 +#define SCE_HPA_DEFAULT 106 +#define SCE_HPA_COMMENTLINE 107 +#define SCE_HPA_NUMBER 108 +#define SCE_HPA_STRING 109 +#define SCE_HPA_CHARACTER 110 +#define SCE_HPA_WORD 111 +#define SCE_HPA_TRIPLE 112 +#define SCE_HPA_TRIPLEDOUBLE 113 +#define SCE_HPA_CLASSNAME 114 +#define SCE_HPA_DEFNAME 115 +#define SCE_HPA_OPERATOR 116 +#define SCE_HPA_IDENTIFIER 117 +#define SCE_HPHP_DEFAULT 118 +#define SCE_HPHP_HSTRING 119 +#define SCE_HPHP_SIMPLESTRING 120 +#define SCE_HPHP_WORD 121 +#define SCE_HPHP_NUMBER 122 +#define SCE_HPHP_VARIABLE 123 +#define SCE_HPHP_COMMENT 124 +#define SCE_HPHP_COMMENTLINE 125 +#define SCE_HPHP_HSTRING_VARIABLE 126 +#define SCE_HPHP_OPERATOR 127 +#define SCE_PL_DEFAULT 0 +#define SCE_PL_ERROR 1 +#define SCE_PL_COMMENTLINE 2 +#define SCE_PL_POD 3 +#define SCE_PL_NUMBER 4 +#define SCE_PL_WORD 5 +#define SCE_PL_STRING 6 +#define SCE_PL_CHARACTER 7 +#define SCE_PL_PUNCTUATION 8 +#define SCE_PL_PREPROCESSOR 9 +#define SCE_PL_OPERATOR 10 +#define SCE_PL_IDENTIFIER 11 +#define SCE_PL_SCALAR 12 +#define SCE_PL_ARRAY 13 +#define SCE_PL_HASH 14 +#define SCE_PL_SYMBOLTABLE 15 +#define SCE_PL_VARIABLE_INDEXER 16 +#define SCE_PL_REGEX 17 +#define SCE_PL_REGSUBST 18 +#define SCE_PL_LONGQUOTE 19 +#define SCE_PL_BACKTICKS 20 +#define SCE_PL_DATASECTION 21 +#define SCE_PL_HERE_DELIM 22 +#define SCE_PL_HERE_Q 23 +#define SCE_PL_HERE_QQ 24 +#define SCE_PL_HERE_QX 25 +#define SCE_PL_STRING_Q 26 +#define SCE_PL_STRING_QQ 27 +#define SCE_PL_STRING_QX 28 +#define SCE_PL_STRING_QR 29 +#define SCE_PL_STRING_QW 30 +#define SCE_PL_POD_VERB 31 +#define SCE_PL_SUB_PROTOTYPE 40 +#define SCE_PL_FORMAT_IDENT 41 +#define SCE_PL_FORMAT 42 +#define SCE_RB_DEFAULT 0 +#define SCE_RB_ERROR 1 +#define SCE_RB_COMMENTLINE 2 +#define SCE_RB_POD 3 +#define SCE_RB_NUMBER 4 +#define SCE_RB_WORD 5 +#define SCE_RB_STRING 6 +#define SCE_RB_CHARACTER 7 +#define SCE_RB_CLASSNAME 8 +#define SCE_RB_DEFNAME 9 +#define SCE_RB_OPERATOR 10 +#define SCE_RB_IDENTIFIER 11 +#define SCE_RB_REGEX 12 +#define SCE_RB_GLOBAL 13 +#define SCE_RB_SYMBOL 14 +#define SCE_RB_MODULE_NAME 15 +#define SCE_RB_INSTANCE_VAR 16 +#define SCE_RB_CLASS_VAR 17 +#define SCE_RB_BACKTICKS 18 +#define SCE_RB_DATASECTION 19 +#define SCE_RB_HERE_DELIM 20 +#define SCE_RB_HERE_Q 21 +#define SCE_RB_HERE_QQ 22 +#define SCE_RB_HERE_QX 23 +#define SCE_RB_STRING_Q 24 +#define SCE_RB_STRING_QQ 25 +#define SCE_RB_STRING_QX 26 +#define SCE_RB_STRING_QR 27 +#define SCE_RB_STRING_QW 28 +#define SCE_RB_WORD_DEMOTED 29 +#define SCE_RB_STDIN 30 +#define SCE_RB_STDOUT 31 +#define SCE_RB_STDERR 40 +#define SCE_RB_UPPER_BOUND 41 +#define SCE_B_DEFAULT 0 +#define SCE_B_COMMENT 1 +#define SCE_B_NUMBER 2 +#define SCE_B_KEYWORD 3 +#define SCE_B_STRING 4 +#define SCE_B_PREPROCESSOR 5 +#define SCE_B_OPERATOR 6 +#define SCE_B_IDENTIFIER 7 +#define SCE_B_DATE 8 +#define SCE_B_STRINGEOL 9 +#define SCE_B_KEYWORD2 10 +#define SCE_B_KEYWORD3 11 +#define SCE_B_KEYWORD4 12 +#define SCE_B_CONSTANT 13 +#define SCE_B_ASM 14 +#define SCE_B_LABEL 15 +#define SCE_B_ERROR 16 +#define SCE_B_HEXNUMBER 17 +#define SCE_B_BINNUMBER 18 +#define SCE_PROPS_DEFAULT 0 +#define SCE_PROPS_COMMENT 1 +#define SCE_PROPS_SECTION 2 +#define SCE_PROPS_ASSIGNMENT 3 +#define SCE_PROPS_DEFVAL 4 +#define SCE_PROPS_KEY 5 +#define SCE_L_DEFAULT 0 +#define SCE_L_COMMAND 1 +#define SCE_L_TAG 2 +#define SCE_L_MATH 3 +#define SCE_L_COMMENT 4 +#define SCE_LUA_DEFAULT 0 +#define SCE_LUA_COMMENT 1 +#define SCE_LUA_COMMENTLINE 2 +#define SCE_LUA_COMMENTDOC 3 +#define SCE_LUA_NUMBER 4 +#define SCE_LUA_WORD 5 +#define SCE_LUA_STRING 6 +#define SCE_LUA_CHARACTER 7 +#define SCE_LUA_LITERALSTRING 8 +#define SCE_LUA_PREPROCESSOR 9 +#define SCE_LUA_OPERATOR 10 +#define SCE_LUA_IDENTIFIER 11 +#define SCE_LUA_STRINGEOL 12 +#define SCE_LUA_WORD2 13 +#define SCE_LUA_WORD3 14 +#define SCE_LUA_WORD4 15 +#define SCE_LUA_WORD5 16 +#define SCE_LUA_WORD6 17 +#define SCE_LUA_WORD7 18 +#define SCE_LUA_WORD8 19 +#define SCE_ERR_DEFAULT 0 +#define SCE_ERR_PYTHON 1 +#define SCE_ERR_GCC 2 +#define SCE_ERR_MS 3 +#define SCE_ERR_CMD 4 +#define SCE_ERR_BORLAND 5 +#define SCE_ERR_PERL 6 +#define SCE_ERR_NET 7 +#define SCE_ERR_LUA 8 +#define SCE_ERR_CTAG 9 +#define SCE_ERR_DIFF_CHANGED 10 +#define SCE_ERR_DIFF_ADDITION 11 +#define SCE_ERR_DIFF_DELETION 12 +#define SCE_ERR_DIFF_MESSAGE 13 +#define SCE_ERR_PHP 14 +#define SCE_ERR_ELF 15 +#define SCE_ERR_IFC 16 +#define SCE_ERR_IFORT 17 +#define SCE_ERR_ABSF 18 +#define SCE_ERR_TIDY 19 +#define SCE_ERR_JAVA_STACK 20 +#define SCE_ERR_VALUE 21 +#define SCE_BAT_DEFAULT 0 +#define SCE_BAT_COMMENT 1 +#define SCE_BAT_WORD 2 +#define SCE_BAT_LABEL 3 +#define SCE_BAT_HIDE 4 +#define SCE_BAT_COMMAND 5 +#define SCE_BAT_IDENTIFIER 6 +#define SCE_BAT_OPERATOR 7 +#define SCE_MAKE_DEFAULT 0 +#define SCE_MAKE_COMMENT 1 +#define SCE_MAKE_PREPROCESSOR 2 +#define SCE_MAKE_IDENTIFIER 3 +#define SCE_MAKE_OPERATOR 4 +#define SCE_MAKE_TARGET 5 +#define SCE_MAKE_IDEOL 9 +#define SCE_DIFF_DEFAULT 0 +#define SCE_DIFF_COMMENT 1 +#define SCE_DIFF_COMMAND 2 +#define SCE_DIFF_HEADER 3 +#define SCE_DIFF_POSITION 4 +#define SCE_DIFF_DELETED 5 +#define SCE_DIFF_ADDED 6 +#define SCE_DIFF_CHANGED 7 +#define SCE_CONF_DEFAULT 0 +#define SCE_CONF_COMMENT 1 +#define SCE_CONF_NUMBER 2 +#define SCE_CONF_IDENTIFIER 3 +#define SCE_CONF_EXTENSION 4 +#define SCE_CONF_PARAMETER 5 +#define SCE_CONF_STRING 6 +#define SCE_CONF_OPERATOR 7 +#define SCE_CONF_IP 8 +#define SCE_CONF_DIRECTIVE 9 +#define SCE_AVE_DEFAULT 0 +#define SCE_AVE_COMMENT 1 +#define SCE_AVE_NUMBER 2 +#define SCE_AVE_WORD 3 +#define SCE_AVE_STRING 6 +#define SCE_AVE_ENUM 7 +#define SCE_AVE_STRINGEOL 8 +#define SCE_AVE_IDENTIFIER 9 +#define SCE_AVE_OPERATOR 10 +#define SCE_AVE_WORD1 11 +#define SCE_AVE_WORD2 12 +#define SCE_AVE_WORD3 13 +#define SCE_AVE_WORD4 14 +#define SCE_AVE_WORD5 15 +#define SCE_AVE_WORD6 16 +#define SCE_ADA_DEFAULT 0 +#define SCE_ADA_WORD 1 +#define SCE_ADA_IDENTIFIER 2 +#define SCE_ADA_NUMBER 3 +#define SCE_ADA_DELIMITER 4 +#define SCE_ADA_CHARACTER 5 +#define SCE_ADA_CHARACTEREOL 6 +#define SCE_ADA_STRING 7 +#define SCE_ADA_STRINGEOL 8 +#define SCE_ADA_LABEL 9 +#define SCE_ADA_COMMENTLINE 10 +#define SCE_ADA_ILLEGAL 11 +#define SCE_BAAN_DEFAULT 0 +#define SCE_BAAN_COMMENT 1 +#define SCE_BAAN_COMMENTDOC 2 +#define SCE_BAAN_NUMBER 3 +#define SCE_BAAN_WORD 4 +#define SCE_BAAN_STRING 5 +#define SCE_BAAN_PREPROCESSOR 6 +#define SCE_BAAN_OPERATOR 7 +#define SCE_BAAN_IDENTIFIER 8 +#define SCE_BAAN_STRINGEOL 9 +#define SCE_BAAN_WORD2 10 +#define SCE_LISP_DEFAULT 0 +#define SCE_LISP_COMMENT 1 +#define SCE_LISP_NUMBER 2 +#define SCE_LISP_KEYWORD 3 +#define SCE_LISP_KEYWORD_KW 4 +#define SCE_LISP_SYMBOL 5 +#define SCE_LISP_STRING 6 +#define SCE_LISP_STRINGEOL 8 +#define SCE_LISP_IDENTIFIER 9 +#define SCE_LISP_OPERATOR 10 +#define SCE_LISP_SPECIAL 11 +#define SCE_LISP_MULTI_COMMENT 12 +#define SCE_EIFFEL_DEFAULT 0 +#define SCE_EIFFEL_COMMENTLINE 1 +#define SCE_EIFFEL_NUMBER 2 +#define SCE_EIFFEL_WORD 3 +#define SCE_EIFFEL_STRING 4 +#define SCE_EIFFEL_CHARACTER 5 +#define SCE_EIFFEL_OPERATOR 6 +#define SCE_EIFFEL_IDENTIFIER 7 +#define SCE_EIFFEL_STRINGEOL 8 +#define SCE_NNCRONTAB_DEFAULT 0 +#define SCE_NNCRONTAB_COMMENT 1 +#define SCE_NNCRONTAB_TASK 2 +#define SCE_NNCRONTAB_SECTION 3 +#define SCE_NNCRONTAB_KEYWORD 4 +#define SCE_NNCRONTAB_MODIFIER 5 +#define SCE_NNCRONTAB_ASTERISK 6 +#define SCE_NNCRONTAB_NUMBER 7 +#define SCE_NNCRONTAB_STRING 8 +#define SCE_NNCRONTAB_ENVIRONMENT 9 +#define SCE_NNCRONTAB_IDENTIFIER 10 +#define SCE_FORTH_DEFAULT 0 +#define SCE_FORTH_COMMENT 1 +#define SCE_FORTH_COMMENT_ML 2 +#define SCE_FORTH_IDENTIFIER 3 +#define SCE_FORTH_CONTROL 4 +#define SCE_FORTH_KEYWORD 5 +#define SCE_FORTH_DEFWORD 6 +#define SCE_FORTH_PREWORD1 7 +#define SCE_FORTH_PREWORD2 8 +#define SCE_FORTH_NUMBER 9 +#define SCE_FORTH_STRING 10 +#define SCE_FORTH_LOCALE 11 +#define SCE_MATLAB_DEFAULT 0 +#define SCE_MATLAB_COMMENT 1 +#define SCE_MATLAB_COMMAND 2 +#define SCE_MATLAB_NUMBER 3 +#define SCE_MATLAB_KEYWORD 4 +#define SCE_MATLAB_STRING 5 +#define SCE_MATLAB_OPERATOR 6 +#define SCE_MATLAB_IDENTIFIER 7 +#define SCE_MATLAB_DOUBLEQUOTESTRING 8 +#define SCE_SCRIPTOL_DEFAULT 0 +#define SCE_SCRIPTOL_WHITE 1 +#define SCE_SCRIPTOL_COMMENTLINE 2 +#define SCE_SCRIPTOL_PERSISTENT 3 +#define SCE_SCRIPTOL_CSTYLE 4 +#define SCE_SCRIPTOL_COMMENTBLOCK 5 +#define SCE_SCRIPTOL_NUMBER 6 +#define SCE_SCRIPTOL_STRING 7 +#define SCE_SCRIPTOL_CHARACTER 8 +#define SCE_SCRIPTOL_STRINGEOL 9 +#define SCE_SCRIPTOL_KEYWORD 10 +#define SCE_SCRIPTOL_OPERATOR 11 +#define SCE_SCRIPTOL_IDENTIFIER 12 +#define SCE_SCRIPTOL_TRIPLE 13 +#define SCE_SCRIPTOL_CLASSNAME 14 +#define SCE_SCRIPTOL_PREPROCESSOR 15 +#define SCE_ASM_DEFAULT 0 +#define SCE_ASM_COMMENT 1 +#define SCE_ASM_NUMBER 2 +#define SCE_ASM_STRING 3 +#define SCE_ASM_OPERATOR 4 +#define SCE_ASM_IDENTIFIER 5 +#define SCE_ASM_CPUINSTRUCTION 6 +#define SCE_ASM_MATHINSTRUCTION 7 +#define SCE_ASM_REGISTER 8 +#define SCE_ASM_DIRECTIVE 9 +#define SCE_ASM_DIRECTIVEOPERAND 10 +#define SCE_ASM_COMMENTBLOCK 11 +#define SCE_ASM_CHARACTER 12 +#define SCE_ASM_STRINGEOL 13 +#define SCE_ASM_EXTINSTRUCTION 14 +#define SCE_F_DEFAULT 0 +#define SCE_F_COMMENT 1 +#define SCE_F_NUMBER 2 +#define SCE_F_STRING1 3 +#define SCE_F_STRING2 4 +#define SCE_F_STRINGEOL 5 +#define SCE_F_OPERATOR 6 +#define SCE_F_IDENTIFIER 7 +#define SCE_F_WORD 8 +#define SCE_F_WORD2 9 +#define SCE_F_WORD3 10 +#define SCE_F_PREPROCESSOR 11 +#define SCE_F_OPERATOR2 12 +#define SCE_F_LABEL 13 +#define SCE_F_CONTINUATION 14 +#define SCE_CSS_DEFAULT 0 +#define SCE_CSS_TAG 1 +#define SCE_CSS_CLASS 2 +#define SCE_CSS_PSEUDOCLASS 3 +#define SCE_CSS_UNKNOWN_PSEUDOCLASS 4 +#define SCE_CSS_OPERATOR 5 +#define SCE_CSS_IDENTIFIER 6 +#define SCE_CSS_UNKNOWN_IDENTIFIER 7 +#define SCE_CSS_VALUE 8 +#define SCE_CSS_COMMENT 9 +#define SCE_CSS_ID 10 +#define SCE_CSS_IMPORTANT 11 +#define SCE_CSS_DIRECTIVE 12 +#define SCE_CSS_DOUBLESTRING 13 +#define SCE_CSS_SINGLESTRING 14 +#define SCE_CSS_IDENTIFIER2 15 +#define SCE_CSS_ATTRIBUTE 16 +#define SCE_CSS_IDENTIFIER3 17 +#define SCE_CSS_PSEUDOELEMENT 18 +#define SCE_CSS_EXTENDED_IDENTIFIER 19 +#define SCE_CSS_EXTENDED_PSEUDOCLASS 20 +#define SCE_CSS_EXTENDED_PSEUDOELEMENT 21 +#define SCE_CSS_MEDIA 22 +#define SCE_POV_DEFAULT 0 +#define SCE_POV_COMMENT 1 +#define SCE_POV_COMMENTLINE 2 +#define SCE_POV_NUMBER 3 +#define SCE_POV_OPERATOR 4 +#define SCE_POV_IDENTIFIER 5 +#define SCE_POV_STRING 6 +#define SCE_POV_STRINGEOL 7 +#define SCE_POV_DIRECTIVE 8 +#define SCE_POV_BADDIRECTIVE 9 +#define SCE_POV_WORD2 10 +#define SCE_POV_WORD3 11 +#define SCE_POV_WORD4 12 +#define SCE_POV_WORD5 13 +#define SCE_POV_WORD6 14 +#define SCE_POV_WORD7 15 +#define SCE_POV_WORD8 16 +#define SCE_LOUT_DEFAULT 0 +#define SCE_LOUT_COMMENT 1 +#define SCE_LOUT_NUMBER 2 +#define SCE_LOUT_WORD 3 +#define SCE_LOUT_WORD2 4 +#define SCE_LOUT_WORD3 5 +#define SCE_LOUT_WORD4 6 +#define SCE_LOUT_STRING 7 +#define SCE_LOUT_OPERATOR 8 +#define SCE_LOUT_IDENTIFIER 9 +#define SCE_LOUT_STRINGEOL 10 +#define SCE_ESCRIPT_DEFAULT 0 +#define SCE_ESCRIPT_COMMENT 1 +#define SCE_ESCRIPT_COMMENTLINE 2 +#define SCE_ESCRIPT_COMMENTDOC 3 +#define SCE_ESCRIPT_NUMBER 4 +#define SCE_ESCRIPT_WORD 5 +#define SCE_ESCRIPT_STRING 6 +#define SCE_ESCRIPT_OPERATOR 7 +#define SCE_ESCRIPT_IDENTIFIER 8 +#define SCE_ESCRIPT_BRACE 9 +#define SCE_ESCRIPT_WORD2 10 +#define SCE_ESCRIPT_WORD3 11 +#define SCE_PS_DEFAULT 0 +#define SCE_PS_COMMENT 1 +#define SCE_PS_DSC_COMMENT 2 +#define SCE_PS_DSC_VALUE 3 +#define SCE_PS_NUMBER 4 +#define SCE_PS_NAME 5 +#define SCE_PS_KEYWORD 6 +#define SCE_PS_LITERAL 7 +#define SCE_PS_IMMEVAL 8 +#define SCE_PS_PAREN_ARRAY 9 +#define SCE_PS_PAREN_DICT 10 +#define SCE_PS_PAREN_PROC 11 +#define SCE_PS_TEXT 12 +#define SCE_PS_HEXSTRING 13 +#define SCE_PS_BASE85STRING 14 +#define SCE_PS_BADSTRINGCHAR 15 +#define SCE_NSIS_DEFAULT 0 +#define SCE_NSIS_COMMENT 1 +#define SCE_NSIS_STRINGDQ 2 +#define SCE_NSIS_STRINGLQ 3 +#define SCE_NSIS_STRINGRQ 4 +#define SCE_NSIS_FUNCTION 5 +#define SCE_NSIS_VARIABLE 6 +#define SCE_NSIS_LABEL 7 +#define SCE_NSIS_USERDEFINED 8 +#define SCE_NSIS_SECTIONDEF 9 +#define SCE_NSIS_SUBSECTIONDEF 10 +#define SCE_NSIS_IFDEFINEDEF 11 +#define SCE_NSIS_MACRODEF 12 +#define SCE_NSIS_STRINGVAR 13 +#define SCE_NSIS_NUMBER 14 +#define SCE_NSIS_SECTIONGROUP 15 +#define SCE_NSIS_PAGEEX 16 +#define SCE_NSIS_FUNCTIONDEF 17 +#define SCE_NSIS_COMMENTBOX 18 +#define SCE_MMIXAL_LEADWS 0 +#define SCE_MMIXAL_COMMENT 1 +#define SCE_MMIXAL_LABEL 2 +#define SCE_MMIXAL_OPCODE 3 +#define SCE_MMIXAL_OPCODE_PRE 4 +#define SCE_MMIXAL_OPCODE_VALID 5 +#define SCE_MMIXAL_OPCODE_UNKNOWN 6 +#define SCE_MMIXAL_OPCODE_POST 7 +#define SCE_MMIXAL_OPERANDS 8 +#define SCE_MMIXAL_NUMBER 9 +#define SCE_MMIXAL_REF 10 +#define SCE_MMIXAL_CHAR 11 +#define SCE_MMIXAL_STRING 12 +#define SCE_MMIXAL_REGISTER 13 +#define SCE_MMIXAL_HEX 14 +#define SCE_MMIXAL_OPERATOR 15 +#define SCE_MMIXAL_SYMBOL 16 +#define SCE_MMIXAL_INCLUDE 17 +#define SCE_CLW_DEFAULT 0 +#define SCE_CLW_LABEL 1 +#define SCE_CLW_COMMENT 2 +#define SCE_CLW_STRING 3 +#define SCE_CLW_USER_IDENTIFIER 4 +#define SCE_CLW_INTEGER_CONSTANT 5 +#define SCE_CLW_REAL_CONSTANT 6 +#define SCE_CLW_PICTURE_STRING 7 +#define SCE_CLW_KEYWORD 8 +#define SCE_CLW_COMPILER_DIRECTIVE 9 +#define SCE_CLW_RUNTIME_EXPRESSIONS 10 +#define SCE_CLW_BUILTIN_PROCEDURES_FUNCTION 11 +#define SCE_CLW_STRUCTURE_DATA_TYPE 12 +#define SCE_CLW_ATTRIBUTE 13 +#define SCE_CLW_STANDARD_EQUATE 14 +#define SCE_CLW_ERROR 15 +#define SCE_CLW_DEPRECATED 16 +#define SCE_LOT_DEFAULT 0 +#define SCE_LOT_HEADER 1 +#define SCE_LOT_BREAK 2 +#define SCE_LOT_SET 3 +#define SCE_LOT_PASS 4 +#define SCE_LOT_FAIL 5 +#define SCE_LOT_ABORT 6 +#define SCE_YAML_DEFAULT 0 +#define SCE_YAML_COMMENT 1 +#define SCE_YAML_IDENTIFIER 2 +#define SCE_YAML_KEYWORD 3 +#define SCE_YAML_NUMBER 4 +#define SCE_YAML_REFERENCE 5 +#define SCE_YAML_DOCUMENT 6 +#define SCE_YAML_TEXT 7 +#define SCE_YAML_ERROR 8 +#define SCE_YAML_OPERATOR 9 +#define SCE_TEX_DEFAULT 0 +#define SCE_TEX_SPECIAL 1 +#define SCE_TEX_GROUP 2 +#define SCE_TEX_SYMBOL 3 +#define SCE_TEX_COMMAND 4 +#define SCE_TEX_TEXT 5 +#define SCE_METAPOST_DEFAULT 0 +#define SCE_METAPOST_SPECIAL 1 +#define SCE_METAPOST_GROUP 2 +#define SCE_METAPOST_SYMBOL 3 +#define SCE_METAPOST_COMMAND 4 +#define SCE_METAPOST_TEXT 5 +#define SCE_METAPOST_EXTRA 6 +#define SCE_ERLANG_DEFAULT 0 +#define SCE_ERLANG_COMMENT 1 +#define SCE_ERLANG_VARIABLE 2 +#define SCE_ERLANG_NUMBER 3 +#define SCE_ERLANG_KEYWORD 4 +#define SCE_ERLANG_STRING 5 +#define SCE_ERLANG_OPERATOR 6 +#define SCE_ERLANG_ATOM 7 +#define SCE_ERLANG_FUNCTION_NAME 8 +#define SCE_ERLANG_CHARACTER 9 +#define SCE_ERLANG_MACRO 10 +#define SCE_ERLANG_RECORD 11 +#define SCE_ERLANG_PREPROC 12 +#define SCE_ERLANG_NODE_NAME 13 +#define SCE_ERLANG_COMMENT_FUNCTION 14 +#define SCE_ERLANG_COMMENT_MODULE 15 +#define SCE_ERLANG_COMMENT_DOC 16 +#define SCE_ERLANG_COMMENT_DOC_MACRO 17 +#define SCE_ERLANG_ATOM_QUOTED 18 +#define SCE_ERLANG_MACRO_QUOTED 19 +#define SCE_ERLANG_RECORD_QUOTED 20 +#define SCE_ERLANG_NODE_NAME_QUOTED 21 +#define SCE_ERLANG_BIFS 22 +#define SCE_ERLANG_MODULES 23 +#define SCE_ERLANG_MODULES_ATT 24 +#define SCE_ERLANG_UNKNOWN 31 +#define SCE_MSSQL_DEFAULT 0 +#define SCE_MSSQL_COMMENT 1 +#define SCE_MSSQL_LINE_COMMENT 2 +#define SCE_MSSQL_NUMBER 3 +#define SCE_MSSQL_STRING 4 +#define SCE_MSSQL_OPERATOR 5 +#define SCE_MSSQL_IDENTIFIER 6 +#define SCE_MSSQL_VARIABLE 7 +#define SCE_MSSQL_COLUMN_NAME 8 +#define SCE_MSSQL_STATEMENT 9 +#define SCE_MSSQL_DATATYPE 10 +#define SCE_MSSQL_SYSTABLE 11 +#define SCE_MSSQL_GLOBAL_VARIABLE 12 +#define SCE_MSSQL_FUNCTION 13 +#define SCE_MSSQL_STORED_PROCEDURE 14 +#define SCE_MSSQL_DEFAULT_PREF_DATATYPE 15 +#define SCE_MSSQL_COLUMN_NAME_2 16 +#define SCE_V_DEFAULT 0 +#define SCE_V_COMMENT 1 +#define SCE_V_COMMENTLINE 2 +#define SCE_V_COMMENTLINEBANG 3 +#define SCE_V_NUMBER 4 +#define SCE_V_WORD 5 +#define SCE_V_STRING 6 +#define SCE_V_WORD2 7 +#define SCE_V_WORD3 8 +#define SCE_V_PREPROCESSOR 9 +#define SCE_V_OPERATOR 10 +#define SCE_V_IDENTIFIER 11 +#define SCE_V_STRINGEOL 12 +#define SCE_V_USER 19 +#define SCE_KIX_DEFAULT 0 +#define SCE_KIX_COMMENT 1 +#define SCE_KIX_STRING1 2 +#define SCE_KIX_STRING2 3 +#define SCE_KIX_NUMBER 4 +#define SCE_KIX_VAR 5 +#define SCE_KIX_MACRO 6 +#define SCE_KIX_KEYWORD 7 +#define SCE_KIX_FUNCTIONS 8 +#define SCE_KIX_OPERATOR 9 +#define SCE_KIX_IDENTIFIER 31 +#define SCE_GC_DEFAULT 0 +#define SCE_GC_COMMENTLINE 1 +#define SCE_GC_COMMENTBLOCK 2 +#define SCE_GC_GLOBAL 3 +#define SCE_GC_EVENT 4 +#define SCE_GC_ATTRIBUTE 5 +#define SCE_GC_CONTROL 6 +#define SCE_GC_COMMAND 7 +#define SCE_GC_STRING 8 +#define SCE_GC_OPERATOR 9 +#define SCE_SN_DEFAULT 0 +#define SCE_SN_CODE 1 +#define SCE_SN_COMMENTLINE 2 +#define SCE_SN_COMMENTLINEBANG 3 +#define SCE_SN_NUMBER 4 +#define SCE_SN_WORD 5 +#define SCE_SN_STRING 6 +#define SCE_SN_WORD2 7 +#define SCE_SN_WORD3 8 +#define SCE_SN_PREPROCESSOR 9 +#define SCE_SN_OPERATOR 10 +#define SCE_SN_IDENTIFIER 11 +#define SCE_SN_STRINGEOL 12 +#define SCE_SN_REGEXTAG 13 +#define SCE_SN_SIGNAL 14 +#define SCE_SN_USER 19 +#define SCE_AU3_DEFAULT 0 +#define SCE_AU3_COMMENT 1 +#define SCE_AU3_COMMENTBLOCK 2 +#define SCE_AU3_NUMBER 3 +#define SCE_AU3_FUNCTION 4 +#define SCE_AU3_KEYWORD 5 +#define SCE_AU3_MACRO 6 +#define SCE_AU3_STRING 7 +#define SCE_AU3_OPERATOR 8 +#define SCE_AU3_VARIABLE 9 +#define SCE_AU3_SENT 10 +#define SCE_AU3_PREPROCESSOR 11 +#define SCE_AU3_SPECIAL 12 +#define SCE_AU3_EXPAND 13 +#define SCE_AU3_COMOBJ 14 +#define SCE_AU3_UDF 15 +#define SCE_APDL_DEFAULT 0 +#define SCE_APDL_COMMENT 1 +#define SCE_APDL_COMMENTBLOCK 2 +#define SCE_APDL_NUMBER 3 +#define SCE_APDL_STRING 4 +#define SCE_APDL_OPERATOR 5 +#define SCE_APDL_WORD 6 +#define SCE_APDL_PROCESSOR 7 +#define SCE_APDL_COMMAND 8 +#define SCE_APDL_SLASHCOMMAND 9 +#define SCE_APDL_STARCOMMAND 10 +#define SCE_APDL_ARGUMENT 11 +#define SCE_APDL_FUNCTION 12 +#define SCE_SH_DEFAULT 0 +#define SCE_SH_ERROR 1 +#define SCE_SH_COMMENTLINE 2 +#define SCE_SH_NUMBER 3 +#define SCE_SH_WORD 4 +#define SCE_SH_STRING 5 +#define SCE_SH_CHARACTER 6 +#define SCE_SH_OPERATOR 7 +#define SCE_SH_IDENTIFIER 8 +#define SCE_SH_SCALAR 9 +#define SCE_SH_PARAM 10 +#define SCE_SH_BACKTICKS 11 +#define SCE_SH_HERE_DELIM 12 +#define SCE_SH_HERE_Q 13 +#define SCE_ASN1_DEFAULT 0 +#define SCE_ASN1_COMMENT 1 +#define SCE_ASN1_IDENTIFIER 2 +#define SCE_ASN1_STRING 3 +#define SCE_ASN1_OID 4 +#define SCE_ASN1_SCALAR 5 +#define SCE_ASN1_KEYWORD 6 +#define SCE_ASN1_ATTRIBUTE 7 +#define SCE_ASN1_DESCRIPTOR 8 +#define SCE_ASN1_TYPE 9 +#define SCE_ASN1_OPERATOR 10 +#define SCE_VHDL_DEFAULT 0 +#define SCE_VHDL_COMMENT 1 +#define SCE_VHDL_COMMENTLINEBANG 2 +#define SCE_VHDL_NUMBER 3 +#define SCE_VHDL_STRING 4 +#define SCE_VHDL_OPERATOR 5 +#define SCE_VHDL_IDENTIFIER 6 +#define SCE_VHDL_STRINGEOL 7 +#define SCE_VHDL_KEYWORD 8 +#define SCE_VHDL_STDOPERATOR 9 +#define SCE_VHDL_ATTRIBUTE 10 +#define SCE_VHDL_STDFUNCTION 11 +#define SCE_VHDL_STDPACKAGE 12 +#define SCE_VHDL_STDTYPE 13 +#define SCE_VHDL_USERWORD 14 +#define SCE_CAML_DEFAULT 0 +#define SCE_CAML_IDENTIFIER 1 +#define SCE_CAML_TAGNAME 2 +#define SCE_CAML_KEYWORD 3 +#define SCE_CAML_KEYWORD2 4 +#define SCE_CAML_KEYWORD3 5 +#define SCE_CAML_LINENUM 6 +#define SCE_CAML_OPERATOR 7 +#define SCE_CAML_NUMBER 8 +#define SCE_CAML_CHAR 9 +#define SCE_CAML_WHITE 10 +#define SCE_CAML_STRING 11 +#define SCE_CAML_COMMENT 12 +#define SCE_CAML_COMMENT1 13 +#define SCE_CAML_COMMENT2 14 +#define SCE_CAML_COMMENT3 15 +#define SCE_HA_DEFAULT 0 +#define SCE_HA_IDENTIFIER 1 +#define SCE_HA_KEYWORD 2 +#define SCE_HA_NUMBER 3 +#define SCE_HA_STRING 4 +#define SCE_HA_CHARACTER 5 +#define SCE_HA_CLASS 6 +#define SCE_HA_MODULE 7 +#define SCE_HA_CAPITAL 8 +#define SCE_HA_DATA 9 +#define SCE_HA_IMPORT 10 +#define SCE_HA_OPERATOR 11 +#define SCE_HA_INSTANCE 12 +#define SCE_HA_COMMENTLINE 13 +#define SCE_HA_COMMENTBLOCK 14 +#define SCE_HA_COMMENTBLOCK2 15 +#define SCE_HA_COMMENTBLOCK3 16 +#define SCE_T3_DEFAULT 0 +#define SCE_T3_X_DEFAULT 1 +#define SCE_T3_PREPROCESSOR 2 +#define SCE_T3_BLOCK_COMMENT 3 +#define SCE_T3_LINE_COMMENT 4 +#define SCE_T3_OPERATOR 5 +#define SCE_T3_KEYWORD 6 +#define SCE_T3_NUMBER 7 +#define SCE_T3_IDENTIFIER 8 +#define SCE_T3_S_STRING 9 +#define SCE_T3_D_STRING 10 +#define SCE_T3_X_STRING 11 +#define SCE_T3_LIB_DIRECTIVE 12 +#define SCE_T3_MSG_PARAM 13 +#define SCE_T3_HTML_TAG 14 +#define SCE_T3_HTML_DEFAULT 15 +#define SCE_T3_HTML_STRING 16 +#define SCE_T3_USER1 17 +#define SCE_T3_USER2 18 +#define SCE_T3_USER3 19 +#define SCE_T3_BRACE 20 +#define SCE_REBOL_DEFAULT 0 +#define SCE_REBOL_COMMENTLINE 1 +#define SCE_REBOL_COMMENTBLOCK 2 +#define SCE_REBOL_PREFACE 3 +#define SCE_REBOL_OPERATOR 4 +#define SCE_REBOL_CHARACTER 5 +#define SCE_REBOL_QUOTEDSTRING 6 +#define SCE_REBOL_BRACEDSTRING 7 +#define SCE_REBOL_NUMBER 8 +#define SCE_REBOL_PAIR 9 +#define SCE_REBOL_TUPLE 10 +#define SCE_REBOL_BINARY 11 +#define SCE_REBOL_MONEY 12 +#define SCE_REBOL_ISSUE 13 +#define SCE_REBOL_TAG 14 +#define SCE_REBOL_FILE 15 +#define SCE_REBOL_EMAIL 16 +#define SCE_REBOL_URL 17 +#define SCE_REBOL_DATE 18 +#define SCE_REBOL_TIME 19 +#define SCE_REBOL_IDENTIFIER 20 +#define SCE_REBOL_WORD 21 +#define SCE_REBOL_WORD2 22 +#define SCE_REBOL_WORD3 23 +#define SCE_REBOL_WORD4 24 +#define SCE_REBOL_WORD5 25 +#define SCE_REBOL_WORD6 26 +#define SCE_REBOL_WORD7 27 +#define SCE_REBOL_WORD8 28 +#define SCE_SQL_DEFAULT 0 +#define SCE_SQL_COMMENT 1 +#define SCE_SQL_COMMENTLINE 2 +#define SCE_SQL_COMMENTDOC 3 +#define SCE_SQL_NUMBER 4 +#define SCE_SQL_WORD 5 +#define SCE_SQL_STRING 6 +#define SCE_SQL_CHARACTER 7 +#define SCE_SQL_SQLPLUS 8 +#define SCE_SQL_SQLPLUS_PROMPT 9 +#define SCE_SQL_OPERATOR 10 +#define SCE_SQL_IDENTIFIER 11 +#define SCE_SQL_SQLPLUS_COMMENT 13 +#define SCE_SQL_COMMENTLINEDOC 15 +#define SCE_SQL_WORD2 16 +#define SCE_SQL_COMMENTDOCKEYWORD 17 +#define SCE_SQL_COMMENTDOCKEYWORDERROR 18 +#define SCE_SQL_USER1 19 +#define SCE_SQL_USER2 20 +#define SCE_SQL_USER3 21 +#define SCE_SQL_USER4 22 +#define SCE_SQL_QUOTEDIDENTIFIER 23 +#define SCE_ST_DEFAULT 0 +#define SCE_ST_STRING 1 +#define SCE_ST_NUMBER 2 +#define SCE_ST_COMMENT 3 +#define SCE_ST_SYMBOL 4 +#define SCE_ST_BINARY 5 +#define SCE_ST_BOOL 6 +#define SCE_ST_SELF 7 +#define SCE_ST_SUPER 8 +#define SCE_ST_NIL 9 +#define SCE_ST_GLOBAL 10 +#define SCE_ST_RETURN 11 +#define SCE_ST_SPECIAL 12 +#define SCE_ST_KWSEND 13 +#define SCE_ST_ASSIGN 14 +#define SCE_ST_CHARACTER 15 +#define SCE_ST_SPEC_SEL 16 +#define SCE_FS_DEFAULT 0 +#define SCE_FS_COMMENT 1 +#define SCE_FS_COMMENTLINE 2 +#define SCE_FS_COMMENTDOC 3 +#define SCE_FS_COMMENTLINEDOC 4 +#define SCE_FS_COMMENTDOCKEYWORD 5 +#define SCE_FS_COMMENTDOCKEYWORDERROR 6 +#define SCE_FS_KEYWORD 7 +#define SCE_FS_KEYWORD2 8 +#define SCE_FS_KEYWORD3 9 +#define SCE_FS_KEYWORD4 10 +#define SCE_FS_NUMBER 11 +#define SCE_FS_STRING 12 +#define SCE_FS_PREPROCESSOR 13 +#define SCE_FS_OPERATOR 14 +#define SCE_FS_IDENTIFIER 15 +#define SCE_FS_DATE 16 +#define SCE_FS_STRINGEOL 17 +#define SCE_FS_CONSTANT 18 +#define SCE_FS_WORDOPERATOR 19 +#define SCE_FS_DISABLEDCODE 20 +#define SCE_FS_DEFAULT_C 21 +#define SCE_FS_COMMENTDOC_C 22 +#define SCE_FS_COMMENTLINEDOC_C 23 +#define SCE_FS_KEYWORD_C 24 +#define SCE_FS_KEYWORD2_C 25 +#define SCE_FS_NUMBER_C 26 +#define SCE_FS_STRING_C 27 +#define SCE_FS_PREPROCESSOR_C 28 +#define SCE_FS_OPERATOR_C 29 +#define SCE_FS_IDENTIFIER_C 30 +#define SCE_FS_STRINGEOL_C 31 +#define SCE_CSOUND_DEFAULT 0 +#define SCE_CSOUND_COMMENT 1 +#define SCE_CSOUND_NUMBER 2 +#define SCE_CSOUND_OPERATOR 3 +#define SCE_CSOUND_INSTR 4 +#define SCE_CSOUND_IDENTIFIER 5 +#define SCE_CSOUND_OPCODE 6 +#define SCE_CSOUND_HEADERSTMT 7 +#define SCE_CSOUND_USERKEYWORD 8 +#define SCE_CSOUND_COMMENTBLOCK 9 +#define SCE_CSOUND_PARAM 10 +#define SCE_CSOUND_ARATE_VAR 11 +#define SCE_CSOUND_KRATE_VAR 12 +#define SCE_CSOUND_IRATE_VAR 13 +#define SCE_CSOUND_GLOBAL_VAR 14 +#define SCE_CSOUND_STRINGEOL 15 +#define SCE_INNO_DEFAULT 0 +#define SCE_INNO_COMMENT 1 +#define SCE_INNO_KEYWORD 2 +#define SCE_INNO_PARAMETER 3 +#define SCE_INNO_SECTION 4 +#define SCE_INNO_PREPROC 5 +#define SCE_INNO_INLINE_EXPANSION 6 +#define SCE_INNO_COMMENT_PASCAL 7 +#define SCE_INNO_KEYWORD_PASCAL 8 +#define SCE_INNO_KEYWORD_USER 9 +#define SCE_INNO_STRING_DOUBLE 10 +#define SCE_INNO_STRING_SINGLE 11 +#define SCE_INNO_IDENTIFIER 12 +#define SCE_OPAL_SPACE 0 +#define SCE_OPAL_COMMENT_BLOCK 1 +#define SCE_OPAL_COMMENT_LINE 2 +#define SCE_OPAL_INTEGER 3 +#define SCE_OPAL_KEYWORD 4 +#define SCE_OPAL_SORT 5 +#define SCE_OPAL_STRING 6 +#define SCE_OPAL_PAR 7 +#define SCE_OPAL_BOOL_CONST 8 +#define SCE_OPAL_DEFAULT 32 +#define SCE_SPICE_DEFAULT 0 +#define SCE_SPICE_IDENTIFIER 1 +#define SCE_SPICE_KEYWORD 2 +#define SCE_SPICE_KEYWORD2 3 +#define SCE_SPICE_KEYWORD3 4 +#define SCE_SPICE_NUMBER 5 +#define SCE_SPICE_DELIMITER 6 +#define SCE_SPICE_VALUE 7 +#define SCE_SPICE_COMMENTLINE 8 +#define SCE_CMAKE_DEFAULT 0 +#define SCE_CMAKE_COMMENT 1 +#define SCE_CMAKE_STRINGDQ 2 +#define SCE_CMAKE_STRINGLQ 3 +#define SCE_CMAKE_STRINGRQ 4 +#define SCE_CMAKE_COMMANDS 5 +#define SCE_CMAKE_PARAMETERS 6 +#define SCE_CMAKE_VARIABLE 7 +#define SCE_CMAKE_USERDEFINED 8 +#define SCE_CMAKE_WHILEDEF 9 +#define SCE_CMAKE_FOREACHDEF 10 +#define SCE_CMAKE_IFDEFINEDEF 11 +#define SCE_CMAKE_MACRODEF 12 +#define SCE_CMAKE_STRINGVAR 13 +#define SCE_CMAKE_NUMBER 14 +#define SCE_GAP_DEFAULT 0 +#define SCE_GAP_IDENTIFIER 1 +#define SCE_GAP_KEYWORD 2 +#define SCE_GAP_KEYWORD2 3 +#define SCE_GAP_KEYWORD3 4 +#define SCE_GAP_KEYWORD4 5 +#define SCE_GAP_STRING 6 +#define SCE_GAP_CHAR 7 +#define SCE_GAP_OPERATOR 8 +#define SCE_GAP_COMMENT 9 +#define SCE_GAP_NUMBER 10 +#define SCE_GAP_STRINGEOL 11 +#define SCE_PLM_DEFAULT 0 +#define SCE_PLM_COMMENT 1 +#define SCE_PLM_STRING 2 +#define SCE_PLM_NUMBER 3 +#define SCE_PLM_IDENTIFIER 4 +#define SCE_PLM_OPERATOR 5 +#define SCE_PLM_CONTROL 6 +#define SCE_PLM_KEYWORD 7 +#define SCE_4GL_DEFAULT 0 +#define SCE_4GL_NUMBER 1 +#define SCE_4GL_WORD 2 +#define SCE_4GL_STRING 3 +#define SCE_4GL_CHARACTER 4 +#define SCE_4GL_PREPROCESSOR 5 +#define SCE_4GL_OPERATOR 6 +#define SCE_4GL_IDENTIFIER 7 +#define SCE_4GL_BLOCK 8 +#define SCE_4GL_END 9 +#define SCE_4GL_COMMENT1 10 +#define SCE_4GL_COMMENT2 11 +#define SCE_4GL_COMMENT3 12 +#define SCE_4GL_COMMENT4 13 +#define SCE_4GL_COMMENT5 14 +#define SCE_4GL_COMMENT6 15 +#define SCE_4GL_DEFAULT_ 16 +#define SCE_4GL_NUMBER_ 17 +#define SCE_4GL_WORD_ 18 +#define SCE_4GL_STRING_ 19 +#define SCE_4GL_CHARACTER_ 20 +#define SCE_4GL_PREPROCESSOR_ 21 +#define SCE_4GL_OPERATOR_ 22 +#define SCE_4GL_IDENTIFIER_ 23 +#define SCE_4GL_BLOCK_ 24 +#define SCE_4GL_END_ 25 +#define SCE_4GL_COMMENT1_ 26 +#define SCE_4GL_COMMENT2_ 27 +#define SCE_4GL_COMMENT3_ 28 +#define SCE_4GL_COMMENT4_ 29 +#define SCE_4GL_COMMENT5_ 30 +#define SCE_4GL_COMMENT6_ 31 +#define SCE_ABAQUS_DEFAULT 0 +#define SCE_ABAQUS_COMMENT 1 +#define SCE_ABAQUS_COMMENTBLOCK 2 +#define SCE_ABAQUS_NUMBER 3 +#define SCE_ABAQUS_STRING 4 +#define SCE_ABAQUS_OPERATOR 5 +#define SCE_ABAQUS_WORD 6 +#define SCE_ABAQUS_PROCESSOR 7 +#define SCE_ABAQUS_COMMAND 8 +#define SCE_ABAQUS_SLASHCOMMAND 9 +#define SCE_ABAQUS_STARCOMMAND 10 +#define SCE_ABAQUS_ARGUMENT 11 +#define SCE_ABAQUS_FUNCTION 12 +#define SCE_ASY_DEFAULT 0 +#define SCE_ASY_COMMENT 1 +#define SCE_ASY_COMMENTLINE 2 +#define SCE_ASY_NUMBER 3 +#define SCE_ASY_WORD 4 +#define SCE_ASY_STRING 5 +#define SCE_ASY_CHARACTER 6 +#define SCE_ASY_OPERATOR 7 +#define SCE_ASY_IDENTIFIER 8 +#define SCE_ASY_STRINGEOL 9 +#define SCE_ASY_COMMENTLINEDOC 10 +#define SCE_ASY_WORD2 11 +#define SCE_R_DEFAULT 0 +#define SCE_R_COMMENT 1 +#define SCE_R_KWORD 2 +#define SCE_R_BASEKWORD 3 +#define SCE_R_OTHERKWORD 4 +#define SCE_R_NUMBER 5 +#define SCE_R_STRING 6 +#define SCE_R_STRING2 7 +#define SCE_R_OPERATOR 8 +#define SCE_R_IDENTIFIER 9 +#define SCE_R_INFIX 10 +#define SCE_R_INFIXEOL 11 +#define SCE_MAGIK_DEFAULT 0 +#define SCE_MAGIK_COMMENT 1 +#define SCE_MAGIK_HYPER_COMMENT 16 +#define SCE_MAGIK_STRING 2 +#define SCE_MAGIK_CHARACTER 3 +#define SCE_MAGIK_NUMBER 4 +#define SCE_MAGIK_IDENTIFIER 5 +#define SCE_MAGIK_OPERATOR 6 +#define SCE_MAGIK_FLOW 7 +#define SCE_MAGIK_CONTAINER 8 +#define SCE_MAGIK_BRACKET_BLOCK 9 +#define SCE_MAGIK_BRACE_BLOCK 10 +#define SCE_MAGIK_SQBRACKET_BLOCK 11 +#define SCE_MAGIK_UNKNOWN_KEYWORD 12 +#define SCE_MAGIK_KEYWORD 13 +#define SCE_MAGIK_PRAGMA 14 +#define SCE_MAGIK_SYMBOL 15 +#define SCE_POWERSHELL_DEFAULT 0 +#define SCE_POWERSHELL_COMMENT 1 +#define SCE_POWERSHELL_STRING 2 +#define SCE_POWERSHELL_CHARACTER 3 +#define SCE_POWERSHELL_NUMBER 4 +#define SCE_POWERSHELL_VARIABLE 5 +#define SCE_POWERSHELL_OPERATOR 6 +#define SCE_POWERSHELL_IDENTIFIER 7 +#define SCE_POWERSHELL_KEYWORD 8 +#define SCE_POWERSHELL_CMDLET 9 +#define SCE_POWERSHELL_ALIAS 10 +#define SCE_MYSQL_DEFAULT 0 +#define SCE_MYSQL_COMMENT 1 +#define SCE_MYSQL_COMMENTLINE 2 +#define SCE_MYSQL_VARIABLE 3 +#define SCE_MYSQL_SYSTEMVARIABLE 4 +#define SCE_MYSQL_KNOWNSYSTEMVARIABLE 5 +#define SCE_MYSQL_NUMBER 6 +#define SCE_MYSQL_MAJORKEYWORD 7 +#define SCE_MYSQL_KEYWORD 8 +#define SCE_MYSQL_DATABASEOBJECT 9 +#define SCE_MYSQL_PROCEDUREKEYWORD 10 +#define SCE_MYSQL_STRING 11 +#define SCE_MYSQL_SQSTRING 12 +#define SCE_MYSQL_DQSTRING 13 +#define SCE_MYSQL_OPERATOR 14 +#define SCE_MYSQL_FUNCTION 15 +#define SCE_MYSQL_IDENTIFIER 16 +#define SCE_MYSQL_QUOTEDIDENTIFIER 17 +#define SCE_MYSQL_USER1 18 +#define SCE_MYSQL_USER2 19 +#define SCE_MYSQL_USER3 20 +#define SCE_MYSQL_HIDDENCOMMAND 21 +#define SCE_PO_DEFAULT 0 +#define SCE_PO_COMMENT 1 +#define SCE_PO_MSGID 2 +#define SCE_PO_MSGID_TEXT 3 +#define SCE_PO_MSGSTR 4 +#define SCE_PO_MSGSTR_TEXT 5 +#define SCE_PO_MSGCTXT 6 +#define SCE_PO_MSGCTXT_TEXT 7 +#define SCE_PO_FUZZY 8 +#define SCE_PAS_DEFAULT 0 +#define SCE_PAS_IDENTIFIER 1 +#define SCE_PAS_COMMENT 2 +#define SCE_PAS_COMMENT2 3 +#define SCE_PAS_COMMENTLINE 4 +#define SCE_PAS_PREPROCESSOR 5 +#define SCE_PAS_PREPROCESSOR2 6 +#define SCE_PAS_NUMBER 7 +#define SCE_PAS_HEXNUMBER 8 +#define SCE_PAS_WORD 9 +#define SCE_PAS_STRING 10 +#define SCE_PAS_STRINGEOL 11 +#define SCE_PAS_CHARACTER 12 +#define SCE_PAS_OPERATOR 13 +#define SCE_PAS_ASM 14 +#define SCE_SORCUS_DEFAULT 0 +#define SCE_SORCUS_COMMAND 1 +#define SCE_SORCUS_PARAMETER 2 +#define SCE_SORCUS_COMMENTLINE 3 +#define SCE_SORCUS_STRING 4 +#define SCE_SORCUS_STRINGEOL 5 +#define SCE_SORCUS_IDENTIFIER 6 +#define SCE_SORCUS_OPERATOR 7 +#define SCE_SORCUS_NUMBER 8 +#define SCE_SORCUS_CONSTANT 9 +#define SCE_POWERPRO_DEFAULT 0 +#define SCE_POWERPRO_COMMENTBLOCK 1 +#define SCE_POWERPRO_COMMENTLINE 2 +#define SCE_POWERPRO_NUMBER 3 +#define SCE_POWERPRO_WORD 4 +#define SCE_POWERPRO_WORD2 5 +#define SCE_POWERPRO_WORD3 6 +#define SCE_POWERPRO_WORD4 7 +#define SCE_POWERPRO_DOUBLEQUOTEDSTRING 8 +#define SCE_POWERPRO_SINGLEQUOTEDSTRING 9 +#define SCE_POWERPRO_LINECONTINUE 10 +#define SCE_POWERPRO_OPERATOR 11 +#define SCE_POWERPRO_IDENTIFIER 12 +#define SCE_POWERPRO_STRINGEOL 13 +#define SCE_POWERPRO_VERBATIM 14 +#define SCE_POWERPRO_ALTQUOTE 15 +#define SCE_POWERPRO_FUNCTION 16 +#define SCE_SML_DEFAULT 0 +#define SCE_SML_IDENTIFIER 1 +#define SCE_SML_TAGNAME 2 +#define SCE_SML_KEYWORD 3 +#define SCE_SML_KEYWORD2 4 +#define SCE_SML_KEYWORD3 5 +#define SCE_SML_LINENUM 6 +#define SCE_SML_OPERATOR 7 +#define SCE_SML_NUMBER 8 +#define SCE_SML_CHAR 9 +#define SCE_SML_STRING 11 +#define SCE_SML_COMMENT 12 +#define SCE_SML_COMMENT1 13 +#define SCE_SML_COMMENT2 14 +#define SCE_SML_COMMENT3 15 +#define SCE_MARKDOWN_DEFAULT 0 +#define SCE_MARKDOWN_LINE_BEGIN 1 +#define SCE_MARKDOWN_STRONG1 2 +#define SCE_MARKDOWN_STRONG2 3 +#define SCE_MARKDOWN_EM1 4 +#define SCE_MARKDOWN_EM2 5 +#define SCE_MARKDOWN_HEADER1 6 +#define SCE_MARKDOWN_HEADER2 7 +#define SCE_MARKDOWN_HEADER3 8 +#define SCE_MARKDOWN_HEADER4 9 +#define SCE_MARKDOWN_HEADER5 10 +#define SCE_MARKDOWN_HEADER6 11 +#define SCE_MARKDOWN_PRECHAR 12 +#define SCE_MARKDOWN_ULIST_ITEM 13 +#define SCE_MARKDOWN_OLIST_ITEM 14 +#define SCE_MARKDOWN_BLOCKQUOTE 15 +#define SCE_MARKDOWN_STRIKEOUT 16 +#define SCE_MARKDOWN_HRULE 17 +#define SCE_MARKDOWN_LINK 18 +#define SCE_MARKDOWN_CODE 19 +#define SCE_MARKDOWN_CODE2 20 +#define SCE_MARKDOWN_CODEBK 21 +/* --Autogenerated -- end of section automatically generated from Scintilla.iface */ + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Scintilla.h b/harbour/contrib/hbide/qscintilla/Scintilla.h new file mode 100644 index 0000000000..0e7e7ecf0a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Scintilla.h @@ -0,0 +1,891 @@ +/* Scintilla source code edit control */ +/** @file Scintilla.h + ** Interface to the edit control. + **/ +/* Copyright 1998-2003 by Neil Hodgson + * The License.txt file describes the conditions under which this software may be distributed. */ + +/* Most of this file is automatically generated from the Scintilla.iface interface definition + * file which contains any comments about the definitions. HFacer.py does the generation. */ + +#ifndef SCINTILLA_H +#define SCINTILLA_H + +#if LCCWIN +typedef BOOL bool; +#endif + +#if PLAT_WIN +/* Return false on failure: */ +bool Scintilla_RegisterClasses(void *hInstance); +bool Scintilla_ReleaseResources(); +#endif +int Scintilla_LinkLexers(); + +/* Here should be placed typedefs for uptr_t, an unsigned integer type large enough to + * hold a pointer and sptr_t, a signed integer large enough to hold a pointer. + * May need to be changed for 64 bit platforms. */ +#if defined(_WIN32) +#include +#endif +#ifdef MAXULONG_PTR +typedef ULONG_PTR uptr_t; +typedef LONG_PTR sptr_t; +#else +typedef unsigned long uptr_t; +typedef long sptr_t; +#endif + +typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam); + +/* ++Autogenerated -- start of section automatically generated from Scintilla.iface */ +#define INVALID_POSITION -1 +#define SCI_START 2000 +#define SCI_OPTIONAL_START 3000 +#define SCI_LEXER_START 4000 +#define SCI_ADDTEXT 2001 +#define SCI_ADDSTYLEDTEXT 2002 +#define SCI_INSERTTEXT 2003 +#define SCI_CLEARALL 2004 +#define SCI_CLEARDOCUMENTSTYLE 2005 +#define SCI_GETLENGTH 2006 +#define SCI_GETCHARAT 2007 +#define SCI_GETCURRENTPOS 2008 +#define SCI_GETANCHOR 2009 +#define SCI_GETSTYLEAT 2010 +#define SCI_REDO 2011 +#define SCI_SETUNDOCOLLECTION 2012 +#define SCI_SELECTALL 2013 +#define SCI_SETSAVEPOINT 2014 +#define SCI_GETSTYLEDTEXT 2015 +#define SCI_CANREDO 2016 +#define SCI_MARKERLINEFROMHANDLE 2017 +#define SCI_MARKERDELETEHANDLE 2018 +#define SCI_GETUNDOCOLLECTION 2019 +#define SCWS_INVISIBLE 0 +#define SCWS_VISIBLEALWAYS 1 +#define SCWS_VISIBLEAFTERINDENT 2 +#define SCI_GETVIEWWS 2020 +#define SCI_SETVIEWWS 2021 +#define SCI_POSITIONFROMPOINT 2022 +#define SCI_POSITIONFROMPOINTCLOSE 2023 +#define SCI_GOTOLINE 2024 +#define SCI_GOTOPOS 2025 +#define SCI_SETANCHOR 2026 +#define SCI_GETCURLINE 2027 +#define SCI_GETENDSTYLED 2028 +#define SC_EOL_CRLF 0 +#define SC_EOL_CR 1 +#define SC_EOL_LF 2 +#define SCI_CONVERTEOLS 2029 +#define SCI_GETEOLMODE 2030 +#define SCI_SETEOLMODE 2031 +#define SCI_STARTSTYLING 2032 +#define SCI_SETSTYLING 2033 +#define SCI_GETBUFFEREDDRAW 2034 +#define SCI_SETBUFFEREDDRAW 2035 +#define SCI_SETTABWIDTH 2036 +#define SCI_GETTABWIDTH 2121 +#define SC_CP_UTF8 65001 +#define SC_CP_DBCS 1 +#define SCI_SETCODEPAGE 2037 +#define SCI_SETUSEPALETTE 2039 +#define MARKER_MAX 31 +#define SC_MARK_CIRCLE 0 +#define SC_MARK_ROUNDRECT 1 +#define SC_MARK_ARROW 2 +#define SC_MARK_SMALLRECT 3 +#define SC_MARK_SHORTARROW 4 +#define SC_MARK_EMPTY 5 +#define SC_MARK_ARROWDOWN 6 +#define SC_MARK_MINUS 7 +#define SC_MARK_PLUS 8 +#define SC_MARK_VLINE 9 +#define SC_MARK_LCORNER 10 +#define SC_MARK_TCORNER 11 +#define SC_MARK_BOXPLUS 12 +#define SC_MARK_BOXPLUSCONNECTED 13 +#define SC_MARK_BOXMINUS 14 +#define SC_MARK_BOXMINUSCONNECTED 15 +#define SC_MARK_LCORNERCURVE 16 +#define SC_MARK_TCORNERCURVE 17 +#define SC_MARK_CIRCLEPLUS 18 +#define SC_MARK_CIRCLEPLUSCONNECTED 19 +#define SC_MARK_CIRCLEMINUS 20 +#define SC_MARK_CIRCLEMINUSCONNECTED 21 +#define SC_MARK_BACKGROUND 22 +#define SC_MARK_DOTDOTDOT 23 +#define SC_MARK_ARROWS 24 +#define SC_MARK_PIXMAP 25 +#define SC_MARK_FULLRECT 26 +#define SC_MARK_LEFTRECT 27 +#define SC_MARK_AVAILABLE 28 +#define SC_MARK_CHARACTER 10000 +#define SC_MARKNUM_FOLDEREND 25 +#define SC_MARKNUM_FOLDEROPENMID 26 +#define SC_MARKNUM_FOLDERMIDTAIL 27 +#define SC_MARKNUM_FOLDERTAIL 28 +#define SC_MARKNUM_FOLDERSUB 29 +#define SC_MARKNUM_FOLDER 30 +#define SC_MARKNUM_FOLDEROPEN 31 +#define SC_MASK_FOLDERS 0xFE000000 +#define SCI_MARKERDEFINE 2040 +#define SCI_MARKERSETFORE 2041 +#define SCI_MARKERSETBACK 2042 +#define SCI_MARKERADD 2043 +#define SCI_MARKERDELETE 2044 +#define SCI_MARKERDELETEALL 2045 +#define SCI_MARKERGET 2046 +#define SCI_MARKERNEXT 2047 +#define SCI_MARKERPREVIOUS 2048 +#define SCI_MARKERDEFINEPIXMAP 2049 +#define SCI_MARKERADDSET 2466 +#define SCI_MARKERSETALPHA 2476 +#define SC_MARGIN_SYMBOL 0 +#define SC_MARGIN_NUMBER 1 +#define SC_MARGIN_BACK 2 +#define SC_MARGIN_FORE 3 +#define SC_MARGIN_TEXT 4 +#define SC_MARGIN_RTEXT 5 +#define SCI_SETMARGINTYPEN 2240 +#define SCI_GETMARGINTYPEN 2241 +#define SCI_SETMARGINWIDTHN 2242 +#define SCI_GETMARGINWIDTHN 2243 +#define SCI_SETMARGINMASKN 2244 +#define SCI_GETMARGINMASKN 2245 +#define SCI_SETMARGINSENSITIVEN 2246 +#define SCI_GETMARGINSENSITIVEN 2247 +#define STYLE_DEFAULT 32 +#define STYLE_LINENUMBER 33 +#define STYLE_BRACELIGHT 34 +#define STYLE_BRACEBAD 35 +#define STYLE_CONTROLCHAR 36 +#define STYLE_INDENTGUIDE 37 +#define STYLE_CALLTIP 38 +#define STYLE_LASTPREDEFINED 39 +#define STYLE_MAX 255 +#define SC_CHARSET_ANSI 0 +#define SC_CHARSET_DEFAULT 1 +#define SC_CHARSET_BALTIC 186 +#define SC_CHARSET_CHINESEBIG5 136 +#define SC_CHARSET_EASTEUROPE 238 +#define SC_CHARSET_GB2312 134 +#define SC_CHARSET_GREEK 161 +#define SC_CHARSET_HANGUL 129 +#define SC_CHARSET_MAC 77 +#define SC_CHARSET_OEM 255 +#define SC_CHARSET_RUSSIAN 204 +#define SC_CHARSET_CYRILLIC 1251 +#define SC_CHARSET_SHIFTJIS 128 +#define SC_CHARSET_SYMBOL 2 +#define SC_CHARSET_TURKISH 162 +#define SC_CHARSET_JOHAB 130 +#define SC_CHARSET_HEBREW 177 +#define SC_CHARSET_ARABIC 178 +#define SC_CHARSET_VIETNAMESE 163 +#define SC_CHARSET_THAI 222 +#define SC_CHARSET_8859_15 1000 +#define SCI_STYLECLEARALL 2050 +#define SCI_STYLESETFORE 2051 +#define SCI_STYLESETBACK 2052 +#define SCI_STYLESETBOLD 2053 +#define SCI_STYLESETITALIC 2054 +#define SCI_STYLESETSIZE 2055 +#define SCI_STYLESETFONT 2056 +#define SCI_STYLESETEOLFILLED 2057 +#define SCI_STYLERESETDEFAULT 2058 +#define SCI_STYLESETUNDERLINE 2059 +#define SC_CASE_MIXED 0 +#define SC_CASE_UPPER 1 +#define SC_CASE_LOWER 2 +#define SCI_STYLEGETFORE 2481 +#define SCI_STYLEGETBACK 2482 +#define SCI_STYLEGETBOLD 2483 +#define SCI_STYLEGETITALIC 2484 +#define SCI_STYLEGETSIZE 2485 +#define SCI_STYLEGETFONT 2486 +#define SCI_STYLEGETEOLFILLED 2487 +#define SCI_STYLEGETUNDERLINE 2488 +#define SCI_STYLEGETCASE 2489 +#define SCI_STYLEGETCHARACTERSET 2490 +#define SCI_STYLEGETVISIBLE 2491 +#define SCI_STYLEGETCHANGEABLE 2492 +#define SCI_STYLEGETHOTSPOT 2493 +#define SCI_STYLESETCASE 2060 +#define SCI_STYLESETCHARACTERSET 2066 +#define SCI_STYLESETHOTSPOT 2409 +#define SCI_SETSELFORE 2067 +#define SCI_SETSELBACK 2068 +#define SCI_GETSELALPHA 2477 +#define SCI_SETSELALPHA 2478 +#define SCI_GETSELEOLFILLED 2479 +#define SCI_SETSELEOLFILLED 2480 +#define SCI_SETCARETFORE 2069 +#define SCI_ASSIGNCMDKEY 2070 +#define SCI_CLEARCMDKEY 2071 +#define SCI_CLEARALLCMDKEYS 2072 +#define SCI_SETSTYLINGEX 2073 +#define SCI_STYLESETVISIBLE 2074 +#define SCI_GETCARETPERIOD 2075 +#define SCI_SETCARETPERIOD 2076 +#define SCI_SETWORDCHARS 2077 +#define SCI_BEGINUNDOACTION 2078 +#define SCI_ENDUNDOACTION 2079 +#define INDIC_PLAIN 0 +#define INDIC_SQUIGGLE 1 +#define INDIC_TT 2 +#define INDIC_DIAGONAL 3 +#define INDIC_STRIKE 4 +#define INDIC_HIDDEN 5 +#define INDIC_BOX 6 +#define INDIC_ROUNDBOX 7 +#define INDIC_MAX 31 +#define INDIC_CONTAINER 8 +#define INDIC0_MASK 0x20 +#define INDIC1_MASK 0x40 +#define INDIC2_MASK 0x80 +#define INDICS_MASK 0xE0 +#define SCI_INDICSETSTYLE 2080 +#define SCI_INDICGETSTYLE 2081 +#define SCI_INDICSETFORE 2082 +#define SCI_INDICGETFORE 2083 +#define SCI_INDICSETUNDER 2510 +#define SCI_INDICGETUNDER 2511 +#define SCI_SETWHITESPACEFORE 2084 +#define SCI_SETWHITESPACEBACK 2085 +#define SCI_SETSTYLEBITS 2090 +#define SCI_GETSTYLEBITS 2091 +#define SCI_SETLINESTATE 2092 +#define SCI_GETLINESTATE 2093 +#define SCI_GETMAXLINESTATE 2094 +#define SCI_GETCARETLINEVISIBLE 2095 +#define SCI_SETCARETLINEVISIBLE 2096 +#define SCI_GETCARETLINEBACK 2097 +#define SCI_SETCARETLINEBACK 2098 +#define SCI_STYLESETCHANGEABLE 2099 +#define SCI_AUTOCSHOW 2100 +#define SCI_AUTOCCANCEL 2101 +#define SCI_AUTOCACTIVE 2102 +#define SCI_AUTOCPOSSTART 2103 +#define SCI_AUTOCCOMPLETE 2104 +#define SCI_AUTOCSTOPS 2105 +#define SCI_AUTOCSETSEPARATOR 2106 +#define SCI_AUTOCGETSEPARATOR 2107 +#define SCI_AUTOCSELECT 2108 +#define SCI_AUTOCSETCANCELATSTART 2110 +#define SCI_AUTOCGETCANCELATSTART 2111 +#define SCI_AUTOCSETFILLUPS 2112 +#define SCI_AUTOCSETCHOOSESINGLE 2113 +#define SCI_AUTOCGETCHOOSESINGLE 2114 +#define SCI_AUTOCSETIGNORECASE 2115 +#define SCI_AUTOCGETIGNORECASE 2116 +#define SCI_USERLISTSHOW 2117 +#define SCI_AUTOCSETAUTOHIDE 2118 +#define SCI_AUTOCGETAUTOHIDE 2119 +#define SCI_AUTOCSETDROPRESTOFWORD 2270 +#define SCI_AUTOCGETDROPRESTOFWORD 2271 +#define SCI_REGISTERIMAGE 2405 +#define SCI_CLEARREGISTEREDIMAGES 2408 +#define SCI_AUTOCGETTYPESEPARATOR 2285 +#define SCI_AUTOCSETTYPESEPARATOR 2286 +#define SCI_AUTOCSETMAXWIDTH 2208 +#define SCI_AUTOCGETMAXWIDTH 2209 +#define SCI_AUTOCSETMAXHEIGHT 2210 +#define SCI_AUTOCGETMAXHEIGHT 2211 +#define SCI_SETINDENT 2122 +#define SCI_GETINDENT 2123 +#define SCI_SETUSETABS 2124 +#define SCI_GETUSETABS 2125 +#define SCI_SETLINEINDENTATION 2126 +#define SCI_GETLINEINDENTATION 2127 +#define SCI_GETLINEINDENTPOSITION 2128 +#define SCI_GETCOLUMN 2129 +#define SCI_SETHSCROLLBAR 2130 +#define SCI_GETHSCROLLBAR 2131 +#define SC_IV_NONE 0 +#define SC_IV_REAL 1 +#define SC_IV_LOOKFORWARD 2 +#define SC_IV_LOOKBOTH 3 +#define SCI_SETINDENTATIONGUIDES 2132 +#define SCI_GETINDENTATIONGUIDES 2133 +#define SCI_SETHIGHLIGHTGUIDE 2134 +#define SCI_GETHIGHLIGHTGUIDE 2135 +#define SCI_GETLINEENDPOSITION 2136 +#define SCI_GETCODEPAGE 2137 +#define SCI_GETCARETFORE 2138 +#define SCI_GETUSEPALETTE 2139 +#define SCI_GETREADONLY 2140 +#define SCI_SETCURRENTPOS 2141 +#define SCI_SETSELECTIONSTART 2142 +#define SCI_GETSELECTIONSTART 2143 +#define SCI_SETSELECTIONEND 2144 +#define SCI_GETSELECTIONEND 2145 +#define SCI_SETPRINTMAGNIFICATION 2146 +#define SCI_GETPRINTMAGNIFICATION 2147 +#define SC_PRINT_NORMAL 0 +#define SC_PRINT_INVERTLIGHT 1 +#define SC_PRINT_BLACKONWHITE 2 +#define SC_PRINT_COLOURONWHITE 3 +#define SC_PRINT_COLOURONWHITEDEFAULTBG 4 +#define SCI_SETPRINTCOLOURMODE 2148 +#define SCI_GETPRINTCOLOURMODE 2149 +#define SCFIND_WHOLEWORD 2 +#define SCFIND_MATCHCASE 4 +#define SCFIND_WORDSTART 0x00100000 +#define SCFIND_REGEXP 0x00200000 +#define SCFIND_POSIX 0x00400000 +#define SCI_FINDTEXT 2150 +#define SCI_FORMATRANGE 2151 +#define SCI_GETFIRSTVISIBLELINE 2152 +#define SCI_GETLINE 2153 +#define SCI_GETLINECOUNT 2154 +#define SCI_SETMARGINLEFT 2155 +#define SCI_GETMARGINLEFT 2156 +#define SCI_SETMARGINRIGHT 2157 +#define SCI_GETMARGINRIGHT 2158 +#define SCI_GETMODIFY 2159 +#define SCI_SETSEL 2160 +#define SCI_GETSELTEXT 2161 +#define SCI_GETTEXTRANGE 2162 +#define SCI_HIDESELECTION 2163 +#define SCI_POINTXFROMPOSITION 2164 +#define SCI_POINTYFROMPOSITION 2165 +#define SCI_LINEFROMPOSITION 2166 +#define SCI_POSITIONFROMLINE 2167 +#define SCI_LINESCROLL 2168 +#define SCI_SCROLLCARET 2169 +#define SCI_REPLACESEL 2170 +#define SCI_SETREADONLY 2171 +#define SCI_NULL 2172 +#define SCI_CANPASTE 2173 +#define SCI_CANUNDO 2174 +#define SCI_EMPTYUNDOBUFFER 2175 +#define SCI_UNDO 2176 +#define SCI_CUT 2177 +#define SCI_COPY 2178 +#define SCI_PASTE 2179 +#define SCI_CLEAR 2180 +#define SCI_SETTEXT 2181 +#define SCI_GETTEXT 2182 +#define SCI_GETTEXTLENGTH 2183 +#define SCI_GETDIRECTFUNCTION 2184 +#define SCI_GETDIRECTPOINTER 2185 +#define SCI_SETOVERTYPE 2186 +#define SCI_GETOVERTYPE 2187 +#define SCI_SETCARETWIDTH 2188 +#define SCI_GETCARETWIDTH 2189 +#define SCI_SETTARGETSTART 2190 +#define SCI_GETTARGETSTART 2191 +#define SCI_SETTARGETEND 2192 +#define SCI_GETTARGETEND 2193 +#define SCI_REPLACETARGET 2194 +#define SCI_REPLACETARGETRE 2195 +#define SCI_SEARCHINTARGET 2197 +#define SCI_SETSEARCHFLAGS 2198 +#define SCI_GETSEARCHFLAGS 2199 +#define SCI_CALLTIPSHOW 2200 +#define SCI_CALLTIPCANCEL 2201 +#define SCI_CALLTIPACTIVE 2202 +#define SCI_CALLTIPPOSSTART 2203 +#define SCI_CALLTIPSETHLT 2204 +#define SCI_CALLTIPSETBACK 2205 +#define SCI_CALLTIPSETFORE 2206 +#define SCI_CALLTIPSETFOREHLT 2207 +#define SCI_CALLTIPUSESTYLE 2212 +#define SCI_VISIBLEFROMDOCLINE 2220 +#define SCI_DOCLINEFROMVISIBLE 2221 +#define SCI_WRAPCOUNT 2235 +#define SC_FOLDLEVELBASE 0x400 +#define SC_FOLDLEVELWHITEFLAG 0x1000 +#define SC_FOLDLEVELHEADERFLAG 0x2000 +#define SC_FOLDLEVELNUMBERMASK 0x0FFF +#define SCI_SETFOLDLEVEL 2222 +#define SCI_GETFOLDLEVEL 2223 +#define SCI_GETLASTCHILD 2224 +#define SCI_GETFOLDPARENT 2225 +#define SCI_SHOWLINES 2226 +#define SCI_HIDELINES 2227 +#define SCI_GETLINEVISIBLE 2228 +#define SCI_SETFOLDEXPANDED 2229 +#define SCI_GETFOLDEXPANDED 2230 +#define SCI_TOGGLEFOLD 2231 +#define SCI_ENSUREVISIBLE 2232 +#define SC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002 +#define SC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004 +#define SC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008 +#define SC_FOLDFLAG_LINEAFTER_CONTRACTED 0x0010 +#define SC_FOLDFLAG_LEVELNUMBERS 0x0040 +#define SCI_SETFOLDFLAGS 2233 +#define SCI_ENSUREVISIBLEENFORCEPOLICY 2234 +#define SCI_SETTABINDENTS 2260 +#define SCI_GETTABINDENTS 2261 +#define SCI_SETBACKSPACEUNINDENTS 2262 +#define SCI_GETBACKSPACEUNINDENTS 2263 +#define SC_TIME_FOREVER 10000000 +#define SCI_SETMOUSEDWELLTIME 2264 +#define SCI_GETMOUSEDWELLTIME 2265 +#define SCI_WORDSTARTPOSITION 2266 +#define SCI_WORDENDPOSITION 2267 +#define SC_WRAP_NONE 0 +#define SC_WRAP_WORD 1 +#define SC_WRAP_CHAR 2 +#define SCI_SETWRAPMODE 2268 +#define SCI_GETWRAPMODE 2269 +#define SC_WRAPVISUALFLAG_NONE 0x0000 +#define SC_WRAPVISUALFLAG_END 0x0001 +#define SC_WRAPVISUALFLAG_START 0x0002 +#define SCI_SETWRAPVISUALFLAGS 2460 +#define SCI_GETWRAPVISUALFLAGS 2461 +#define SC_WRAPVISUALFLAGLOC_DEFAULT 0x0000 +#define SC_WRAPVISUALFLAGLOC_END_BY_TEXT 0x0001 +#define SC_WRAPVISUALFLAGLOC_START_BY_TEXT 0x0002 +#define SCI_SETWRAPVISUALFLAGSLOCATION 2462 +#define SCI_GETWRAPVISUALFLAGSLOCATION 2463 +#define SCI_SETWRAPSTARTINDENT 2464 +#define SCI_GETWRAPSTARTINDENT 2465 +#define SC_CACHE_NONE 0 +#define SC_CACHE_CARET 1 +#define SC_CACHE_PAGE 2 +#define SC_CACHE_DOCUMENT 3 +#define SCI_SETLAYOUTCACHE 2272 +#define SCI_GETLAYOUTCACHE 2273 +#define SCI_SETSCROLLWIDTH 2274 +#define SCI_GETSCROLLWIDTH 2275 +#define SCI_SETSCROLLWIDTHTRACKING 2516 +#define SCI_GETSCROLLWIDTHTRACKING 2517 +#define SCI_TEXTWIDTH 2276 +#define SCI_SETENDATLASTLINE 2277 +#define SCI_GETENDATLASTLINE 2278 +#define SCI_TEXTHEIGHT 2279 +#define SCI_SETVSCROLLBAR 2280 +#define SCI_GETVSCROLLBAR 2281 +#define SCI_APPENDTEXT 2282 +#define SCI_GETTWOPHASEDRAW 2283 +#define SCI_SETTWOPHASEDRAW 2284 +#define SCI_TARGETFROMSELECTION 2287 +#define SCI_LINESJOIN 2288 +#define SCI_LINESSPLIT 2289 +#define SCI_SETFOLDMARGINCOLOUR 2290 +#define SCI_SETFOLDMARGINHICOLOUR 2291 +#define SCI_LINEDOWN 2300 +#define SCI_LINEDOWNEXTEND 2301 +#define SCI_LINEUP 2302 +#define SCI_LINEUPEXTEND 2303 +#define SCI_CHARLEFT 2304 +#define SCI_CHARLEFTEXTEND 2305 +#define SCI_CHARRIGHT 2306 +#define SCI_CHARRIGHTEXTEND 2307 +#define SCI_WORDLEFT 2308 +#define SCI_WORDLEFTEXTEND 2309 +#define SCI_WORDRIGHT 2310 +#define SCI_WORDRIGHTEXTEND 2311 +#define SCI_HOME 2312 +#define SCI_HOMEEXTEND 2313 +#define SCI_LINEEND 2314 +#define SCI_LINEENDEXTEND 2315 +#define SCI_DOCUMENTSTART 2316 +#define SCI_DOCUMENTSTARTEXTEND 2317 +#define SCI_DOCUMENTEND 2318 +#define SCI_DOCUMENTENDEXTEND 2319 +#define SCI_PAGEUP 2320 +#define SCI_PAGEUPEXTEND 2321 +#define SCI_PAGEDOWN 2322 +#define SCI_PAGEDOWNEXTEND 2323 +#define SCI_EDITTOGGLEOVERTYPE 2324 +#define SCI_CANCEL 2325 +#define SCI_DELETEBACK 2326 +#define SCI_TAB 2327 +#define SCI_BACKTAB 2328 +#define SCI_NEWLINE 2329 +#define SCI_FORMFEED 2330 +#define SCI_VCHOME 2331 +#define SCI_VCHOMEEXTEND 2332 +#define SCI_ZOOMIN 2333 +#define SCI_ZOOMOUT 2334 +#define SCI_DELWORDLEFT 2335 +#define SCI_DELWORDRIGHT 2336 +#define SCI_DELWORDRIGHTEND 2518 +#define SCI_LINECUT 2337 +#define SCI_LINEDELETE 2338 +#define SCI_LINETRANSPOSE 2339 +#define SCI_LINEDUPLICATE 2404 +#define SCI_LOWERCASE 2340 +#define SCI_UPPERCASE 2341 +#define SCI_LINESCROLLDOWN 2342 +#define SCI_LINESCROLLUP 2343 +#define SCI_DELETEBACKNOTLINE 2344 +#define SCI_HOMEDISPLAY 2345 +#define SCI_HOMEDISPLAYEXTEND 2346 +#define SCI_LINEENDDISPLAY 2347 +#define SCI_LINEENDDISPLAYEXTEND 2348 +#define SCI_HOMEWRAP 2349 +#define SCI_HOMEWRAPEXTEND 2450 +#define SCI_LINEENDWRAP 2451 +#define SCI_LINEENDWRAPEXTEND 2452 +#define SCI_VCHOMEWRAP 2453 +#define SCI_VCHOMEWRAPEXTEND 2454 +#define SCI_LINECOPY 2455 +#define SCI_MOVECARETINSIDEVIEW 2401 +#define SCI_LINELENGTH 2350 +#define SCI_BRACEHIGHLIGHT 2351 +#define SCI_BRACEBADLIGHT 2352 +#define SCI_BRACEMATCH 2353 +#define SCI_GETVIEWEOL 2355 +#define SCI_SETVIEWEOL 2356 +#define SCI_GETDOCPOINTER 2357 +#define SCI_SETDOCPOINTER 2358 +#define SCI_SETMODEVENTMASK 2359 +#define EDGE_NONE 0 +#define EDGE_LINE 1 +#define EDGE_BACKGROUND 2 +#define SCI_GETEDGECOLUMN 2360 +#define SCI_SETEDGECOLUMN 2361 +#define SCI_GETEDGEMODE 2362 +#define SCI_SETEDGEMODE 2363 +#define SCI_GETEDGECOLOUR 2364 +#define SCI_SETEDGECOLOUR 2365 +#define SCI_SEARCHANCHOR 2366 +#define SCI_SEARCHNEXT 2367 +#define SCI_SEARCHPREV 2368 +#define SCI_LINESONSCREEN 2370 +#define SCI_USEPOPUP 2371 +#define SCI_SELECTIONISRECTANGLE 2372 +#define SCI_SETZOOM 2373 +#define SCI_GETZOOM 2374 +#define SCI_CREATEDOCUMENT 2375 +#define SCI_ADDREFDOCUMENT 2376 +#define SCI_RELEASEDOCUMENT 2377 +#define SCI_GETMODEVENTMASK 2378 +#define SCI_SETFOCUS 2380 +#define SCI_GETFOCUS 2381 +#define SCI_SETSTATUS 2382 +#define SCI_GETSTATUS 2383 +#define SCI_SETMOUSEDOWNCAPTURES 2384 +#define SCI_GETMOUSEDOWNCAPTURES 2385 +#define SC_CURSORNORMAL -1 +#define SC_CURSORWAIT 4 +#define SCI_SETCURSOR 2386 +#define SCI_GETCURSOR 2387 +#define SCI_SETCONTROLCHARSYMBOL 2388 +#define SCI_GETCONTROLCHARSYMBOL 2389 +#define SCI_WORDPARTLEFT 2390 +#define SCI_WORDPARTLEFTEXTEND 2391 +#define SCI_WORDPARTRIGHT 2392 +#define SCI_WORDPARTRIGHTEXTEND 2393 +#define VISIBLE_SLOP 0x01 +#define VISIBLE_STRICT 0x04 +#define SCI_SETVISIBLEPOLICY 2394 +#define SCI_DELLINELEFT 2395 +#define SCI_DELLINERIGHT 2396 +#define SCI_SETXOFFSET 2397 +#define SCI_GETXOFFSET 2398 +#define SCI_CHOOSECARETX 2399 +#define SCI_GRABFOCUS 2400 +#define CARET_SLOP 0x01 +#define CARET_STRICT 0x04 +#define CARET_JUMPS 0x10 +#define CARET_EVEN 0x08 +#define SCI_SETXCARETPOLICY 2402 +#define SCI_SETYCARETPOLICY 2403 +#define SCI_SETPRINTWRAPMODE 2406 +#define SCI_GETPRINTWRAPMODE 2407 +#define SCI_SETHOTSPOTACTIVEFORE 2410 +#define SCI_GETHOTSPOTACTIVEFORE 2494 +#define SCI_SETHOTSPOTACTIVEBACK 2411 +#define SCI_GETHOTSPOTACTIVEBACK 2495 +#define SCI_SETHOTSPOTACTIVEUNDERLINE 2412 +#define SCI_GETHOTSPOTACTIVEUNDERLINE 2496 +#define SCI_SETHOTSPOTSINGLELINE 2421 +#define SCI_GETHOTSPOTSINGLELINE 2497 +#define SCI_PARADOWN 2413 +#define SCI_PARADOWNEXTEND 2414 +#define SCI_PARAUP 2415 +#define SCI_PARAUPEXTEND 2416 +#define SCI_POSITIONBEFORE 2417 +#define SCI_POSITIONAFTER 2418 +#define SCI_COPYRANGE 2419 +#define SCI_COPYTEXT 2420 +#define SC_SEL_STREAM 0 +#define SC_SEL_RECTANGLE 1 +#define SC_SEL_LINES 2 +#define SCI_SETSELECTIONMODE 2422 +#define SCI_GETSELECTIONMODE 2423 +#define SCI_GETLINESELSTARTPOSITION 2424 +#define SCI_GETLINESELENDPOSITION 2425 +#define SCI_LINEDOWNRECTEXTEND 2426 +#define SCI_LINEUPRECTEXTEND 2427 +#define SCI_CHARLEFTRECTEXTEND 2428 +#define SCI_CHARRIGHTRECTEXTEND 2429 +#define SCI_HOMERECTEXTEND 2430 +#define SCI_VCHOMERECTEXTEND 2431 +#define SCI_LINEENDRECTEXTEND 2432 +#define SCI_PAGEUPRECTEXTEND 2433 +#define SCI_PAGEDOWNRECTEXTEND 2434 +#define SCI_STUTTEREDPAGEUP 2435 +#define SCI_STUTTEREDPAGEUPEXTEND 2436 +#define SCI_STUTTEREDPAGEDOWN 2437 +#define SCI_STUTTEREDPAGEDOWNEXTEND 2438 +#define SCI_WORDLEFTEND 2439 +#define SCI_WORDLEFTENDEXTEND 2440 +#define SCI_WORDRIGHTEND 2441 +#define SCI_WORDRIGHTENDEXTEND 2442 +#define SCI_SETWHITESPACECHARS 2443 +#define SCI_SETCHARSDEFAULT 2444 +#define SCI_AUTOCGETCURRENT 2445 +#define SCI_ALLOCATE 2446 +#define SCI_TARGETASUTF8 2447 +#define SCI_SETLENGTHFORENCODE 2448 +#define SCI_ENCODEDFROMUTF8 2449 +#define SCI_FINDCOLUMN 2456 +#define SCI_GETCARETSTICKY 2457 +#define SCI_SETCARETSTICKY 2458 +#define SCI_TOGGLECARETSTICKY 2459 +#define SCI_SETPASTECONVERTENDINGS 2467 +#define SCI_GETPASTECONVERTENDINGS 2468 +#define SCI_SELECTIONDUPLICATE 2469 +#define SC_ALPHA_TRANSPARENT 0 +#define SC_ALPHA_OPAQUE 255 +#define SC_ALPHA_NOALPHA 256 +#define SCI_SETCARETLINEBACKALPHA 2470 +#define SCI_GETCARETLINEBACKALPHA 2471 +#define CARETSTYLE_INVISIBLE 0 +#define CARETSTYLE_LINE 1 +#define CARETSTYLE_BLOCK 2 +#define SCI_SETCARETSTYLE 2512 +#define SCI_GETCARETSTYLE 2513 +#define SCI_SETINDICATORCURRENT 2500 +#define SCI_GETINDICATORCURRENT 2501 +#define SCI_SETINDICATORVALUE 2502 +#define SCI_GETINDICATORVALUE 2503 +#define SCI_INDICATORFILLRANGE 2504 +#define SCI_INDICATORCLEARRANGE 2505 +#define SCI_INDICATORALLONFOR 2506 +#define SCI_INDICATORVALUEAT 2507 +#define SCI_INDICATORSTART 2508 +#define SCI_INDICATOREND 2509 +#define SCI_SETPOSITIONCACHE 2514 +#define SCI_GETPOSITIONCACHE 2515 +#define SCI_COPYALLOWLINE 2519 +#define SCI_GETCHARACTERPOINTER 2520 +#define SCI_SETKEYSUNICODE 2521 +#define SCI_GETKEYSUNICODE 2522 +#define SCI_INDICSETALPHA 2523 +#define SCI_INDICGETALPHA 2524 +#define SCI_SETEXTRAASCENT 2525 +#define SCI_GETEXTRAASCENT 2526 +#define SCI_SETEXTRADESCENT 2527 +#define SCI_GETEXTRADESCENT 2528 +#define SCI_MARKERSYMBOLDEFINED 2529 +#define SCI_MARGINSETTEXT 2530 +#define SCI_MARGINGETTEXT 2531 +#define SCI_MARGINSETSTYLE 2532 +#define SCI_MARGINGETSTYLE 2533 +#define SCI_MARGINSETSTYLES 2534 +#define SCI_MARGINGETSTYLES 2535 +#define SCI_MARGINTEXTCLEARALL 2536 +#define SCI_MARGINSETSTYLEOFFSET 2537 +#define SCI_MARGINGETSTYLEOFFSET 2538 +#define SCI_ANNOTATIONSETTEXT 2540 +#define SCI_ANNOTATIONGETTEXT 2541 +#define SCI_ANNOTATIONSETSTYLE 2542 +#define SCI_ANNOTATIONGETSTYLE 2543 +#define SCI_ANNOTATIONSETSTYLES 2544 +#define SCI_ANNOTATIONGETSTYLES 2545 +#define SCI_ANNOTATIONGETLINES 2546 +#define SCI_ANNOTATIONCLEARALL 2547 +#define ANNOTATION_HIDDEN 0 +#define ANNOTATION_STANDARD 1 +#define ANNOTATION_BOXED 2 +#define SCI_ANNOTATIONSETVISIBLE 2548 +#define SCI_ANNOTATIONGETVISIBLE 2549 +#define SCI_ANNOTATIONSETSTYLEOFFSET 2550 +#define SCI_ANNOTATIONGETSTYLEOFFSET 2551 +#define UNDO_MAY_COALESCE 1 +#define SCI_ADDUNDOACTION 2560 +#define SCI_STARTRECORD 3001 +#define SCI_STOPRECORD 3002 +#define SCI_SETLEXER 4001 +#define SCI_GETLEXER 4002 +#define SCI_COLOURISE 4003 +#define SCI_SETPROPERTY 4004 +#define KEYWORDSET_MAX 8 +#define SCI_SETKEYWORDS 4005 +#define SCI_SETLEXERLANGUAGE 4006 +#define SCI_LOADLEXERLIBRARY 4007 +#define SCI_GETPROPERTY 4008 +#define SCI_GETPROPERTYEXPANDED 4009 +#define SCI_GETPROPERTYINT 4010 +#define SCI_GETSTYLEBITSNEEDED 4011 +#define SC_MOD_INSERTTEXT 0x1 +#define SC_MOD_DELETETEXT 0x2 +#define SC_MOD_CHANGESTYLE 0x4 +#define SC_MOD_CHANGEFOLD 0x8 +#define SC_PERFORMED_USER 0x10 +#define SC_PERFORMED_UNDO 0x20 +#define SC_PERFORMED_REDO 0x40 +#define SC_MULTISTEPUNDOREDO 0x80 +#define SC_LASTSTEPINUNDOREDO 0x100 +#define SC_MOD_CHANGEMARKER 0x200 +#define SC_MOD_BEFOREINSERT 0x400 +#define SC_MOD_BEFOREDELETE 0x800 +#define SC_MULTILINEUNDOREDO 0x1000 +#define SC_STARTACTION 0x2000 +#define SC_MOD_CHANGEINDICATOR 0x4000 +#define SC_MOD_CHANGELINESTATE 0x8000 +#define SC_MOD_CHANGEMARGIN 0x10000 +#define SC_MOD_CHANGEANNOTATION 0x20000 +#define SC_MOD_CONTAINER 0x40000 +#define SC_MODEVENTMASKALL 0x7FFFF +#define SCEN_CHANGE 768 +#define SCEN_SETFOCUS 512 +#define SCEN_KILLFOCUS 256 +#define SCK_DOWN 300 +#define SCK_UP 301 +#define SCK_LEFT 302 +#define SCK_RIGHT 303 +#define SCK_HOME 304 +#define SCK_END 305 +#define SCK_PRIOR 306 +#define SCK_NEXT 307 +#define SCK_DELETE 308 +#define SCK_INSERT 309 +#define SCK_ESCAPE 7 +#define SCK_BACK 8 +#define SCK_TAB 9 +#define SCK_RETURN 13 +#define SCK_ADD 310 +#define SCK_SUBTRACT 311 +#define SCK_DIVIDE 312 +#define SCK_WIN 313 +#define SCK_RWIN 314 +#define SCK_MENU 315 +#define SCMOD_NORM 0 +#define SCMOD_SHIFT 1 +#define SCMOD_CTRL 2 +#define SCMOD_ALT 4 +#define SCN_STYLENEEDED 2000 +#define SCN_CHARADDED 2001 +#define SCN_SAVEPOINTREACHED 2002 +#define SCN_SAVEPOINTLEFT 2003 +#define SCN_MODIFYATTEMPTRO 2004 +#define SCN_KEY 2005 +#define SCN_DOUBLECLICK 2006 +#define SCN_UPDATEUI 2007 +#define SCN_MODIFIED 2008 +#define SCN_MACRORECORD 2009 +#define SCN_MARGINCLICK 2010 +#define SCN_NEEDSHOWN 2011 +#define SCN_PAINTED 2013 +#define SCN_USERLISTSELECTION 2014 +#define SCN_URIDROPPED 2015 +#define SCN_DWELLSTART 2016 +#define SCN_DWELLEND 2017 +#define SCN_ZOOM 2018 +#define SCN_HOTSPOTCLICK 2019 +#define SCN_HOTSPOTDOUBLECLICK 2020 +#define SCN_CALLTIPCLICK 2021 +#define SCN_AUTOCSELECTION 2022 +#define SCN_INDICATORCLICK 2023 +#define SCN_INDICATORRELEASE 2024 +#define SCN_AUTOCCANCELLED 2025 +#define SCN_AUTOCCHARDELETED 2026 +/* --Autogenerated -- end of section automatically generated from Scintilla.iface */ + +/* These structures are defined to be exactly the same shape as the Win32 + * CHARRANGE, TEXTRANGE, FINDTEXTEX, FORMATRANGE, and NMHDR structs. + * So older code that treats Scintilla as a RichEdit will work. */ + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +struct CharacterRange { + long cpMin; + long cpMax; +}; + +struct TextRange { + struct CharacterRange chrg; + char *lpstrText; +}; + +struct TextToFind { + struct CharacterRange chrg; + char *lpstrText; + struct CharacterRange chrgText; +}; + +#ifdef PLATFORM_H + +/* This structure is used in printing and requires some of the graphics types + * from Platform.h. Not needed by most client code. */ + +struct RangeToFormat { + SurfaceID hdc; + SurfaceID hdcTarget; + PRectangle rc; + PRectangle rcPage; + CharacterRange chrg; +}; + +#endif + +struct NotifyHeader { + /* Compatible with Windows NMHDR. + * hwndFrom is really an environment specific window handle or pointer + * but most clients of Scintilla.h do not have this type visible. */ + void *hwndFrom; + uptr_t idFrom; + unsigned int code; +}; + +struct SCNotification { + struct NotifyHeader nmhdr; + int position; /* SCN_STYLENEEDED, SCN_MODIFIED, SCN_DWELLSTART, SCN_DWELLEND */ + int ch; /* SCN_CHARADDED, SCN_KEY */ + int modifiers; /* SCN_KEY */ + int modificationType; /* SCN_MODIFIED */ + const char *text; // SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */ + int length; /* SCN_MODIFIED */ + int linesAdded; /* SCN_MODIFIED */ + int message; /* SCN_MACRORECORD */ + uptr_t wParam; /* SCN_MACRORECORD */ + sptr_t lParam; /* SCN_MACRORECORD */ + int line; /* SCN_MODIFIED */ + int foldLevelNow; /* SCN_MODIFIED */ + int foldLevelPrev; /* SCN_MODIFIED */ + int margin; /* SCN_MARGINCLICK */ + int listType; /* SCN_USERLISTSELECTION */ + int x; /* SCN_DWELLSTART, SCN_DWELLEND */ + int y; /* SCN_DWELLSTART, SCN_DWELLEND */ + int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */ + int annotationLinesAdded; /* SC_MOD_CHANGEANNOTATION */ +}; + +#ifdef SCI_NAMESPACE +} +#endif + +/* Deprecation section listing all API features that are deprecated and + * will be removed completely in a future version. + * To enable these features define INCLUDE_DEPRECATED_FEATURES */ + +#ifdef INCLUDE_DEPRECATED_FEATURES + +#define SCI_SETCARETPOLICY 2369 +#define CARET_CENTER 0x02 +#define CARET_XEVEN 0x08 +#define CARET_XJUMPS 0x10 + +#define SC_FOLDFLAG_BOX 0x0001 +#define SC_FOLDLEVELBOXHEADERFLAG 0x4000 +#define SC_FOLDLEVELBOXFOOTERFLAG 0x8000 +#define SC_FOLDLEVELCONTRACTED 0x10000 +#define SC_FOLDLEVELUNINDENT 0x20000 + +#define SCN_POSCHANGED 2012 +#define SCN_CHECKBRACE 2007 + +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/ScintillaBase.cpp b/harbour/contrib/hbide/qscintilla/ScintillaBase.cpp new file mode 100644 index 0000000000..4a90069e00 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ScintillaBase.cpp @@ -0,0 +1,756 @@ +// Scintilla source code edit control +/** @file ScintillaBase.cxx + ** An enhanced subclass of Editor with calltips, autocomplete and context menu. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "PropSet.h" +#ifdef SCI_LEXER +#include "SciLexer.h" +#include "Accessor.h" +#include "DocumentAccessor.h" +#include "KeyWords.h" +#endif +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "CallTip.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "AutoComplete.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "Document.h" +#include "PositionCache.h" +#include "Editor.h" +#include "ScintillaBase.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +ScintillaBase::ScintillaBase() { + displayPopupMenu = true; + listType = 0; + maxListWidth = 0; +#ifdef SCI_LEXER + lexLanguage = SCLEX_CONTAINER; + performingStyle = false; + lexCurrent = 0; + for (int wl = 0;wl < numWordLists;wl++) + keyWordLists[wl] = new WordList; + keyWordLists[numWordLists] = 0; +#endif +} + +ScintillaBase::~ScintillaBase() { +#ifdef SCI_LEXER + for (int wl = 0;wl < numWordLists;wl++) + delete keyWordLists[wl]; +#endif +} + +void ScintillaBase::Finalise() { + Editor::Finalise(); + popup.Destroy(); +} + +void ScintillaBase::RefreshColourPalette(Palette &pal, bool want) { + Editor::RefreshColourPalette(pal, want); + ct.RefreshColourPalette(pal, want); +} + +void ScintillaBase::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { + bool isFillUp = ac.Active() && ac.IsFillUpChar(*s); + if (!isFillUp) { + Editor::AddCharUTF(s, len, treatAsDBCS); + } + if (ac.Active()) { + AutoCompleteCharacterAdded(s[0]); + // For fill ups add the character after the autocompletion has + // triggered so containers see the key so can display a calltip. + if (isFillUp) { + Editor::AddCharUTF(s, len, treatAsDBCS); + } + } +} + +void ScintillaBase::Command(int cmdId) { + + switch (cmdId) { + + case idAutoComplete: // Nothing to do + + break; + + case idCallTip: // Nothing to do + + break; + + case idcmdUndo: + WndProc(SCI_UNDO, 0, 0); + break; + + case idcmdRedo: + WndProc(SCI_REDO, 0, 0); + break; + + case idcmdCut: + WndProc(SCI_CUT, 0, 0); + break; + + case idcmdCopy: + WndProc(SCI_COPY, 0, 0); + break; + + case idcmdPaste: + WndProc(SCI_PASTE, 0, 0); + break; + + case idcmdDelete: + WndProc(SCI_CLEAR, 0, 0); + break; + + case idcmdSelectAll: + WndProc(SCI_SELECTALL, 0, 0); + break; + } +} + +int ScintillaBase::KeyCommand(unsigned int iMessage) { + // Most key commands cancel autocompletion mode + if (ac.Active()) { + switch (iMessage) { + // Except for these + case SCI_LINEDOWN: + AutoCompleteMove(1); + return 0; + case SCI_LINEUP: + AutoCompleteMove( -1); + return 0; + case SCI_PAGEDOWN: + AutoCompleteMove(5); + return 0; + case SCI_PAGEUP: + AutoCompleteMove( -5); + return 0; + case SCI_VCHOME: + AutoCompleteMove( -5000); + return 0; + case SCI_LINEEND: + AutoCompleteMove(5000); + return 0; + case SCI_DELETEBACK: + DelCharBack(true); + AutoCompleteCharacterDeleted(); + EnsureCaretVisible(); + return 0; + case SCI_DELETEBACKNOTLINE: + DelCharBack(false); + AutoCompleteCharacterDeleted(); + EnsureCaretVisible(); + return 0; + case SCI_TAB: + AutoCompleteCompleted(); + return 0; + case SCI_NEWLINE: + AutoCompleteCompleted(); + return 0; + + default: + AutoCompleteCancel(); + } + } + + if (ct.inCallTipMode) { + if ( + (iMessage != SCI_CHARLEFT) && + (iMessage != SCI_CHARLEFTEXTEND) && + (iMessage != SCI_CHARRIGHT) && + (iMessage != SCI_CHARRIGHTEXTEND) && + (iMessage != SCI_EDITTOGGLEOVERTYPE) && + (iMessage != SCI_DELETEBACK) && + (iMessage != SCI_DELETEBACKNOTLINE) + ) { + ct.CallTipCancel(); + } + if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) { + if (currentPos <= ct.posStartCallTip) { + ct.CallTipCancel(); + } + } + } + return Editor::KeyCommand(iMessage); +} + +void ScintillaBase::AutoCompleteDoubleClick(void* p) { + ScintillaBase* sci = reinterpret_cast(p); + sci->AutoCompleteCompleted(); +} + +void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { + //Platform::DebugPrintf("AutoComplete %s\n", list); + ct.CallTipCancel(); + + if (ac.chooseSingle && (listType == 0)) { + if (list && !strchr(list, ac.GetSeparator())) { + const char *typeSep = strchr(list, ac.GetTypesep()); + size_t lenInsert = (typeSep) ? (typeSep-list) : strlen(list); + if (ac.ignoreCase) { + SetEmptySelection(currentPos - lenEntered); + pdoc->DeleteChars(currentPos, lenEntered); + SetEmptySelection(currentPos); + pdoc->InsertString(currentPos, list, lenInsert); + SetEmptySelection(currentPos + lenInsert); + } else { + SetEmptySelection(currentPos); + pdoc->InsertString(currentPos, list + lenEntered, lenInsert - lenEntered); + SetEmptySelection(currentPos + lenInsert - lenEntered); + } + return; + } + } + ac.Start(wMain, idAutoComplete, currentPos, LocationFromPosition(currentPos), + lenEntered, vs.lineHeight, IsUnicodeMode()); + + PRectangle rcClient = GetClientRectangle(); + Point pt = LocationFromPosition(currentPos - lenEntered); + PRectangle rcPopupBounds = wMain.GetMonitorRect(pt); + if (rcPopupBounds.Height() == 0) + rcPopupBounds = rcClient; + + int heightLB = 100; + int widthLB = 100; + if (pt.x >= rcClient.right - widthLB) { + HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB); + Redraw(); + pt = LocationFromPosition(currentPos); + } + PRectangle rcac; + rcac.left = pt.x - ac.lb->CaretFromEdge(); + if (pt.y >= rcPopupBounds.bottom - heightLB && // Wont fit below. + pt.y >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2) { // and there is more room above. + rcac.top = pt.y - heightLB; + if (rcac.top < rcPopupBounds.top) { + heightLB -= (rcPopupBounds.top - rcac.top); + rcac.top = rcPopupBounds.top; + } + } else { + rcac.top = pt.y + vs.lineHeight; + } + rcac.right = rcac.left + widthLB; + rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcPopupBounds.bottom); + ac.lb->SetPositionRelative(rcac, wMain); + ac.lb->SetFont(vs.styles[STYLE_DEFAULT].font); + unsigned int aveCharWidth = vs.styles[STYLE_DEFAULT].aveCharWidth; + ac.lb->SetAverageCharWidth(aveCharWidth); + ac.lb->SetDoubleClickAction(AutoCompleteDoubleClick, this); + + ac.SetList(list); + + // Fiddle the position of the list so it is right next to the target and wide enough for all its strings + PRectangle rcList = ac.lb->GetDesiredRect(); + int heightAlloced = rcList.bottom - rcList.top; + widthLB = Platform::Maximum(widthLB, rcList.right - rcList.left); + if (maxListWidth != 0) + widthLB = Platform::Minimum(widthLB, aveCharWidth*maxListWidth); + // Make an allowance for large strings in list + rcList.left = pt.x - ac.lb->CaretFromEdge(); + rcList.right = rcList.left + widthLB; + if (((pt.y + vs.lineHeight) >= (rcPopupBounds.bottom - heightAlloced)) && // Wont fit below. + ((pt.y + vs.lineHeight / 2) >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2)) { // and there is more room above. + rcList.top = pt.y - heightAlloced; + } else { + rcList.top = pt.y + vs.lineHeight; + } + rcList.bottom = rcList.top + heightAlloced; + ac.lb->SetPositionRelative(rcList, wMain); + ac.Show(true); + if (lenEntered != 0) { + AutoCompleteMoveToCurrentWord(); + } +} + +void ScintillaBase::AutoCompleteCancel() { + if (ac.Active()) { + //SCNotification scn = {0}; + SCNotification scn = {{0,0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + scn.nmhdr.code = SCN_AUTOCCANCELLED; + scn.wParam = 0; + scn.listType = 0; + NotifyParent(scn); + } + ac.Cancel(); +} + +void ScintillaBase::AutoCompleteMove(int delta) { + ac.Move(delta); +} + +void ScintillaBase::AutoCompleteMoveToCurrentWord() { + char wordCurrent[1000]; + int i; + int startWord = ac.posStart - ac.startLen; + for (i = startWord; i < currentPos && i - startWord < 1000; i++) + wordCurrent[i - startWord] = pdoc->CharAt(i); + wordCurrent[Platform::Minimum(i - startWord, 999)] = '\0'; + ac.Select(wordCurrent); +} + +void ScintillaBase::AutoCompleteCharacterAdded(char ch) { + if (ac.IsFillUpChar(ch)) { + AutoCompleteCompleted(); + } else if (ac.IsStopChar(ch)) { + AutoCompleteCancel(); + } else { + AutoCompleteMoveToCurrentWord(); + } +} + +void ScintillaBase::AutoCompleteCharacterDeleted() { + if (currentPos < ac.posStart - ac.startLen) { + AutoCompleteCancel(); + } else if (ac.cancelAtStartPos && (currentPos <= ac.posStart)) { + AutoCompleteCancel(); + } else { + AutoCompleteMoveToCurrentWord(); + } + //SCNotification scn = {0}; + SCNotification scn = {{0,0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + scn.nmhdr.code = SCN_AUTOCCHARDELETED; + scn.wParam = 0; + scn.listType = 0; + NotifyParent(scn); +} + +void ScintillaBase::AutoCompleteCompleted() { + int item = ac.lb->GetSelection(); + char selected[1000]; + selected[0] = '\0'; + if (item != -1) { + ac.lb->GetValue(item, selected, sizeof(selected)); + } else { + AutoCompleteCancel(); + return; + } + + ac.Show(false); + + listSelected = selected; + //SCNotification scn = {0}; + SCNotification scn = {{0,0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + scn.nmhdr.code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION; + scn.message = 0; + scn.wParam = listType; + scn.listType = listType; + Position firstPos = ac.posStart - ac.startLen; + scn.lParam = firstPos; + scn.text = listSelected.c_str(); + NotifyParent(scn); + + if (!ac.Active()) + return; + ac.Cancel(); + + if (listType > 0) + return; + + Position endPos = currentPos; + if (ac.dropRestOfWord) + endPos = pdoc->ExtendWordSelect(endPos, 1, true); + if (endPos < firstPos) + return; + pdoc->BeginUndoAction(); + if (endPos != firstPos) { + pdoc->DeleteChars(firstPos, endPos - firstPos); + } + SetEmptySelection(ac.posStart); + if (item != -1) { + SString piece = selected; + pdoc->InsertCString(firstPos, piece.c_str()); + SetEmptySelection(firstPos + static_cast(piece.length())); + } + pdoc->EndUndoAction(); +} + +int ScintillaBase::AutoCompleteGetCurrent() { + if (!ac.Active()) + return -1; + return ac.lb->GetSelection(); +} + +void ScintillaBase::CallTipShow(Point pt, const char *defn) { + ac.Cancel(); + pt.y += vs.lineHeight; + // If container knows about STYLE_CALLTIP then use it in place of the + // STYLE_DEFAULT for the face name, size and character set. Also use it + // for the foreground and background colour. + int ctStyle = ct.UseStyleCallTip() ? STYLE_CALLTIP : STYLE_DEFAULT; + if (ct.UseStyleCallTip()) { + ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back); + } + PRectangle rc = ct.CallTipStart(currentPos, pt, + defn, + vs.styles[ctStyle].fontName, + vs.styles[ctStyle].sizeZoomed, + CodePage(), + vs.styles[ctStyle].characterSet, + wMain); + // If the call-tip window would be out of the client + // space, adjust so it displays above the text. + PRectangle rcClient = GetClientRectangle(); + if (rc.bottom > rcClient.bottom) { + int offset = vs.lineHeight + rc.Height(); + rc.top -= offset; + rc.bottom -= offset; + } + // Now display the window. + CreateCallTipWindow(rc); + ct.wCallTip.SetPositionRelative(rc, wMain); + ct.wCallTip.Show(); +} + +void ScintillaBase::CallTipClick() { + // SCNotification scn = {0}; + SCNotification scn = {{0,0,0},0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + scn.nmhdr.code = SCN_CALLTIPCLICK; + scn.position = ct.clickPlace; + NotifyParent(scn); +} + +void ScintillaBase::ContextMenu(Point pt) { + if (displayPopupMenu) { + bool writable = !WndProc(SCI_GETREADONLY, 0, 0); + popup.CreatePopUp(); + AddToPopUp("Undo", idcmdUndo, writable && pdoc->CanUndo()); + AddToPopUp("Redo", idcmdRedo, writable && pdoc->CanRedo()); + AddToPopUp(""); + AddToPopUp("Cut", idcmdCut, writable && currentPos != anchor); + AddToPopUp("Copy", idcmdCopy, currentPos != anchor); + AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0)); + AddToPopUp("Delete", idcmdDelete, writable && currentPos != anchor); + AddToPopUp(""); + AddToPopUp("Select All", idcmdSelectAll); + popup.Show(pt, wMain); + } +} + +void ScintillaBase::CancelModes() { + AutoCompleteCancel(); + ct.CallTipCancel(); + Editor::CancelModes(); +} + +void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + CancelModes(); + Editor::ButtonDown(pt, curTime, shift, ctrl, alt); +} + +#ifdef SCI_LEXER +void ScintillaBase::SetLexer(uptr_t wParam) { + lexLanguage = wParam; + lexCurrent = LexerModule::Find(lexLanguage); + if (!lexCurrent) + lexCurrent = LexerModule::Find(SCLEX_NULL); +} + +void ScintillaBase::SetLexerLanguage(const char *languageName) { + lexLanguage = SCLEX_CONTAINER; + lexCurrent = LexerModule::Find(languageName); + if (!lexCurrent) + lexCurrent = LexerModule::Find(SCLEX_NULL); + if (lexCurrent) + lexLanguage = lexCurrent->GetLanguage(); +} + +void ScintillaBase::Colourise(int start, int end) { + if (!performingStyle) { + // Protect against reentrance, which may occur, for example, when + // fold points are discovered while performing styling and the folding + // code looks for child lines which may trigger styling. + performingStyle = true; + + int lengthDoc = pdoc->Length(); + if (end == -1) + end = lengthDoc; + int len = end - start; + + PLATFORM_ASSERT(len >= 0); + PLATFORM_ASSERT(start + len <= lengthDoc); + + //WindowAccessor styler(wMain.GetID(), props); + DocumentAccessor styler(pdoc, props, wMain.GetID()); + + int styleStart = 0; + if (start > 0) + styleStart = styler.StyleAt(start - 1) & pdoc->stylingBitsMask; + styler.SetCodePage(pdoc->dbcsCodePage); + + if (lexCurrent && (len > 0)) { // Should always succeed as null lexer should always be available + lexCurrent->Lex(start, len, styleStart, keyWordLists, styler); + styler.Flush(); + if (styler.GetPropertyInt("fold")) { + lexCurrent->Fold(start, len, styleStart, keyWordLists, styler); + styler.Flush(); + } + } + + performingStyle = false; + } +} +#endif + +void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded) { +#ifdef SCI_LEXER + if (lexLanguage != SCLEX_CONTAINER) { + int endStyled = WndProc(SCI_GETENDSTYLED, 0, 0); + int lineEndStyled = WndProc(SCI_LINEFROMPOSITION, endStyled, 0); + endStyled = WndProc(SCI_POSITIONFROMLINE, lineEndStyled, 0); + Colourise(endStyled, endStyleNeeded); + return; + } +#endif + Editor::NotifyStyleToNeeded(endStyleNeeded); +} + +sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { + switch (iMessage) { + case SCI_AUTOCSHOW: + listType = 0; + AutoCompleteStart(wParam, reinterpret_cast(lParam)); + break; + + case SCI_AUTOCCANCEL: + ac.Cancel(); + break; + + case SCI_AUTOCACTIVE: + return ac.Active(); + + case SCI_AUTOCPOSSTART: + return ac.posStart; + + case SCI_AUTOCCOMPLETE: + AutoCompleteCompleted(); + break; + + case SCI_AUTOCSETSEPARATOR: + ac.SetSeparator(static_cast(wParam)); + break; + + case SCI_AUTOCGETSEPARATOR: + return ac.GetSeparator(); + + case SCI_AUTOCSTOPS: + ac.SetStopChars(reinterpret_cast(lParam)); + break; + + case SCI_AUTOCSELECT: + ac.Select(reinterpret_cast(lParam)); + break; + + case SCI_AUTOCGETCURRENT: + return AutoCompleteGetCurrent(); + + case SCI_AUTOCSETCANCELATSTART: + ac.cancelAtStartPos = wParam != 0; + break; + + case SCI_AUTOCGETCANCELATSTART: + return ac.cancelAtStartPos; + + case SCI_AUTOCSETFILLUPS: + ac.SetFillUpChars(reinterpret_cast(lParam)); + break; + + case SCI_AUTOCSETCHOOSESINGLE: + ac.chooseSingle = wParam != 0; + break; + + case SCI_AUTOCGETCHOOSESINGLE: + return ac.chooseSingle; + + case SCI_AUTOCSETIGNORECASE: + ac.ignoreCase = wParam != 0; + break; + + case SCI_AUTOCGETIGNORECASE: + return ac.ignoreCase; + + case SCI_USERLISTSHOW: + listType = wParam; + AutoCompleteStart(0, reinterpret_cast(lParam)); + break; + + case SCI_AUTOCSETAUTOHIDE: + ac.autoHide = wParam != 0; + break; + + case SCI_AUTOCGETAUTOHIDE: + return ac.autoHide; + + case SCI_AUTOCSETDROPRESTOFWORD: + ac.dropRestOfWord = wParam != 0; + break; + + case SCI_AUTOCGETDROPRESTOFWORD: + return ac.dropRestOfWord; + + case SCI_AUTOCSETMAXHEIGHT: + ac.lb->SetVisibleRows(wParam); + break; + + case SCI_AUTOCGETMAXHEIGHT: + return ac.lb->GetVisibleRows(); + + case SCI_AUTOCSETMAXWIDTH: + maxListWidth = wParam; + break; + + case SCI_AUTOCGETMAXWIDTH: + return maxListWidth; + + case SCI_REGISTERIMAGE: + ac.lb->RegisterImage(wParam, reinterpret_cast(lParam)); + break; + + case SCI_CLEARREGISTEREDIMAGES: + ac.lb->ClearRegisteredImages(); + break; + + case SCI_AUTOCSETTYPESEPARATOR: + ac.SetTypesep(static_cast(wParam)); + break; + + case SCI_AUTOCGETTYPESEPARATOR: + return ac.GetTypesep(); + + case SCI_CALLTIPSHOW: + CallTipShow(LocationFromPosition(wParam), + reinterpret_cast(lParam)); + break; + + case SCI_CALLTIPCANCEL: + ct.CallTipCancel(); + break; + + case SCI_CALLTIPACTIVE: + return ct.inCallTipMode; + + case SCI_CALLTIPPOSSTART: + return ct.posStartCallTip; + + case SCI_CALLTIPSETHLT: + ct.SetHighlight(wParam, lParam); + break; + + case SCI_CALLTIPSETBACK: + ct.colourBG = ColourDesired(wParam); + vs.styles[STYLE_CALLTIP].back = ct.colourBG; + InvalidateStyleRedraw(); + break; + + case SCI_CALLTIPSETFORE: + ct.colourUnSel = ColourDesired(wParam); + vs.styles[STYLE_CALLTIP].fore = ct.colourUnSel; + InvalidateStyleRedraw(); + break; + + case SCI_CALLTIPSETFOREHLT: + ct.colourSel = ColourDesired(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_CALLTIPUSESTYLE: + ct.SetTabSize((int)wParam); + InvalidateStyleRedraw(); + break; + + case SCI_USEPOPUP: + displayPopupMenu = wParam != 0; + break; + +#ifdef SCI_LEXER + case SCI_SETLEXER: + SetLexer(wParam); + lexLanguage = wParam; + break; + + case SCI_GETLEXER: + return lexLanguage; + + case SCI_COLOURISE: + if (lexLanguage == SCLEX_CONTAINER) { + pdoc->ModifiedAt(wParam); + NotifyStyleToNeeded((lParam == -1) ? pdoc->Length() : lParam); + } else { + Colourise(wParam, lParam); + } + Redraw(); + break; + + case SCI_SETPROPERTY: + props.Set(reinterpret_cast(wParam), + reinterpret_cast(lParam)); + break; + + case SCI_GETPROPERTY: { + SString val = props.Get(reinterpret_cast(wParam)); + const int n = val.length(); + if (lParam != 0) { + char *ptr = reinterpret_cast(lParam); + memcpy(ptr, val.c_str(), n); + ptr[n] = '\0'; // terminate + } + return n; // Not including NUL + } + + case SCI_GETPROPERTYEXPANDED: { + SString val = props.GetExpanded(reinterpret_cast(wParam)); + const int n = val.length(); + if (lParam != 0) { + char *ptr = reinterpret_cast(lParam); + memcpy(ptr, val.c_str(), n); + ptr[n] = '\0'; // terminate + } + return n; // Not including NUL + } + + case SCI_GETPROPERTYINT: + return props.GetInt(reinterpret_cast(wParam), lParam); + + case SCI_SETKEYWORDS: + if (wParam < numWordLists) { + keyWordLists[wParam]->Clear(); + keyWordLists[wParam]->Set(reinterpret_cast(lParam)); + } + break; + + case SCI_SETLEXERLANGUAGE: + SetLexerLanguage(reinterpret_cast(lParam)); + break; + + case SCI_GETSTYLEBITSNEEDED: + return lexCurrent ? lexCurrent->GetStyleBitsNeeded() : 5; +#endif + + default: + return Editor::WndProc(iMessage, wParam, lParam); + } + return 0l; +} diff --git a/harbour/contrib/hbide/qscintilla/ScintillaBase.h b/harbour/contrib/hbide/qscintilla/ScintillaBase.h new file mode 100644 index 0000000000..0554d9457a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ScintillaBase.h @@ -0,0 +1,101 @@ +// Scintilla source code edit control +/** @file ScintillaBase.h + ** Defines an enhanced subclass of Editor with calltips, autocomplete and context menu. + **/ +// Copyright 1998-2002 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCINTILLABASE_H +#define SCINTILLABASE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class ScintillaBase : public Editor { + // Private so ScintillaBase objects can not be copied + ScintillaBase(const ScintillaBase &) : Editor() {} + ScintillaBase &operator=(const ScintillaBase &) { return *this; } + +protected: + /** Enumeration of commands and child windows. */ + enum { + idCallTip=1, + idAutoComplete=2, + + idcmdUndo=10, + idcmdRedo=11, + idcmdCut=12, + idcmdCopy=13, + idcmdPaste=14, + idcmdDelete=15, + idcmdSelectAll=16 + }; + + bool displayPopupMenu; + Menu popup; + AutoComplete ac; + + CallTip ct; + + int listType; ///< 0 is an autocomplete list + SString listSelected; ///< Receives listbox selected string + int maxListWidth; /// Maximum width of list, in average character widths + + bool performingStyle; ///< Prevent reentrance + +#ifdef SCI_LEXER + int lexLanguage; + const LexerModule *lexCurrent; + PropSet props; + enum {numWordLists=KEYWORDSET_MAX+1}; + WordList *keyWordLists[numWordLists+1]; + void SetLexer(uptr_t wParam); + void SetLexerLanguage(const char *languageName); + void Colourise(int start, int end); +#endif + + ScintillaBase(); + virtual ~ScintillaBase(); + virtual void Initialise() = 0; + virtual void Finalise() = 0; + + virtual void RefreshColourPalette(Palette &pal, bool want); + + virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); + void Command(int cmdId); + virtual void CancelModes(); + virtual int KeyCommand(unsigned int iMessage); + + void AutoCompleteStart(int lenEntered, const char *list); + void AutoCompleteCancel(); + void AutoCompleteMove(int delta); + int AutoCompleteGetCurrent(); + void AutoCompleteCharacterAdded(char ch); + void AutoCompleteCharacterDeleted(); + void AutoCompleteCompleted(); + void AutoCompleteMoveToCurrentWord(); + static void AutoCompleteDoubleClick(void* p); + + void CallTipClick(); + void CallTipShow(Point pt, const char *defn); + virtual void CreateCallTipWindow(PRectangle rc) = 0; + + virtual void AddToPopUp(const char *label, int cmd=0, bool enabled=true) = 0; + void ContextMenu(Point pt); + + virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); + + virtual void NotifyStyleToNeeded(int endStyleNeeded); +public: + // Public so scintilla_send_message can use it + virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/ScintillaWidget.h b/harbour/contrib/hbide/qscintilla/ScintillaWidget.h new file mode 100644 index 0000000000..c60c4a21b9 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ScintillaWidget.h @@ -0,0 +1,59 @@ +/* Scintilla source code edit control */ +/** @file ScintillaWidget.h + ** Definition of Scintilla widget for GTK+. + ** Only needed by GTK+ code but is harmless on other platforms. + **/ +/* Copyright 1998-2001 by Neil Hodgson + * The License.txt file describes the conditions under which this software may be distributed. */ + +#ifndef SCINTILLAWIDGET_H +#define SCINTILLAWIDGET_H + +#if PLAT_GTK + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCINTILLA(obj) GTK_CHECK_CAST (obj, scintilla_get_type (), ScintillaObject) +#define SCINTILLA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, scintilla_get_type (), ScintillaClass) +#define IS_SCINTILLA(obj) GTK_CHECK_TYPE (obj, scintilla_get_type ()) + +typedef struct _ScintillaObject ScintillaObject; +typedef struct _ScintillaClass ScintillaClass; + +struct _ScintillaObject { + GtkContainer cont; + void *pscin; +}; + +struct _ScintillaClass { + GtkContainerClass parent_class; + + void (* command) (ScintillaObject *ttt); + void (* notify) (ScintillaObject *ttt); +}; + +#if GLIB_MAJOR_VERSION < 2 +GtkType scintilla_get_type (void); +#else +GType scintilla_get_type (void); +#endif +GtkWidget* scintilla_new (void); +void scintilla_set_id (ScintillaObject *sci, uptr_t id); +sptr_t scintilla_send_message (ScintillaObject *sci,unsigned int iMessage, uptr_t wParam, sptr_t lParam); +void scintilla_release_resources(void); + +#if GTK_MAJOR_VERSION < 2 +#define SCINTILLA_NOTIFY "notify" +#else +#define SCINTILLA_NOTIFY "sci-notify" +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/SplitVector.h b/harbour/contrib/hbide/qscintilla/SplitVector.h new file mode 100644 index 0000000000..af4e890e3a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/SplitVector.h @@ -0,0 +1,249 @@ +// Scintilla source code edit control +/** @file SplitVector.h + ** Main data structure for holding arrays that handle insertions + ** and deletions efficiently. + **/ +// Copyright 1998-2007 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SPLITVECTOR_H +#define SPLITVECTOR_H + +template +class SplitVector { +protected: + T *body; + int size; + int lengthBody; + int part1Length; + int gapLength; /// invariant: gapLength == size - lengthBody + int growSize; + + /// Move the gap to a particular position so that insertion and + /// deletion at that point will not require much copying and + /// hence be fast. + void GapTo(int position) { + if (position != part1Length) { + if (position < part1Length) { + memmove( + body + position + gapLength, + body + position, + sizeof(T) * (part1Length - position)); + } else { // position > part1Length + memmove( + body + part1Length, + body + part1Length + gapLength, + sizeof(T) * (position - part1Length)); + } + part1Length = position; + } + } + + /// Check that there is room in the buffer for an insertion, + /// reallocating if more space needed. + void RoomFor(int insertionLength) { + if (gapLength <= insertionLength) { + while (growSize < size / 6) + growSize *= 2; + ReAllocate(size + insertionLength + growSize); + } + } + + void Init() { + body = NULL; + growSize = 8; + size = 0; + lengthBody = 0; + part1Length = 0; + gapLength = 0; + } + +public: + /// Construct a split buffer. + SplitVector() { + Init(); + } + + ~SplitVector() { + delete []body; + body = 0; + } + + int GetGrowSize() const { + return growSize; + } + + void SetGrowSize(int growSize_) { + growSize = growSize_; + } + + /// Reallocate the storage for the buffer to be newSize and + /// copy exisiting contents to the new buffer. + /// Must not be used to decrease the size of the buffer. + void ReAllocate(int newSize) { + if (newSize > size) { + // Move the gap to the end + GapTo(lengthBody); + T *newBody = new T[newSize]; + if ((size != 0) && (body != 0)) { + memmove(newBody, body, sizeof(T) * lengthBody); + delete []body; + } + body = newBody; + gapLength += newSize - size; + size = newSize; + } + } + + /// Retrieve the character at a particular position. + /// Retrieving positions outside the range of the buffer returns 0. + /// The assertions here are disabled since calling code can be + /// simpler if out of range access works and returns 0. + T ValueAt(int position) const { + if (position < part1Length) { + //PLATFORM_ASSERT(position >= 0); + if (position < 0) { + return 0; + } else { + return body[position]; + } + } else { + //PLATFORM_ASSERT(position < lengthBody); + if (position >= lengthBody) { + return 0; + } else { + return body[gapLength + position]; + } + } + } + + void SetValueAt(int position, T v) { + if (position < part1Length) { + PLATFORM_ASSERT(position >= 0); + if (position < 0) { + ; + } else { + body[position] = v; + } + } else { + PLATFORM_ASSERT(position < lengthBody); + if (position >= lengthBody) { + ; + } else { + body[gapLength + position] = v; + } + } + } + + T& operator[](int position) const { + PLATFORM_ASSERT(position >= 0 && position < lengthBody); + if (position < part1Length) { + return body[position]; + } else { + return body[gapLength + position]; + } + } + + /// Retrieve the length of the buffer. + int Length() const { + return lengthBody; + } + + /// Insert a single value into the buffer. + /// Inserting at positions outside the current range fails. + void Insert(int position, T v) { + PLATFORM_ASSERT((position >= 0) && (position <= lengthBody)); + if ((position < 0) || (position > lengthBody)) { + return; + } + RoomFor(1); + GapTo(position); + body[part1Length] = v; + lengthBody++; + part1Length++; + gapLength--; + } + + /// Insert a number of elements into the buffer setting their value. + /// Inserting at positions outside the current range fails. + void InsertValue(int position, int insertLength, T v) { + PLATFORM_ASSERT((position >= 0) && (position <= lengthBody)); + if (insertLength > 0) { + if ((position < 0) || (position > lengthBody)) { + return; + } + RoomFor(insertLength); + GapTo(position); + for (int i = 0; i < insertLength; i++) + body[part1Length + i] = v; + lengthBody += insertLength; + part1Length += insertLength; + gapLength -= insertLength; + } + } + + /// Ensure at least length elements allocated, + /// appending zero valued elements if needed. + void EnsureLength(int wantedLength) { + if (Length() < wantedLength) { + InsertValue(Length(), wantedLength - Length(), 0); + } + } + + /// Insert text into the buffer from an array. + void InsertFromArray(int positionToInsert, const T s[], int positionFrom, int insertLength) { + PLATFORM_ASSERT((positionToInsert >= 0) && (positionToInsert <= lengthBody)); + if (insertLength > 0) { + if ((positionToInsert < 0) || (positionToInsert > lengthBody)) { + return; + } + RoomFor(insertLength); + GapTo(positionToInsert); + memmove(body + part1Length, s + positionFrom, sizeof(T) * insertLength); + lengthBody += insertLength; + part1Length += insertLength; + gapLength -= insertLength; + } + } + + /// Delete one element from the buffer. + void Delete(int position) { + PLATFORM_ASSERT((position >= 0) && (position < lengthBody)); + if ((position < 0) || (position >= lengthBody)) { + return; + } + DeleteRange(position, 1); + } + + /// Delete a range from the buffer. + /// Deleting positions outside the current range fails. + void DeleteRange(int position, int deleteLength) { + PLATFORM_ASSERT((position >= 0) && (position + deleteLength <= lengthBody)); + if ((position < 0) || ((position + deleteLength) > lengthBody)) { + return; + } + if ((position == 0) && (deleteLength == lengthBody)) { + // Full deallocation returns storage and is faster + delete []body; + Init(); + } else if (deleteLength > 0) { + GapTo(position); + lengthBody -= deleteLength; + gapLength += deleteLength; + } + } + + /// Delete all the buffer contents. + void DeleteAll() { + DeleteRange(0, lengthBody); + } + + T* BufferPointer() { + RoomFor(1); + GapTo(lengthBody); + body[lengthBody] = 0; + return body; + } +}; + +#endif diff --git a/harbour/contrib/hbide/qscintilla/Style.cpp b/harbour/contrib/hbide/qscintilla/Style.cpp new file mode 100644 index 0000000000..ad081a66dd --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Style.cpp @@ -0,0 +1,158 @@ +// Scintilla source code edit control +/** @file Style.cxx + ** Defines the font and colour style for a class of text. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "Style.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +Style::Style() { + aliasOfDefaultFont = true; + Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), + Platform::DefaultFontSize(), 0, SC_CHARSET_DEFAULT, + false, false, false, false, caseMixed, true, true, false); +} + +Style::Style(const Style &source) { + Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), + 0, 0, 0, + false, false, false, false, caseMixed, true, true, false); + fore.desired = source.fore.desired; + back.desired = source.back.desired; + characterSet = source.characterSet; + bold = source.bold; + italic = source.italic; + size = source.size; + eolFilled = source.eolFilled; + underline = source.underline; + caseForce = source.caseForce; + visible = source.visible; + changeable = source.changeable; + hotspot = source.hotspot; +} + +Style::~Style() { + if (aliasOfDefaultFont) + font.SetID(0); + else + font.Release(); + aliasOfDefaultFont = false; +} + +Style &Style::operator=(const Style &source) { + if (this == &source) + return * this; + Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), + 0, 0, SC_CHARSET_DEFAULT, + false, false, false, false, caseMixed, true, true, false); + fore.desired = source.fore.desired; + back.desired = source.back.desired; + characterSet = source.characterSet; + bold = source.bold; + italic = source.italic; + size = source.size; + eolFilled = source.eolFilled; + underline = source.underline; + caseForce = source.caseForce; + visible = source.visible; + changeable = source.changeable; + return *this; +} + +void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_, + const char *fontName_, int characterSet_, + bool bold_, bool italic_, bool eolFilled_, + bool underline_, ecaseForced caseForce_, + bool visible_, bool changeable_, bool hotspot_) { + fore.desired = fore_; + back.desired = back_; + characterSet = characterSet_; + bold = bold_; + italic = italic_; + size = size_; + fontName = fontName_; + eolFilled = eolFilled_; + underline = underline_; + caseForce = caseForce_; + visible = visible_; + changeable = changeable_; + hotspot = hotspot_; + if (aliasOfDefaultFont) + font.SetID(0); + else + font.Release(); + aliasOfDefaultFont = false; +} + +void Style::ClearTo(const Style &source) { + Clear( + source.fore.desired, + source.back.desired, + source.size, + source.fontName, + source.characterSet, + source.bold, + source.italic, + source.eolFilled, + source.underline, + source.caseForce, + source.visible, + source.changeable, + source.hotspot); +} + +bool Style::EquivalentFontTo(const Style *other) const { + if (bold != other->bold || + italic != other->italic || + size != other->size || + characterSet != other->characterSet) + return false; + if (fontName == other->fontName) + return true; + if (!fontName) + return false; + if (!other->fontName) + return false; + return strcmp(fontName, other->fontName) == 0; +} + +void Style::Realise(Surface &surface, int zoomLevel, Style *defaultStyle, bool extraFontFlag) { + sizeZoomed = size + zoomLevel; + if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2; + + if (aliasOfDefaultFont) + font.SetID(0); + else + font.Release(); + int deviceHeight = surface.DeviceHeightFont(sizeZoomed); + aliasOfDefaultFont = defaultStyle && + (EquivalentFontTo(defaultStyle) || !fontName); + if (aliasOfDefaultFont) { + font.SetID(defaultStyle->font.GetID()); + } else if (fontName) { + font.Create(fontName, characterSet, deviceHeight, bold, italic, extraFontFlag); + } else { + font.SetID(0); + } + + ascent = surface.Ascent(font); + descent = surface.Descent(font); + // Probably more typographically correct to include leading + // but that means more complex drawing as leading must be erased + //lineHeight = surface.ExternalLeading() + surface.Height(); + externalLeading = surface.ExternalLeading(font); + lineHeight = surface.Height(font); + aveCharWidth = surface.AverageCharWidth(font); + spaceWidth = surface.WidthChar(font, ' '); +} diff --git a/harbour/contrib/hbide/qscintilla/Style.h b/harbour/contrib/hbide/qscintilla/Style.h new file mode 100644 index 0000000000..1caecaee73 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/Style.h @@ -0,0 +1,64 @@ +// Scintilla source code edit control +/** @file Style.h + ** Defines the font and colour style for a class of text. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef STYLE_H +#define STYLE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class Style { +public: + ColourPair fore; + ColourPair back; + bool aliasOfDefaultFont; + bool bold; + bool italic; + int size; + const char *fontName; + int characterSet; + bool eolFilled; + bool underline; + enum ecaseForced {caseMixed, caseUpper, caseLower}; + ecaseForced caseForce; + bool visible; + bool changeable; + bool hotspot; + + Font font; + int sizeZoomed; + unsigned int lineHeight; + unsigned int ascent; + unsigned int descent; + unsigned int externalLeading; + unsigned int aveCharWidth; + unsigned int spaceWidth; + + Style(); + Style(const Style &source); + ~Style(); + Style &operator=(const Style &source); + void Clear(ColourDesired fore_, ColourDesired back_, + int size_, + const char *fontName_, int characterSet_, + bool bold_, bool italic_, bool eolFilled_, + bool underline_, ecaseForced caseForce_, + bool visible_, bool changeable_, bool hotspot_); + void ClearTo(const Style &source); + bool EquivalentFontTo(const Style *other) const; + void Realise(Surface &surface, int zoomLevel, Style *defaultStyle = 0, bool extraFontFlag = false); + bool IsProtected() const { return !(changeable && visible);}; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/StyleContext.cpp b/harbour/contrib/hbide/qscintilla/StyleContext.cpp new file mode 100644 index 0000000000..d7bbd53344 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/StyleContext.cpp @@ -0,0 +1,55 @@ +// Scintilla source code edit control +/** @file StyleContext.cxx + ** Lexer infrastructure. + **/ +// Copyright 1998-2004 by Neil Hodgson +// This file is in the public domain. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static void getRange(unsigned int start, + unsigned int end, + Accessor &styler, + char *s, + unsigned int len) { + unsigned int i = 0; + while ((i < end - start + 1) && (i < len-1)) { + s[i] = styler[start + i]; + i++; + } + s[i] = '\0'; +} + +void StyleContext::GetCurrent(char *s, unsigned int len) { + getRange(styler.GetStartSegment(), currentPos - 1, styler, s, len); +} + +static void getRangeLowered(unsigned int start, + unsigned int end, + Accessor &styler, + char *s, + unsigned int len) { + unsigned int i = 0; + while ((i < end - start + 1) && (i < len-1)) { + s[i] = static_cast(tolower(styler[start + i])); + i++; + } + s[i] = '\0'; +} + +void StyleContext::GetCurrentLowered(char *s, unsigned int len) { + getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len); +} diff --git a/harbour/contrib/hbide/qscintilla/StyleContext.h b/harbour/contrib/hbide/qscintilla/StyleContext.h new file mode 100644 index 0000000000..463aab462a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/StyleContext.h @@ -0,0 +1,179 @@ +// Scintilla source code edit control +/** @file StyleContext.cxx + ** Lexer infrastructure. + **/ +// Copyright 1998-2004 by Neil Hodgson +// This file is in the public domain. + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +// All languages handled so far can treat all characters >= 0x80 as one class +// which just continues the current token or starts an identifier if in default. +// DBCS treated specially as the second character can be < 0x80 and hence +// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80 +class StyleContext { + Accessor &styler; + unsigned int endPos; + StyleContext& operator=(const StyleContext&) { + return *this; + } + void GetNextChar(unsigned int pos) { + chNext = static_cast(styler.SafeGetCharAt(pos+1)); + if (styler.IsLeadByte(static_cast(chNext))) { + chNext = chNext << 8; + chNext |= static_cast(styler.SafeGetCharAt(pos+2)); + } + // End of line? + // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) + // or on LF alone (Unix). Avoid triggering two times on Dos/Win. + atLineEnd = (ch == '\r' && chNext != '\n') || + (ch == '\n') || + (currentPos >= endPos); + } + +public: + unsigned int currentPos; + bool atLineStart; + bool atLineEnd; + int state; + int chPrev; + int ch; + int chNext; + + StyleContext(unsigned int startPos, unsigned int length, + int initStyle, Accessor &styler_, char chMask=31) : + styler(styler_), + endPos(startPos + length), + currentPos(startPos), + atLineStart(true), + atLineEnd(false), + state(initStyle & chMask), // Mask off all bits which aren't in the chMask. + chPrev(0), + ch(0), + chNext(0) { + styler.StartAt(startPos, chMask); + styler.StartSegment(startPos); + unsigned int pos = currentPos; + ch = static_cast(styler.SafeGetCharAt(pos)); + if (styler.IsLeadByte(static_cast(ch))) { + pos++; + ch = ch << 8; + ch |= static_cast(styler.SafeGetCharAt(pos)); + } + GetNextChar(pos); + } + void Complete() { + styler.ColourTo(currentPos - 1, state); + } + bool More() { + return currentPos < endPos; + } + void Forward() { + if (currentPos < endPos) { + atLineStart = atLineEnd; + chPrev = ch; + currentPos++; + if (ch >= 0x100) + currentPos++; + ch = chNext; + GetNextChar(currentPos + ((ch >= 0x100) ? 1 : 0)); + } else { + atLineStart = false; + chPrev = ' '; + ch = ' '; + chNext = ' '; + atLineEnd = true; + } + } + void Forward(int nb) { + for (int i = 0; i < nb; i++) { + Forward(); + } + } + void ChangeState(int state_) { + state = state_; + } + void SetState(int state_) { + styler.ColourTo(currentPos - 1, state); + state = state_; + } + void ForwardSetState(int state_) { + Forward(); + styler.ColourTo(currentPos - 1, state); + state = state_; + } + int LengthCurrent() { + return currentPos - styler.GetStartSegment(); + } + int GetRelative(int n) { + return static_cast(styler.SafeGetCharAt(currentPos+n)); + } + bool Match(char ch0) { + return ch == static_cast(ch0); + } + bool Match(char ch0, char ch1) { + return (ch == static_cast(ch0)) && (chNext == static_cast(ch1)); + } + bool Match(const char *s) { + if (ch != static_cast(*s)) + return false; + s++; + if (!*s) + return true; + if (chNext != static_cast(*s)) + return false; + s++; + for (int n=2; *s; n++) { + if (*s != styler.SafeGetCharAt(currentPos+n)) + return false; + s++; + } + return true; + } + bool MatchIgnoreCase(const char *s) { + if (tolower(ch) != static_cast(*s)) + return false; + s++; + if (tolower(chNext) != static_cast(*s)) + return false; + s++; + for (int n=2; *s; n++) { + if (static_cast(*s) != + tolower(static_cast(styler.SafeGetCharAt(currentPos+n)))) + return false; + s++; + } + return true; + } + // Non-inline + void GetCurrent(char *s, unsigned int len); + void GetCurrentLowered(char *s, unsigned int len); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +inline bool IsASpace(unsigned int ch) { + return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); +} + +inline bool IsASpaceOrTab(unsigned int ch) { + return (ch == ' ') || (ch == '\t'); +} + +inline bool IsADigit(unsigned int ch) { + return (ch >= '0') && (ch <= '9'); +} + +inline bool IsADigit(unsigned int ch, unsigned int base) { + if (base <= 10) { + return (ch >= '0') && (ch < '0' + base); + } else { + return ((ch >= '0') && (ch <= '9')) || + ((ch >= 'A') && (ch < 'A' + base - 10)) || + ((ch >= 'a') && (ch < 'a' + base - 10)); + } +} diff --git a/harbour/contrib/hbide/qscintilla/UniConversion.cpp b/harbour/contrib/hbide/qscintilla/UniConversion.cpp new file mode 100644 index 0000000000..7dbe9e23de --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/UniConversion.cpp @@ -0,0 +1,119 @@ +// Scintilla source code edit control +/** @file UniConversion.cxx + ** Functions to handle UFT-8 and UCS-2 strings. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "UniConversion.h" + +enum { SURROGATE_LEAD_FIRST = 0xD800 }; +enum { SURROGATE_TRAIL_FIRST = 0xDC00 }; +enum { SURROGATE_TRAIL_LAST = 0xDFFF }; + +unsigned int UTF8Length(const wchar_t *uptr, unsigned int tlen) { + unsigned int len = 0; + for (unsigned int i = 0; i < tlen && uptr[i];) { + unsigned int uch = uptr[i]; + if (uch < 0x80) { + len++; + } else if (uch < 0x800) { + len += 2; + } else if ((uch >= SURROGATE_LEAD_FIRST) && + (uch <= SURROGATE_TRAIL_LAST)) { + len += 4; + i++; + } else { + len += 3; + } + i++; + } + return len; +} + +void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len) { + int k = 0; + for (unsigned int i = 0; i < tlen && uptr[i];) { + unsigned int uch = uptr[i]; + if (uch < 0x80) { + putf[k++] = static_cast(uch); + } else if (uch < 0x800) { + putf[k++] = static_cast(0xC0 | (uch >> 6)); + putf[k++] = static_cast(0x80 | (uch & 0x3f)); + } else if ((uch >= SURROGATE_LEAD_FIRST) && + (uch <= SURROGATE_TRAIL_LAST)) { + // Half a surrogate pair + i++; + unsigned int xch = 0x10000 + ((uch & 0x3ff) << 10) + (uptr[i] & 0x3ff); + putf[k++] = static_cast(0xF0 | (xch >> 18)); + putf[k++] = static_cast(0x80 | ((xch >> 12) & 0x3f)); + putf[k++] = static_cast(0x80 | ((xch >> 6) & 0x3f)); + putf[k++] = static_cast(0x80 | (xch & 0x3f)); + } else { + putf[k++] = static_cast(0xE0 | (uch >> 12)); + putf[k++] = static_cast(0x80 | ((uch >> 6) & 0x3f)); + putf[k++] = static_cast(0x80 | (uch & 0x3f)); + } + i++; + } + putf[len] = '\0'; +} + +unsigned int UTF16Length(const char *s, unsigned int len) { + unsigned int ulen = 0; + unsigned int charLen; + for (unsigned int i=0;i(s[i]); + if (ch < 0x80) { + charLen = 1; + } else if (ch < 0x80 + 0x40 + 0x20) { + charLen = 2; + } else if (ch < 0x80 + 0x40 + 0x20 + 0x10) { + charLen = 3; + } else { + charLen = 4; + ulen++; + } + i += charLen; + ulen++; + } + return ulen; +} + +unsigned int UTF16FromUTF8(const char *s, unsigned int len, wchar_t *tbuf, unsigned int tlen) { + unsigned int ui=0; + const unsigned char *us = reinterpret_cast(s); + unsigned int i=0; + while ((i((ch & 0x1F) << 6); + ch = us[i++]; + tbuf[ui] = static_cast(tbuf[ui] + (ch & 0x7F)); + } else if (ch < 0x80 + 0x40 + 0x20 + 0x10) { + tbuf[ui] = static_cast((ch & 0xF) << 12); + ch = us[i++]; + tbuf[ui] = static_cast(tbuf[ui] + ((ch & 0x7F) << 6)); + ch = us[i++]; + tbuf[ui] = static_cast(tbuf[ui] + (ch & 0x7F)); + } else { + // Outside the BMP so need two surrogates + int val = (ch & 0x7) << 18; + ch = us[i++]; + val += (ch & 0x3F) << 12; + ch = us[i++]; + val += (ch & 0x3F) << 6; + ch = us[i++]; + val += (ch & 0x3F); + tbuf[ui] = static_cast(((val - 0x10000) >> 10) + SURROGATE_LEAD_FIRST); + ui++; + tbuf[ui] = static_cast((val & 0x3ff) + SURROGATE_TRAIL_FIRST); + } + ui++; + } + return ui; +} diff --git a/harbour/contrib/hbide/qscintilla/UniConversion.h b/harbour/contrib/hbide/qscintilla/UniConversion.h new file mode 100644 index 0000000000..fd420a6884 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/UniConversion.h @@ -0,0 +1,12 @@ +// Scintilla source code edit control +/** @file UniConversion.h + ** Functions to handle UFT-8 and UCS-2 strings. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +unsigned int UTF8Length(const wchar_t *uptr, unsigned int tlen); +void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len); +unsigned int UTF16Length(const char *s, unsigned int len); +unsigned int UTF16FromUTF8(const char *s, unsigned int len, wchar_t *tbuf, unsigned int tlen); + diff --git a/harbour/contrib/hbide/qscintilla/ViewStyle.cpp b/harbour/contrib/hbide/qscintilla/ViewStyle.cpp new file mode 100644 index 0000000000..fdcd114b91 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/ViewStyle.cpp @@ -0,0 +1,376 @@ +// Scintilla source code edit control +/** @file ViewStyle.cxx + ** Store information on how the document is to be viewed. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +MarginStyle::MarginStyle() : + style(SC_MARGIN_SYMBOL), width(0), mask(0), sensitive(false) { +} + +// A list of the fontnames - avoids wasting space in each style +FontNames::FontNames() { + size = 8; + names = new char *[size]; + max = 0; +} + +FontNames::~FontNames() { + Clear(); + delete []names; + names = 0; +} + +void FontNames::Clear() { + for (int i=0;i= size) { + // Grow array + int sizeNew = size * 2; + char **namesNew = new char *[sizeNew]; + for (int j=0;j 0) + maskInLine &= ~ms[margin].mask; + } + zoomLevel = 0; + viewWhitespace = wsInvisible; + viewIndentationGuides = ivNone; + viewEOL = false; + showMarkedLines = true; + extraFontFlag = false; + extraAscent = 0; + extraDescent = 0; + marginStyleOffset = 0; + annotationVisible = ANNOTATION_HIDDEN; + annotationStyleOffset = 0; +} + +void ViewStyle::RefreshColourPalette(Palette &pal, bool want) { + unsigned int i; + for (i=0;i 0) + maskInLine &= ~ms[margin].mask; + } +} + +void ViewStyle::AllocStyles(size_t sizeNew) { + Style *stylesNew = new Style[sizeNew]; + size_t i=0; + for (; i STYLE_DEFAULT) { + for (; i= stylesSize) { + size_t sizeNew = stylesSize * 2; + while (sizeNew <= index) + sizeNew *= 2; + AllocStyles(sizeNew); + } +} + +void ViewStyle::ResetDefaultStyle() { + styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0), + ColourDesired(0xff,0xff,0xff), + Platform::DefaultFontSize(), fontNames.Save(Platform::DefaultFont()), + SC_CHARSET_DEFAULT, + false, false, false, false, Style::caseMixed, true, true, false); +} + +void ViewStyle::ClearStyles() { + // Reset all styles to be like the default style + for (unsigned int i=0; i +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef VIEWSTYLE_H +#define VIEWSTYLE_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class MarginStyle { +public: + int style; + int width; + int mask; + bool sensitive; + MarginStyle(); +}; + +/** + */ +class FontNames { +private: + char **names; + int size; + int max; + +public: + FontNames(); + ~FontNames(); + void Clear(); + const char *Save(const char *name); +}; + +enum IndentView {ivNone, ivReal, ivLookForward, ivLookBoth}; + +enum WhiteSpaceVisibility {wsInvisible=0, wsVisibleAlways=1, wsVisibleAfterIndent=2}; + +/** + */ +class ViewStyle { +public: + FontNames fontNames; + size_t stylesSize; + Style *styles; + LineMarker markers[MARKER_MAX + 1]; + Indicator indicators[INDIC_MAX + 1]; + int lineHeight; + unsigned int maxAscent; + unsigned int maxDescent; + unsigned int aveCharWidth; + unsigned int spaceWidth; + bool selforeset; + ColourPair selforeground; + bool selbackset; + ColourPair selbackground; + ColourPair selbackground2; + int selAlpha; + bool selEOLFilled; + bool whitespaceForegroundSet; + ColourPair whitespaceForeground; + bool whitespaceBackgroundSet; + ColourPair whitespaceBackground; + ColourPair selbar; + ColourPair selbarlight; + bool foldmarginColourSet; + ColourPair foldmarginColour; + bool foldmarginHighlightColourSet; + ColourPair foldmarginHighlightColour; + bool hotspotForegroundSet; + ColourPair hotspotForeground; + bool hotspotBackgroundSet; + ColourPair hotspotBackground; + bool hotspotUnderline; + bool hotspotSingleLine; + /// Margins are ordered: Line Numbers, Selection Margin, Spacing Margin + enum { margins=5 }; + int leftMarginWidth; ///< Spacing margin on left of text + int rightMarginWidth; ///< Spacing margin on left of text + bool symbolMargin; + int maskInLine; ///< Mask for markers to be put into text because there is nowhere for them to go in margin + MarginStyle ms[margins]; + int fixedColumnWidth; + int zoomLevel; + WhiteSpaceVisibility viewWhitespace; + IndentView viewIndentationGuides; + bool viewEOL; + bool showMarkedLines; + ColourPair caretcolour; + bool showCaretLineBackground; + ColourPair caretLineBackground; + int caretLineAlpha; + ColourPair edgecolour; + int edgeState; + int caretStyle; + int caretWidth; + bool someStylesProtected; + bool extraFontFlag; + int extraAscent; + int extraDescent; + int marginStyleOffset; + int annotationVisible; + int annotationStyleOffset; + + ViewStyle(); + ViewStyle(const ViewStyle &source); + ~ViewStyle(); + void Init(size_t stylesSize_=64); + void RefreshColourPalette(Palette &pal, bool want); + void Refresh(Surface &surface); + void AllocStyles(size_t sizeNew); + void EnsureStyle(size_t index); + void ResetDefaultStyle(); + void ClearStyles(); + void SetStyleFontName(int styleIndex, const char *name); + bool ProtectionActive() const; + bool ValidStyle(size_t styleIndex) const; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/WindowAccessor.cpp b/harbour/contrib/hbide/qscintilla/WindowAccessor.cpp new file mode 100644 index 0000000000..8093300bc0 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/WindowAccessor.cpp @@ -0,0 +1,191 @@ +// Scintilla source code edit control +/** @file WindowAccessor.cxx + ** Rapid easy access to contents of a Scintilla. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "WindowAccessor.h" +#include "Scintilla.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +WindowAccessor::~WindowAccessor() { +} + +bool WindowAccessor::InternalIsLeadByte(char ch) { + if (SC_CP_UTF8 == codePage) + // For lexing, all characters >= 0x80 are treated the + // same so none is considered a lead byte. + return false; + else + return Platform::IsDBCSLeadByte(codePage, ch); +} + +void WindowAccessor::Fill(int position) { + if (lenDoc == -1) + lenDoc = Platform::SendScintilla(id, SCI_GETTEXTLENGTH, 0, 0); + startPos = position - slopSize; + if (startPos + bufferSize > lenDoc) + startPos = lenDoc - bufferSize; + if (startPos < 0) + startPos = 0; + endPos = startPos + bufferSize; + if (endPos > lenDoc) + endPos = lenDoc; + + TextRange tr = {{startPos, endPos}, buf}; + Platform::SendScintillaPointer(id, SCI_GETTEXTRANGE, 0, &tr); +} + +bool WindowAccessor::Match(int pos, const char *s) { + for (int i=0; *s; i++) { + if (*s != SafeGetCharAt(pos+i)) + return false; + s++; + } + return true; +} + +char WindowAccessor::StyleAt(int position) { + return static_cast(Platform::SendScintilla( + id, SCI_GETSTYLEAT, position, 0)); +} + +int WindowAccessor::GetLine(int position) { + return Platform::SendScintilla(id, SCI_LINEFROMPOSITION, position, 0); +} + +int WindowAccessor::LineStart(int line) { + return Platform::SendScintilla(id, SCI_POSITIONFROMLINE, line, 0); +} + +int WindowAccessor::LevelAt(int line) { + return Platform::SendScintilla(id, SCI_GETFOLDLEVEL, line, 0); +} + +int WindowAccessor::Length() { + if (lenDoc == -1) + lenDoc = Platform::SendScintilla(id, SCI_GETTEXTLENGTH, 0, 0); + return lenDoc; +} + +int WindowAccessor::GetLineState(int line) { + return Platform::SendScintilla(id, SCI_GETLINESTATE, line); +} + +int WindowAccessor::SetLineState(int line, int state) { + return Platform::SendScintilla(id, SCI_SETLINESTATE, line, state); +} + +void WindowAccessor::StartAt(unsigned int start, char chMask) { + Platform::SendScintilla(id, SCI_STARTSTYLING, start, chMask); +} + +void WindowAccessor::StartSegment(unsigned int pos) { + startSeg = pos; +} + +void WindowAccessor::ColourTo(unsigned int pos, int chAttr) { + // Only perform styling if non empty range + if (pos != startSeg - 1) { + if (pos < startSeg) { + Platform::DebugPrintf("Bad colour positions %d - %d\n", startSeg, pos); + } + + if (validLen + (pos - startSeg + 1) >= bufferSize) + Flush(); + if (validLen + (pos - startSeg + 1) >= bufferSize) { + // Too big for buffer so send directly + Platform::SendScintilla(id, SCI_SETSTYLING, pos - startSeg + 1, chAttr); + } else { + if (chAttr != chWhile) + chFlags = 0; + chAttr |= chFlags; + for (unsigned int i = startSeg; i <= pos; i++) { + styleBuf[validLen++] = static_cast(chAttr); + } + } + } + startSeg = pos+1; +} + +void WindowAccessor::SetLevel(int line, int level) { + Platform::SendScintilla(id, SCI_SETFOLDLEVEL, line, level); +} + +void WindowAccessor::Flush() { + startPos = extremePosition; + lenDoc = -1; + if (validLen > 0) { + Platform::SendScintillaPointer(id, SCI_SETSTYLINGEX, validLen, + styleBuf); + validLen = 0; + } +} + +int WindowAccessor::IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader) { + int end = Length(); + int spaceFlags = 0; + + // Determines the indentation level of the current line and also checks for consistent + // indentation compared to the previous line. + // Indentation is judged consistent when the indentation whitespace of each line lines + // the same or the indentation of one line is a prefix of the other. + + int pos = LineStart(line); + char ch = (*this)[pos]; + int indent = 0; + bool inPrevPrefix = line > 0; + int posPrev = inPrevPrefix ? LineStart(line-1) : 0; + while ((ch == ' ' || ch == '\t') && (pos < end)) { + if (inPrevPrefix) { + char chPrev = (*this)[posPrev++]; + if (chPrev == ' ' || chPrev == '\t') { + if (chPrev != ch) + spaceFlags |= wsInconsistent; + } else { + inPrevPrefix = false; + } + } + if (ch == ' ') { + spaceFlags |= wsSpace; + indent++; + } else { // Tab + spaceFlags |= wsTab; + if (spaceFlags & wsSpace) + spaceFlags |= wsSpaceTab; + indent = (indent / 8 + 1) * 8; + } + ch = (*this)[++pos]; + } + + *flags = spaceFlags; + indent += SC_FOLDLEVELBASE; + // if completely empty line or the start of a comment... + if (isspace(ch) || (pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos)) ) + return indent | SC_FOLDLEVELWHITEFLAG; + else + return indent; +} + +void WindowAccessor::IndicatorFill(int start, int end, int indicator, int value) { + Platform::SendScintilla(id, SCI_SETINDICATORCURRENT, indicator); + if (value) { + Platform::SendScintilla(id, SCI_SETINDICATORVALUE, value); + Platform::SendScintilla(id, SCI_INDICATORFILLRANGE, start, end - start); + } else { + Platform::SendScintilla(id, SCI_INDICATORCLEARRANGE, start, end - start); + } +} diff --git a/harbour/contrib/hbide/qscintilla/WindowAccessor.h b/harbour/contrib/hbide/qscintilla/WindowAccessor.h new file mode 100644 index 0000000000..e107a0659c --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/WindowAccessor.h @@ -0,0 +1,66 @@ +// Scintilla source code edit control +/** @file WindowAccessor.h + ** Implementation of BufferAccess and StylingAccess on a Scintilla + ** rapid easy access to contents of a Scintilla. + **/ +// Copyright 1998-2001 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + */ +class WindowAccessor : public Accessor { + // Private so WindowAccessor objects can not be copied + WindowAccessor(const WindowAccessor &source) : Accessor(), props(source.props) {} + WindowAccessor &operator=(const WindowAccessor &) { return *this; } +protected: + WindowID id; + PropSet &props; + int lenDoc; + + char styleBuf[bufferSize]; + int validLen; + char chFlags; + char chWhile; + unsigned int startSeg; + + bool InternalIsLeadByte(char ch); + void Fill(int position); +public: + WindowAccessor(WindowID id_, PropSet &props_) : + Accessor(), id(id_), props(props_), + lenDoc(-1), validLen(0), chFlags(0), chWhile(0) { + } + ~WindowAccessor(); + bool Match(int pos, const char *s); + char StyleAt(int position); + int GetLine(int position); + int LineStart(int line); + int LevelAt(int line); + int Length(); + void Flush(); + int GetLineState(int line); + int SetLineState(int line, int state); + int GetPropertyInt(const char *key, int defaultValue=0) { + return props.GetInt(key, defaultValue); + } + char *GetProperties() { + return props.ToString(); + } + + void StartAt(unsigned int start, char chMask=31); + void SetFlags(char chFlags_, char chWhile_) {chFlags = chFlags_; chWhile = chWhile_; }; + unsigned int GetStartSegment() { return startSeg; } + void StartSegment(unsigned int pos); + void ColourTo(unsigned int pos, int chAttr); + void SetLevel(int line, int level); + int IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); + void IndicatorFill(int start, int end, int indicator, int value); +}; + +#ifdef SCI_NAMESPACE +} +#endif diff --git a/harbour/contrib/hbide/qscintilla/XPM.cpp b/harbour/contrib/hbide/qscintilla/XPM.cpp new file mode 100644 index 0000000000..5faaa67bd0 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/XPM.cpp @@ -0,0 +1,354 @@ +// Scintilla source code edit control +/** @file XPM.cxx + ** Define a class that holds data in the X Pixmap (XPM) format. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "XPM.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +#if defined(PLAT_QT) + +XPM::XPM(const char *textForm) +{ + qpm = *reinterpret_cast(textForm); +} + +XPM::XPM(const char * const *linesForm) +{ + qpm = *reinterpret_cast(linesForm); +} + +void XPM::RefreshColourPalette(Palette &pal, bool want) +{ + Q_UNUSED( pal ); + Q_UNUSED( want ); + // Nothing to do. +} + +void XPM::Draw(Surface *surface, PRectangle &rc) +{ + surface -> DrawXPM(rc,this); +} + +#else + +static const char *NextField(const char *s) { + // In case there are leading spaces in the string + while (*s && *s == ' ') { + s++; + } + while (*s && *s != ' ') { + s++; + } + while (*s && *s == ' ') { + s++; + } + return s; +} + +// Data lines in XPM can be terminated either with NUL or " +static size_t MeasureLength(const char *s) { + size_t i = 0; + while (s[i] && (s[i] != '\"')) + i++; + return i; +} + +ColourAllocated XPM::ColourFromCode(int ch) { + return colourCodeTable[ch]->allocated; +#ifdef SLOW + for (int i=0; iFillRectangle(rc, ColourFromCode(code)); + } +} + +XPM::XPM(const char *textForm) : + data(0), codes(0), colours(0), lines(0) { + Init(textForm); +} + +XPM::XPM(const char * const *linesForm) : + data(0), codes(0), colours(0), lines(0) { + Init(linesForm); +} + +XPM::~XPM() { + Clear(); +} + +void XPM::Init(const char *textForm) { + Clear(); + // Test done is two parts to avoid possibility of overstepping the memory + // if memcmp implemented strangely. Must be 4 bytes at least at destination. + if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) { + // Build the lines form out of the text form + const char **linesForm = LinesFormFromTextForm(textForm); + if (linesForm != 0) { + Init(linesForm); + delete []linesForm; + } + } else { + // It is really in line form + Init(reinterpret_cast(textForm)); + } +} + +void XPM::Init(const char * const *linesForm) { + Clear(); + height = 1; + width = 1; + nColours = 1; + data = NULL; + codeTransparent = ' '; + codes = NULL; + colours = NULL; + lines = NULL; + if (!linesForm) + return; + + const char *line0 = linesForm[0]; + width = atoi(line0); + line0 = NextField(line0); + height = atoi(line0); + line0 = NextField(line0); + nColours = atoi(line0); + line0 = NextField(line0); + if (atoi(line0) != 1) { + // Only one char per pixel is supported + return; + } + codes = new char[nColours]; + colours = new ColourPair[nColours]; + + int strings = 1+height+nColours; + lines = new char *[strings]; + size_t allocation = 0; + for (int i=0; i(codes[c])] = &(colours[c]); + } +} + +void XPM::Clear() { + delete []data; + data = 0; + delete []codes; + codes = 0; + delete []colours; + colours = 0; + delete []lines; + lines = 0; +} + +void XPM::RefreshColourPalette(Palette &pal, bool want) { + if (!data || !codes || !colours || !lines) { + return; + } + for (int i=0; i= strings) { + break; // Bad height or number of colors! + } + if ((countQuotes & 1) == 0) { + linesForm[countQuotes / 2] = textForm + j + 1; + } + countQuotes++; + } + } + if (textForm[j] == '\0' || countQuotes / 2 > strings) { + // Malformed XPM! Height + number of colors too high or too low + delete []linesForm; + linesForm = 0; + } + return linesForm; +} + +// In future, may want to minimize search time by sorting and using a binary search. + +XPMSet::XPMSet() : set(0), len(0), maximum(0), height(-1), width(-1) { +} + +XPMSet::~XPMSet() { + Clear(); +} + +void XPMSet::Clear() { + for (int i = 0; i < len; i++) { + delete set[i]; + } + delete []set; + set = 0; + len = 0; + maximum = 0; + height = -1; + width = -1; +} + +void XPMSet::Add(int id, const char *textForm) { + // Invalidate cached dimensions + height = -1; + width = -1; + + // Replace if this id already present + for (int i = 0; i < len; i++) { + if (set[i]->GetId() == id) { + set[i]->Init(textForm); + set[i]->CopyDesiredColours(); + return; + } + } + + // Not present, so add to end + XPM *pxpm = new XPM(textForm); + if (pxpm) { + pxpm->SetId(id); + pxpm->CopyDesiredColours(); + if (len == maximum) { + maximum += 64; + XPM **setNew = new XPM *[maximum]; + for (int i = 0; i < len; i++) { + setNew[i] = set[i]; + } + delete []set; + set = setNew; + } + set[len] = pxpm; + len++; + } +} + +XPM *XPMSet::Get(int id) { + for (int i = 0; i < len; i++) { + if (set[i]->GetId() == id) { + return set[i]; + } + } + return 0; +} + +int XPMSet::GetHeight() { + if (height < 0) { + for (int i = 0; i < len; i++) { + if (height < set[i]->GetHeight()) { + height = set[i]->GetHeight(); + } + } + } + return (height > 0) ? height : 0; +} + +int XPMSet::GetWidth() { + if (width < 0) { + for (int i = 0; i < len; i++) { + if (width < set[i]->GetWidth()) { + width = set[i]->GetWidth(); + } + } + } + return (width > 0) ? width : 0; +} + +#endif diff --git a/harbour/contrib/hbide/qscintilla/XPM.h b/harbour/contrib/hbide/qscintilla/XPM.h new file mode 100644 index 0000000000..a610c91fd5 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/XPM.h @@ -0,0 +1,102 @@ +// Scintilla source code edit control +/** @file XPM.h + ** Define a class that holds data in the X Pixmap (XPM) format. + **/ +// Copyright 1998-2003 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef XPM_H +#define XPM_H + +#if defined(PLAT_QT) +#include +#endif + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** + * Hold a pixmap in XPM format. + */ +class XPM { +#if defined(PLAT_QT) + QPixmap qpm; + +public: + XPM(const char *textForm); + XPM(const char * const *linesForm); + ~XPM() {} + + void RefreshColourPalette(Palette &pal, bool want); + void Draw(Surface *surface,PRectangle &rc); + + const QPixmap &Pixmap() const {return qpm;} +#else + int id; // Assigned by container + int height; + int width; + int nColours; + char *data; + char codeTransparent; + char *codes; + ColourPair *colours; + ColourAllocated ColourFromCode(int ch); + void FillRun(Surface *surface, int code, int startX, int y, int x); + char **lines; + ColourPair *colourCodeTable[256]; +public: + XPM(const char *textForm); + XPM(const char * const *linesForm); + ~XPM(); + void Init(const char *textForm); + void Init(const char * const *linesForm); + void Clear(); + /// Similar to same named method in ViewStyle: + void RefreshColourPalette(Palette &pal, bool want); + /// No palette used, so just copy the desired colours to the allocated colours + void CopyDesiredColours(); + /// Decompose image into runs and use FillRectangle for each run + void Draw(Surface *surface, PRectangle &rc); + char **InLinesForm() { return lines; } + void SetId(int id_) { id = id_; } + int GetId() { return id; } + int GetHeight() { return height; } + int GetWidth() { return width; } + static const char **LinesFormFromTextForm(const char *textForm); +#endif +}; + +#if !defined(PLAT_QT) + +/** + * A collection of pixmaps indexed by integer id. + */ +class XPMSet { + XPM **set; ///< The stored XPMs. + int len; ///< Current number of XPMs. + int maximum; ///< Current maximum number of XPMs, increased by steps if reached. + int height; ///< Memorize largest height of the set. + int width; ///< Memorize largest width of the set. +public: + XPMSet(); + ~XPMSet(); + /// Remove all XPMs. + void Clear(); + /// Add a XPM. + void Add(int id, const char *textForm); + /// Get XPM by id. + XPM *Get(int id); + /// Give the largest height of the set. + int GetHeight(); + /// Give the largest width of the set. + int GetWidth(); +}; + +#endif + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qscintilla.hbp b/harbour/contrib/hbide/qscintilla/qscintilla.hbp new file mode 100644 index 0000000000..687930fbe8 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qscintilla.hbp @@ -0,0 +1,77 @@ +-3rd=hbide_version=1.0 +-3rd=hbide_type=Lib +-3rd=hbide_title=qscintilla +-3rd=hbide_location=C:\harbour\contrib\hbide\qscintilla\ +-3rd=hbide_workingfolder= +-3rd=hbide_destinationfolder= +-3rd=hbide_output=qscintilla +-3rd=hbide_launchparams= +-3rd=hbide_launchprogram= +-3rd=hbide_backupfolder= +-3rd=hbide_xhb=NO +-3rd=hbide_xpp=NO +-3rd=hbide_clp=NO + +-inc +-w2 +-es2 +-incpath=. +-incpath=./qt +-incpath=${HB_WITH_QT}/include +-incpath=${HB_WITH_QT}/include/qtcore +-incpath=${HB_WITH_QT}/include/qtgui +-oqscintilla +-hblib + +../../hbqt/hbqt.hbc +AutoComplete.cpp +CallTip.cpp +Decoration.cpp +Document.cpp +DocumentAccessor.cpp +Editor.cpp +ExternalLexer.cpp +Indicator.cpp +KeyMap.cpp +KeyWords.cpp +LexCPP.cpp +LexFlagship.cpp +LineMarker.cpp +CellBuffer.cpp +CharClassify.cpp +ContractionState.cpp +PerLine.cpp +PositionCache.cpp +PropSet.cpp +RESearch.cpp +RunStyles.cpp +ScintillaBase.cpp +Style.cpp +StyleContext.cpp +UniConversion.cpp +ViewStyle.cpp +WindowAccessor.cpp +XPM.cpp +qt/ListBoxQt.cpp +qt/moc_qscilexer.cpp +qt/moc_qscilexercpp.cpp +qt/moc_qsciscintilla.cpp +qt/moc_qsciscintillabase.cpp +qt/moc_SciClasses.cpp +qt/PlatQt.cpp +qt/qsciabstractapis.cpp +qt/qsciapis.cpp +qt/qscicommand.cpp +qt/qscicommandset.cpp +qt/qscidocument.cpp +qt/qscilexer.cpp +qt/qscilexercpp.cpp +qt/qscimacro.cpp +qt/qsciprinter.cpp +qt/qsciscintilla.cpp +qt/qsciscintillabase.cpp +qt/qscistyle.cpp +qt/qscistyledtext.cpp +qt/SciClasses.cpp +qt/ScintillaQt.cpp + diff --git a/harbour/contrib/hbide/qscintilla/qt/ListBoxQt.cpp b/harbour/contrib/hbide/qscintilla/qt/ListBoxQt.cpp new file mode 100644 index 0000000000..72c83a4567 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/ListBoxQt.cpp @@ -0,0 +1,321 @@ +// This module implements the specialisation of QListBox that handles the +// Scintilla double-click callback. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "ListBoxQt.h" + +#include + +#include "SciClasses.h" +#include "qsciscintilla.h" + + +ListBoxQt::ListBoxQt() + : cb_action(0), cb_data(0), slb(0), visible_rows(5), utf8(false) +{ +} + + +void ListBoxQt::SetFont(Font &font) +{ + QFont *f = reinterpret_cast(font.GetID()); + + if (f) + slb->setFont(*f); +} + + +void ListBoxQt::Create(Window &parent, int, Point, int, bool unicodeMode) +{ + utf8 = unicodeMode; + + // The parent we want is the QsciScintillaBase, not the text area. + id = slb = new SciListBox(reinterpret_cast(parent.GetID())->parentWidget(), this); +} + + +void ListBoxQt::SetAverageCharWidth(int) +{ + // We rely on sizeHint() for the size of the list box rather than make + // calculations based on the average character width and the number of + // visible rows. +} + + +void ListBoxQt::SetVisibleRows(int vrows) +{ + // We only pretend to implement this. + visible_rows = vrows; +} + + +int ListBoxQt::GetVisibleRows() const +{ + return visible_rows; +} + + +PRectangle ListBoxQt::GetDesiredRect() +{ + PRectangle rc(0, 0, 100, 100); + + if (slb) + { + QSize sh = slb->sizeHint(); + + rc.right = sh.width(); + rc.bottom = sh.height(); + } + + return rc; +} + + +int ListBoxQt::CaretFromEdge() +{ + int dist = 0; + + // Find the width of the biggest image. + for (xpmMap::const_iterator it = xset.begin(); it != xset.end(); ++it) + { + int w = it.value().width(); + + if (dist < w) + dist = w; + } + + if (slb) + dist += slb->frameWidth(); + + // Fudge factor - adjust if required. + dist += 3; + + return dist; +} + + +void ListBoxQt::Clear() +{ + Q_ASSERT(slb); + + slb->clear(); +} + + +void ListBoxQt::Append(char *s, int type) +{ + Q_ASSERT(slb); + + QString qs; + + if (utf8) + qs = QString::fromUtf8(s); + else + qs = QString::fromLatin1(s); + + xpmMap::const_iterator it; + + if (type < 0 || (it = xset.find(type)) == xset.end()) + slb->addItem(qs); + else + slb->addItemPixmap(it.value(), qs); +} + + +int ListBoxQt::Length() +{ + Q_ASSERT(slb); + + return slb->count(); +} + + +void ListBoxQt::Select(int n) +{ + Q_ASSERT(slb); + + slb->setCurrentRow(n); +} + + +int ListBoxQt::GetSelection() +{ + Q_ASSERT(slb); + + return slb->currentRow(); +} + + +int ListBoxQt::Find(const char *prefix) +{ + Q_ASSERT(slb); + + return slb->find(prefix); +} + + +void ListBoxQt::GetValue(int n, char *value, int len) +{ + Q_ASSERT(slb); + + QString selection = slb->text(n); + + bool trim_selection = false; + QObject *sci_obj = slb->parent(); + + if (sci_obj->inherits("QsciScintilla")) + { + QsciScintilla *sci = static_cast(sci_obj); + + if (sci->isAutoCompletionList()) + { + // Save the full selection and trim the value we return. + sci->acSelection = selection; + trim_selection = true; + } + } + + if (selection.isEmpty() || len <= 0) + value[0] = '\0'; + else + { + const char *s; + int slen; + + QByteArray bytes; + + if (utf8) + bytes = selection.toUtf8(); + else + bytes = selection.toLatin1(); + + s = bytes.data(); + slen = bytes.length(); + + while (slen-- && len--) + { + if (trim_selection && *s == ' ') + break; + + *value++ = *s++; + } + + *value = '\0'; + } +} + + +void ListBoxQt::Sort() +{ + Q_ASSERT(slb); + + slb->sortItems(); +} + + +void ListBoxQt::RegisterImage(int type,const char *xpm_data) +{ + xset.insert(type, *reinterpret_cast(xpm_data)); +} + + +void ListBoxQt::ClearRegisteredImages() +{ + xset.clear(); +} + + +void ListBoxQt::SetDoubleClickAction(CallBackAction action, void *data) +{ + cb_action = action; + cb_data = data; +} + + +void ListBoxQt::SetList(const char *list, char separator, char typesep) +{ + char *words; + + Clear(); + + if ((words = qstrdup(list)) != NULL) + { + char *startword = words; + char *numword = NULL; + + for (int i = 0; words[i] != '\0'; i++) + { + if (words[i] == separator) + { + words[i] = '\0'; + + if (numword) + *numword = '\0'; + + Append(startword, numword ? atoi(numword + 1) : -1); + + startword = words + i + 1; + numword = NULL; + } + else if (words[i] == typesep) + { + numword = words + i; + } + } + + if (startword) + { + if (numword) + *numword = '\0'; + + Append(startword, numword ? atoi(numword + 1) : -1); + } + + delete[] words; + } +} + + +// The ListBox methods that need to be implemented explicitly. + +ListBox::ListBox() +{ +} + + +ListBox::~ListBox() +{ +} + + +ListBox *ListBox::Allocate() +{ + return new ListBoxQt(); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/ListBoxQt.h b/harbour/contrib/hbide/qscintilla/qt/ListBoxQt.h new file mode 100644 index 0000000000..ce45396712 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/ListBoxQt.h @@ -0,0 +1,77 @@ +// This defines the specialisation of QListBox that handles the Scintilla +// double-click callback. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include +#include +#include + +#include "Platform.h" + + +class SciListBox; + + +class ListBoxQt : public ListBox +{ +public: + ListBoxQt(); + + CallBackAction cb_action; + void *cb_data; + + virtual void SetFont(Font &font); + virtual void Create(Window &parent, int, Point, int, bool unicodeMode); + virtual void SetAverageCharWidth(int); + virtual void SetVisibleRows(int); + virtual int GetVisibleRows() const; + virtual PRectangle GetDesiredRect(); + virtual int CaretFromEdge(); + virtual void Clear(); + virtual void Append(char *s, int type = -1); + virtual int Length(); + virtual void Select(int n); + virtual int GetSelection(); + virtual int Find(const char *prefix); + virtual void GetValue(int n, char *value, int len); + virtual void Sort(); + virtual void RegisterImage(int type, const char *xpm_data); + virtual void ClearRegisteredImages(); + virtual void SetDoubleClickAction(CallBackAction action, void *data); + virtual void SetList(const char *list, char separator, char typesep); + +private: + SciListBox *slb; + int visible_rows; + bool utf8; + + typedef QMap xpmMap; + xpmMap xset; +}; diff --git a/harbour/contrib/hbide/qscintilla/qt/PlatQt.cpp b/harbour/contrib/hbide/qscintilla/qt/PlatQt.cpp new file mode 100644 index 0000000000..46e8aaa877 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/PlatQt.cpp @@ -0,0 +1,993 @@ +// This module implements the portability layer for the Qt port of Scintilla. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "Platform.h" +#include "XPM.h" + +#include "qsciscintillabase.h" +#include "SciClasses.h" + + +// Type convertors. +static QFont *PFont(FontID id) +{ + return reinterpret_cast(id); +} + +static QWidget *PWindow(WindowID id) +{ + return reinterpret_cast(id); +} + +static SciPopup *PMenu(MenuID id) +{ + return reinterpret_cast(id); +} + + +// Create a Point instance from a long value. +Point Point::FromLong(long lpoint) +{ + return Point(Platform::LowShortFromLong(lpoint), + Platform::HighShortFromLong(lpoint)); +} + + +// Colour palette management. The Qt interface to colours means this class +// doesn't have to do anything. +Palette::Palette() +{ + used = 0; + allowRealization = false; +} + +Palette::~Palette() +{ + Release(); +} + +void Palette::Release() +{ + used = 0; +} + +void Palette::WantFind(ColourPair &cp, bool want) +{ + if (!want) + cp.allocated.Set(cp.desired.AsLong()); +} + +void Palette::Allocate(Window &) +{ +} + + +// Font management. +Font::Font() : id(0) +{ +} + +Font::~Font() +{ +} + +void Font::Create(const char *faceName, int, int size, bool bold, bool italic, + bool) +{ + Release(); + + QFont *f = new QFont(); + + // If name of the font begins with a '-', assume, that it is an XLFD. + if (faceName[0] == '-') + f->setRawName(faceName); + else + { + f->setFamily(faceName); + f->setPointSize(size); + f->setBold(bold); + f->setItalic(italic); + } + + id = f; +} + +void Font::Release() +{ + if (id) + { + delete PFont(id); + id = 0; + } +} + + +// A surface abstracts a place to draw. +class SurfaceImpl : public Surface +{ +public: + SurfaceImpl(); + virtual ~SurfaceImpl(); + + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID); + void Init(QPainter *p); + void InitPixMap(int width, int height, Surface *, WindowID); + + void Release(); + bool Initialised() {return painter;} + void PenColour(ColourAllocated fore); + int LogPixelsY() {return 72;} + int DeviceHeightFont(int points) {return points;} + void MoveTo(int x_,int y_); + void LineTo(int x_,int y_); + void Polygon(Point *pts, int npts, ColourAllocated fore, + ColourAllocated back); + void RectangleDraw(PRectangle rc, ColourAllocated fore, + ColourAllocated back); + void FillRectangle(PRectangle rc, ColourAllocated back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, ColourAllocated fore, + ColourAllocated back); + void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, + int alphaFill, ColourAllocated outline, int alphaOutline, + int flags); + void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void Copy(PRectangle rc, Point from, Surface &surfaceSource); + + void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, + int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, + int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, + const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, int *positions); + int WidthText(Font &font_, const char *s, int len); + int WidthChar(Font &font_, char ch); + int Ascent(Font &font_); + int Descent(Font &font_); + int InternalLeading(Font &font_) { Q_UNUSED( font_ ); return 0;} + int ExternalLeading(Font &font_); + int Height(Font &font_); + int AverageCharWidth(Font &font_) {return WidthChar(font_, 'n');} + + int SetPalette(Palette *, bool) {return 0;} + void SetClip(PRectangle rc); + void FlushCachedState(); + + void SetUnicodeMode(bool unicodeMode_) {unicodeMode = unicodeMode_;} + void SetDBCSMode(int codePage) { Q_UNUSED( codePage ); } + + void DrawXPM(PRectangle rc, const XPM *xpm); + +private: + void drawText(PRectangle rc, Font &font_, int ybase, const char *s, + int len, ColourAllocated fore); + QFontMetrics metrics(Font &font_); + QString convertText(const char *s, int len); + static QColor convertQColor(const ColourAllocated &col, + unsigned alpha = 255); + + bool unicodeMode; + QPaintDevice *pd; + QPainter *painter; + bool my_resources; + int pen_x, pen_y; +}; + +Surface *Surface::Allocate() +{ + return new SurfaceImpl; +} + +SurfaceImpl::SurfaceImpl() + : unicodeMode(false), pd(0), painter(0), my_resources(false), pen_x(0), + pen_y(0) +{ +} + +SurfaceImpl::~SurfaceImpl() +{ + Release(); +} + +void SurfaceImpl::Init(WindowID wid) +{ + Release(); + + pd = reinterpret_cast(wid); +} + +void SurfaceImpl::Init(SurfaceID sid, WindowID) +{ + Release(); + + // This method, and the SurfaceID type, is only used when printing. As it + // is actually a void * we pass (when using SCI_FORMATRANGE) a pointer to a + // QPainter rather than a pointer to a SurfaceImpl as might be expected. + QPainter *p = reinterpret_cast(sid); + + pd = p->device(); + painter = p; +} + +void SurfaceImpl::Init(QPainter *p) +{ + Release(); + + pd = p->device(); + painter = p; +} + +void SurfaceImpl::InitPixMap(int width, int height, Surface *, WindowID) +{ + Release(); + + pd = new QPixmap(width, height); + painter = new QPainter(pd); + my_resources = true; +} + +void SurfaceImpl::Release() +{ + if (my_resources) + { + if (painter) + delete painter; + + if (pd) + delete pd; + + my_resources = false; + } + + painter = 0; + pd = 0; +} + +void SurfaceImpl::MoveTo(int x_, int y_) +{ + Q_ASSERT(painter); + + pen_x = x_; + pen_y = y_; +} + +void SurfaceImpl::LineTo(int x_, int y_) +{ + Q_ASSERT(painter); + + painter->drawLine(pen_x, pen_y, x_, y_); + + pen_x = x_; + pen_y = y_; +} + +void SurfaceImpl::PenColour(ColourAllocated fore) +{ + Q_ASSERT(painter); + + painter->setPen(convertQColor(fore)); +} + +void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, + ColourAllocated back) +{ + Q_ASSERT(painter); + + QPolygon qpts(npts); + + for (int i = 0; i < npts; ++i) + qpts.setPoint(i, pts[i].x, pts[i].y); + + painter->setPen(convertQColor(fore)); + painter->setBrush(convertQColor(back)); + painter->drawPolygon(qpts); +} + +void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, + ColourAllocated back) +{ + Q_ASSERT(painter); + + painter->setPen(convertQColor(fore)); + painter->setBrush(convertQColor(back)); + painter->drawRect(rc.left, rc.top, rc.right - rc.left - 1, + rc.bottom - rc.top - 1); +} + +void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) +{ + Q_ASSERT(painter); + + painter->setPen(Qt::NoPen); + painter->setBrush(convertQColor(back)); + painter->drawRect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); +} + +void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) +{ + Q_ASSERT(painter); + + SurfaceImpl &si = static_cast(surfacePattern); + QPixmap *pm = static_cast(si.pd); + + if (pm) + { + QBrush brsh(Qt::black, *pm); + + painter->setPen(Qt::NoPen); + painter->setBrush(brsh); + painter->drawRect(rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top); + } + else + FillRectangle(rc, ColourAllocated(0)); +} + +void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, + ColourAllocated back) +{ + Q_ASSERT(painter); + + painter->setPen(convertQColor(fore)); + painter->setBrush(convertQColor(back)); + painter->drawRoundRect(rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top); +} + +void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, + ColourAllocated fill, int alphaFill, ColourAllocated outline, + int alphaOutline, int) +{ + Q_ASSERT(painter); + + int w = rc.right - rc.left; + int h = rc.bottom - rc.top; + + // Assume that "cornerSize" means outline width. + if (cornerSize > 0) + painter->setPen(QPen(convertQColor(outline, alphaOutline), cornerSize)); + else + painter->setPen(Qt::NoPen); + + painter->setBrush(convertQColor(fill, alphaFill)); + painter->drawRect(rc.left, rc.top, w, h); +} + +void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, + ColourAllocated back) +{ + Q_ASSERT(painter); + + painter->setPen(convertQColor(fore)); + painter->setBrush(convertQColor(back)); + painter->drawEllipse(rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top); +} + +void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) +{ + Q_ASSERT(painter); + + SurfaceImpl &si = static_cast(surfaceSource); + + if (si.pd) + { + QPixmap *pm = static_cast(si.pd); + + painter->drawPixmap(rc.left, rc.top, *pm, from.x, from.y, + rc.right - rc.left, rc.bottom - rc.top); + } +} + +void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, + const char *s, int len,ColourAllocated fore, ColourAllocated back) +{ + Q_ASSERT(painter); + + FillRectangle(rc, back); + drawText(rc, font_, ybase, s, len, fore); +} + +void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, + const char *s, int len, ColourAllocated fore, ColourAllocated back) +{ + Q_ASSERT(painter); + + SetClip(rc); + DrawTextNoClip(rc, font_, ybase, s, len, fore, back); + painter->setClipping(false); +} + +void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, + const char *s, int len, ColourAllocated fore) +{ + // Only draw if there is a non-space. + for (int i = 0; i < len; ++i) + if (s[i] != ' ') + { + drawText(rc, font_, ybase, s, len, fore); + return; + } +} + +void SurfaceImpl::drawText(PRectangle rc, Font &font_, int ybase, + const char *s, int len, ColourAllocated fore) +{ + QString qs = convertText(s, len); + + QFont *f = PFont(font_.GetID()); + + if (f) + painter->setFont(*f); + + painter->setPen(convertQColor(fore)); + painter->drawText(rc.left, ybase, qs); +} + +void SurfaceImpl::DrawXPM(PRectangle rc, const XPM *xpm) +{ + Q_ASSERT(painter); + + int x, y; + const QPixmap &qpm = xpm->Pixmap(); + + x = rc.left + (rc.Width() - qpm.width()) / 2; + y = rc.top + (rc.Height() - qpm.height()) / 2; + + painter->drawPixmap(x, y, qpm); +} + +void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, + int *positions) +{ + QFontMetrics fm = metrics(font_); + QString qs = convertText(s, len); + + // The position for each byte of a character is the offset from the start + // where the following character should be drawn. + int i_byte = 0, width = 0; + + for (int i_char = 0; i_char < qs.length(); ++i_char) + { + width += fm.width(qs.at(i_char)); + + if (unicodeMode) + { + // Set the same position for each byte of the character. + int nbytes = qs.mid(i_char, 1).toUtf8().length(); + + while (nbytes--) + positions[i_byte++] = width; + } + else + positions[i_byte++] = width; + } +} + +int SurfaceImpl::WidthText(Font &font_, const char *s, int len) +{ + return metrics(font_).width(convertText(s, len)); + +} + +int SurfaceImpl::WidthChar(Font &font_, char ch) +{ + return metrics(font_).width(ch); +} + +int SurfaceImpl::Ascent(Font &font_) +{ + return metrics(font_).ascent(); +} + +int SurfaceImpl::Descent(Font &font_) +{ + // Qt doesn't include the baseline in the descent, so add it. Note that + // a descent from Qt4 always seems to be 2 pixels larger (irrespective of + // font or size) than the same descent from Qt3. This means that text is a + // little more spaced out with Qt4 - and will be more noticeable with + // smaller fonts. + return metrics(font_).descent() + 1; +} + +int SurfaceImpl::ExternalLeading(Font &font_) +{ + // Scintilla doesn't use this at the moment, which is good because Qt4 can + // return a negative value. + return metrics(font_).leading(); +} + +int SurfaceImpl::Height(Font &font_) +{ + return metrics(font_).height(); +} + +void SurfaceImpl::SetClip(PRectangle rc) +{ + Q_ASSERT(painter); + + painter->setClipRect(rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top); +} + +void SurfaceImpl::FlushCachedState() +{ +} + +// Get the metrics for a font. +QFontMetrics SurfaceImpl::metrics(Font &font_) +{ + QFont *f = PFont(font_.GetID()), fnt; + + if (f) + fnt = *f; + else + fnt = QApplication::font(); + + return QFontMetrics(fnt, pd); +} + +// Convert a Scintilla string to a Qt Unicode string. +QString SurfaceImpl::convertText(const char *s, int len) +{ + if (unicodeMode) + return QString::fromUtf8(s, len); + + return QString::fromLatin1(s, len); +} + + +// Convert a Scintilla colour, and alpha component, to a Qt QColor. +QColor SurfaceImpl::convertQColor(const ColourAllocated &col, unsigned alpha) +{ + long c = col.AsLong(); + + unsigned r = c & 0xff; + unsigned g = (c >> 8) & 0xff; + unsigned b = (c >> 16) & 0xff; + + return QColor(r, g, b, alpha); +} + + +// Window (widget) management. +Window::~Window() +{ +} + +void Window::Destroy() +{ + QWidget *w = PWindow(id); + + if (w) + { + // Delete the widget next time round the event loop rather than + // straight away. This gets round a problem when auto-completion lists + // are cancelled after an entry has been double-clicked, ie. the list's + // dtor is called from one of the list's slots. There are other ways + // around the problem but this is the simplest and doesn't seem to + // cause problems of its own. + w->deleteLater(); + id = 0; + } +} + +bool Window::HasFocus() +{ + return PWindow(id)->hasFocus(); +} + +PRectangle Window::GetPosition() +{ + QWidget *w = PWindow(id); + + // Before any size allocated pretend its big enough not to be scrolled. + PRectangle rc(0,0,5000,5000); + + if (w) + { + const QRect &r = w->geometry(); + + rc.right = r.right() - r.left() + 1; + rc.bottom = r.bottom() - r.top() + 1; + } + + return rc; +} + +void Window::SetPosition(PRectangle rc) +{ + PWindow(id)->setGeometry(rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top); +} + +void Window::SetPositionRelative(PRectangle rc, Window relativeTo) +{ + QWidget *rel = PWindow(relativeTo.id); + QPoint pos = rel->mapToGlobal(rel->pos()); + + int x = pos.x() + rc.left; + int y = pos.y() + rc.top; + + PWindow(id)->setGeometry(x, y, rc.right - rc.left, rc.bottom - rc.top); +} + +PRectangle Window::GetClientPosition() +{ + return GetPosition(); +} + +void Window::Show(bool show) +{ + QWidget *w = PWindow(id); + + if (show) + w->show(); + else + w->hide(); +} + +void Window::InvalidateAll() +{ + QWidget *w = PWindow(id); + + if (w) + w->update(); +} + +void Window::InvalidateRectangle(PRectangle rc) +{ + QWidget *w = PWindow(id); + + if (w) + w->update(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); +} + +void Window::SetFont(Font &font) +{ + PWindow(id)->setFont(*PFont(font.GetID())); +} + +void Window::SetCursor(Cursor curs) +{ + Qt::CursorShape qc; + + switch (curs) + { + case cursorText: + qc = Qt::IBeamCursor; + break; + + case cursorUp: + qc = Qt::UpArrowCursor; + break; + + case cursorWait: + qc = Qt::WaitCursor; + break; + + case cursorHoriz: + qc = Qt::SizeHorCursor; + break; + + case cursorVert: + qc = Qt::SizeVerCursor; + break; + + case cursorHand: + qc = Qt::PointingHandCursor; + break; + + default: + qc = Qt::ArrowCursor; + } + + PWindow(id)->setCursor(qc); +} + +void Window::SetTitle(const char *s) +{ + PWindow(id)->setWindowTitle(s); +} + + +PRectangle Window::GetMonitorRect(Point pt) +{ + QPoint qpt = PWindow(id)->mapToGlobal(QPoint(pt.x, pt.y)); + QRect qr = QApplication::desktop()->availableGeometry(qpt); + qpt = PWindow(id)->mapFromGlobal(qr.topLeft()); + + return PRectangle(qpt.x(), qpt.y(), qpt.x() + qr.width(), qpt.y() + qr.height()); +} + + +// Menu management. +Menu::Menu() : id(0) +{ +} + +void Menu::CreatePopUp() +{ + Destroy(); + id = new SciPopup(); +} + +void Menu::Destroy() +{ + SciPopup *m = PMenu(id); + + if (m) + { + delete m; + id = 0; + } +} + +void Menu::Show(Point pt, Window &) +{ + PMenu(id)->popup(QPoint(pt.x, pt.y)); +} + + +class DynamicLibraryImpl : public DynamicLibrary +{ +public: + DynamicLibraryImpl(const char *modulePath) + { + m = new QLibrary(modulePath); + m->load(); + } + + virtual ~DynamicLibraryImpl() + { + if (m) + delete m; + } + + virtual Function FindFunction(const char *name) + { + if (m) + return m->resolve(name); + + return 0; + } + + virtual bool IsValid() + { + return m && m->isLoaded(); + } + +private: + QLibrary* m; +}; + +DynamicLibrary *DynamicLibrary::Load(const char *modulePath) +{ + return new DynamicLibraryImpl(modulePath); +} + + +// Elapsed time. This implementation assumes that the maximum elapsed time is +// less than 48 hours. +ElapsedTime::ElapsedTime() +{ + QTime now = QTime::currentTime(); + + bigBit = now.hour() * 60 * 60 + now.minute() * 60 + now.second(); + littleBit = now.msec(); +} + +double ElapsedTime::Duration(bool reset) +{ + long endBigBit, endLittleBit; + QTime now = QTime::currentTime(); + + endBigBit = now.hour() * 60 * 60 + now.minute() * 60 + now.second(); + endLittleBit = now.msec(); + + double duration = endBigBit - bigBit; + + if (duration < 0 || (duration == 0 && endLittleBit < littleBit)) + duration += 24 * 60 * 60; + + duration += (endLittleBit - littleBit) / 1000.0; + + if (reset) + { + bigBit = endBigBit; + littleBit = endLittleBit; + } + + return duration; +} + + +// Manage system wide parameters. +ColourDesired Platform::Chrome() +{ + return ColourDesired(0xe0,0xe0,0xe0); +} + +ColourDesired Platform::ChromeHighlight() +{ + return ColourDesired(0xff,0xff,0xff); +} + +const char *Platform::DefaultFont() +{ + static QByteArray def_font; + + def_font = QApplication::font().family().toAscii(); + + return def_font.constData(); +} + +int Platform::DefaultFontSize() +{ + return QApplication::font().pointSize(); +} + +unsigned int Platform::DoubleClickTime() +{ + return QApplication::doubleClickInterval(); +} + +bool Platform::MouseButtonBounce() +{ + return true; +} + +void Platform::DebugDisplay(const char *s) +{ + qDebug("%s", s); +} + +bool Platform::IsKeyDown(int) +{ + return false; +} + +long Platform::SendScintilla(WindowID w, unsigned int msg, + unsigned long wParam, long lParam) +{ + Q_UNUSED( w ); + Q_UNUSED( msg ); + Q_UNUSED( wParam ); + Q_UNUSED( lParam ); + // This is never called. + return 0; +} + +long Platform::SendScintillaPointer(WindowID w, unsigned int msg, + unsigned long wParam, void *lParam) +{ + Q_UNUSED( w ); + Q_UNUSED( msg ); + Q_UNUSED( wParam ); + Q_UNUSED( lParam ); + // This is never called. + return 0; +} + +bool Platform::IsDBCSLeadByte(int, char) +{ + // We don't support DBCS. + return false; +} + +int Platform::DBCSCharLength(int, const char *) +{ + // We don't support DBCS. + return 1; +} + +int Platform::DBCSCharMaxLength() +{ + // We don't support DBCS. + return 2; +} + +int Platform::Minimum(int a, int b) +{ + return (a < b) ? a : b; +} + +int Platform::Maximum(int a, int b) +{ + return (a > b) ? a : b; +} + +int Platform::Clamp(int val, int minVal, int maxVal) +{ + if (val > maxVal) + val = maxVal; + + if (val < minVal) + val = minVal; + + return val; +} + + +//#define TRACE + +#ifdef TRACE +void Platform::DebugPrintf(const char *format, ...) +{ + char buffer[2000]; + va_list pArguments; + + va_start(pArguments, format); + vsprintf(buffer, format, pArguments); + va_end(pArguments); + + DebugDisplay(buffer); +} +#else +void Platform::DebugPrintf(const char *, ...) +{ +} +#endif + +static bool assertionPopUps = true; + +bool Platform::ShowAssertionPopUps(bool assertionPopUps_) +{ + bool ret = assertionPopUps; + + assertionPopUps = assertionPopUps_; + + return ret; +} + +void Platform::Assert(const char *c, const char *file, int line) +{ + qFatal("Assertion [%s] failed at %s %d\n", c, file, line); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/SciClasses.cpp b/harbour/contrib/hbide/qscintilla/qt/SciClasses.cpp new file mode 100644 index 0000000000..d1ba5cacef --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/SciClasses.cpp @@ -0,0 +1,210 @@ +// The implementation of various Qt version independent classes used by the +// rest of the port. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "SciClasses.h" + +#include +#include +#include + +#include "ScintillaQt.h" +#include "ListBoxQt.h" + + +// Create a call tip. +SciCallTip::SciCallTip(QWidget *parent, ScintillaQt *sci_) + : QWidget(parent, Qt::WindowFlags(Qt::Popup|Qt::FramelessWindowHint|Qt::WA_StaticContents)), + sci(sci_) +{ + // Ensure that the main window keeps the focus (and the caret flashing) + // when this is displayed. + setFocusProxy(parent); +} + + +// Destroy a call tip. +SciCallTip::~SciCallTip() +{ + // Ensure that the main window doesn't receive a focus out event when + // this is destroyed. + setFocusProxy(0); +} + + +// Paint a call tip. +void SciCallTip::paintEvent(QPaintEvent *) +{ + Surface *surfaceWindow = Surface::Allocate(); + + if (!surfaceWindow) + return; + + QPainter p(this); + + surfaceWindow->Init(&p); + sci->ct.PaintCT(surfaceWindow); + + delete surfaceWindow; +} + + +// Handle a mouse press in a call tip. +void SciCallTip::mousePressEvent(QMouseEvent *e) +{ + Point pt; + + pt.x = e->x(); + pt.y = e->y(); + + sci->ct.MouseClick(pt); + sci->CallTipClick(); +} + + + +// Create the popup instance. +SciPopup::SciPopup() +{ + // Set up the mapper. + connect(&mapper, SIGNAL(mapped(int)), this, SLOT(on_triggered(int))); +} + + +// Add an item and associated command to the popup and enable it if required. +void SciPopup::addItem(const QString &label, int cmd, bool enabled, + ScintillaQt *sci_) +{ + QAction *act = addAction(label, &mapper, SLOT(map())); + mapper.setMapping(act, cmd); + act->setEnabled(enabled); + sci = sci_; +} + + +// A slot to handle a menu action being triggered. +void SciPopup::on_triggered(int cmd) +{ + sci->Command(cmd); +} + + + +#include + + +SciListBox::SciListBox(QWidget *parent, ListBoxQt *lbx_) + : QListWidget(parent), lbx(lbx_) +{ + // This is the root of the focus problems under Gnome's window manager. We + // have tried many flag combinations in the past. The consensus now seems + // to be that the following works. However it might now work because of a + // change in Qt so we only enable it for recent versions in order to + // reduce the risk of breaking something that works with earlier versions. +#if QT_VERSION >= 0x040500 + setWindowFlags(Qt::ToolTip|Qt::WindowStaysOnTopHint); +#else + setWindowFlags(Qt::Tool|Qt::FramelessWindowHint); +#endif + setAttribute(Qt::WA_StaticContents); + + setFocusProxy(parent); + + setFrameShape(StyledPanel); + setFrameShadow(Plain); + + connect(this, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + SLOT(handleSelection())); + connect(this, SIGNAL(itemActivated(QListWidgetItem *)), + SLOT(handleSelection())); +} + + +void SciListBox::addItemPixmap(const QPixmap &pm, const QString &txt) +{ + new QListWidgetItem(pm, txt, this); +} + + +int SciListBox::find(const QString &prefix) +{ + QList itms = findItems(prefix, + Qt::MatchStartsWith|Qt::MatchCaseSensitive); + + if (itms.size() == 0) + return -1; + + return row(itms[0]); +} + + +QString SciListBox::text(int n) +{ + QListWidgetItem *itm = item(n); + + if (!itm) + return QString(); + + return itm->text(); +} + + +// Reimplemented to close the list when the user presses Escape. +void SciListBox::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Escape) + { + e->accept(); + close(); + } + else + { + QListWidget::keyPressEvent(e); + + if (!e->isAccepted()) + QCoreApplication::sendEvent(parent(), e); + } +} + + + +SciListBox::~SciListBox() +{ + // Ensure that the main widget doesn't get a focus out event when this is + // destroyed. + setFocusProxy(0); +} + + +void SciListBox::handleSelection() +{ + if (lbx && lbx->cb_action) + lbx->cb_action(lbx->cb_data); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/SciClasses.h b/harbour/contrib/hbide/qscintilla/qt/SciClasses.h new file mode 100644 index 0000000000..7b8eae4729 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/SciClasses.h @@ -0,0 +1,119 @@ +// The definition of various Qt version independent classes used by the rest of +// the port. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef _SCICLASSES_H +#define _SCICLASSES_H + +#include +#include + + +class QMouseEvent; +class QPaintEvent; +class ScintillaQt; + + +// A simple QWidget sub-class to implement a call tip. +class SciCallTip : public QWidget +{ + Q_OBJECT + +public: + SciCallTip(QWidget *parent, ScintillaQt *sci_); + ~SciCallTip(); + +protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + +private: + ScintillaQt *sci; +}; + + +// A popup menu where options correspond to a numeric command. + +#include +#include + +class SciPopup : public QMenu +{ + Q_OBJECT + +public: + SciPopup(); + + void addItem(const QString &label, int cmd, bool enabled, + ScintillaQt *sci_); + +private slots: + void on_triggered(int cmd); + +private: + ScintillaQt *sci; + QSignalMapper mapper; +}; + + + +// This sub-class of QListBox is needed to provide slots from which we can call +// ListBox's double-click callback. (And you thought this was a C++ program.) + +class ListBoxQt; + + +#include + +class SciListBox : public QListWidget +{ + Q_OBJECT + +public: + SciListBox(QWidget *parent, ListBoxQt *lbx_); + virtual ~SciListBox(); + + void addItemPixmap(const QPixmap &pm, const QString &txt); + + int find(const QString &prefix); + QString text(int n); + +protected: + void keyPressEvent(QKeyEvent *e); + +private slots: + void handleSelection(); + +private: + ListBoxQt *lbx; +}; + + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/ScintillaQt.cpp b/harbour/contrib/hbide/qscintilla/qt/ScintillaQt.cpp new file mode 100644 index 0000000000..6312063891 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/ScintillaQt.cpp @@ -0,0 +1,582 @@ +// The implementation of the Qt specific subclass of ScintillaBase. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "qsciscintillabase.h" +#include "ScintillaQt.h" +#include "SciClasses.h" + + +// We want to use the Scintilla notification names as Qt signal names. +#undef SCEN_CHANGE +#undef SCN_AUTOCCANCELLED +#undef SCN_AUTOCCHARDELETED +#undef SCN_AUTOCSELECTION +#undef SCN_CALLTIPCLICK +#undef SCN_CHARADDED +#undef SCN_DOUBLECLICK +#undef SCN_DWELLEND +#undef SCN_DWELLSTART +#undef SCN_HOTSPOTCLICK +#undef SCN_HOTSPOTDOUBLECLICK +#undef SCN_INDICATORCLICK +#undef SCN_INDICATORRELEASE +#undef SCN_MACRORECORD +#undef SCN_MARGINCLICK +#undef SCN_MODIFIED +#undef SCN_MODIFYATTEMPTRO +#undef SCN_NEEDSHOWN +#undef SCN_PAINTED +#undef SCN_SAVEPOINTLEFT +#undef SCN_SAVEPOINTREACHED +#undef SCN_STYLENEEDED +#undef SCN_UPDATEUI +#undef SCN_USERLISTSELECTION +#undef SCN_ZOOM + +enum +{ + SCEN_CHANGE = 768, + SCN_AUTOCCANCELLED = 2025, + SCN_AUTOCCHARDELETED = 2026, + SCN_AUTOCSELECTION = 2022, + SCN_CALLTIPCLICK = 2021, + SCN_CHARADDED = 2001, + SCN_DOUBLECLICK = 2006, + SCN_DWELLEND = 2017, + SCN_DWELLSTART = 2016, + SCN_HOTSPOTCLICK = 2019, + SCN_HOTSPOTDOUBLECLICK = 2020, + SCN_INDICATORCLICK = 2023, + SCN_INDICATORRELEASE = 2024, + SCN_MACRORECORD = 2009, + SCN_MARGINCLICK = 2010, + SCN_MODIFIED = 2008, + SCN_MODIFYATTEMPTRO = 2004, + SCN_NEEDSHOWN = 2011, + SCN_PAINTED = 2013, + SCN_SAVEPOINTLEFT = 2003, + SCN_SAVEPOINTREACHED = 2002, + SCN_STYLENEEDED = 2000, + SCN_UPDATEUI = 2007, + SCN_USERLISTSELECTION = 2014, + SCN_ZOOM = 2018 +}; + + +// The ctor. +ScintillaQt::ScintillaQt(QsciScintillaBase *qsb_) + : capturedMouse(false), qsb(qsb_) +{ + wMain = qsb->viewport(); + + // We aren't a QObject so we use the API class to do QObject related things + // for us. + qsb->connect(&qtimer, SIGNAL(timeout()), SLOT(handleTimer())); + + Initialise(); +} + + +// The dtor. +ScintillaQt::~ScintillaQt() +{ + Finalise(); +} + + +// Initialise the instance. +void ScintillaQt::Initialise() +{ + SetTicking(true); +} + + +// Tidy up the instance. +void ScintillaQt::Finalise() +{ + SetTicking(false); + ScintillaBase::Finalise(); +} + + +// Start a drag. +void ScintillaQt::StartDrag() +{ + inDragDrop = ddDragging; + + QDrag *qdrag = new QDrag(qsb); + qdrag->setMimeData(qsb->toMimeData(textRange(&drag))); + +# if QT_VERSION >= 0x040300 + // The default action is to copy so that the cursor is correct when over + // another widget or application (when we have no control over it). We + // make sure it is correct over ourself in the event handlers. + Qt::DropAction action = qdrag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction); +# else + Qt::DropAction action = qdrag->start(Qt::MoveAction); +# endif + + // Remove the dragged text if it was a move to another widget or + // application. + if (action == Qt::MoveAction && qdrag->target() != qsb->viewport()) + ClearSelection(); + + SetDragPosition(-1); + inDragDrop = ddNone; +} + + +// Re-implement to trap certain messages. +sptr_t ScintillaQt::WndProc(unsigned int iMessage, uptr_t wParam, + sptr_t lParam) +{ + switch (iMessage) + { + case SCI_GETDIRECTFUNCTION: + return reinterpret_cast(DirectFunction); + + case SCI_GETDIRECTPOINTER: + return reinterpret_cast(this); + } + + return ScintillaBase::WndProc(iMessage, wParam, lParam); +} + + +// Windows nonsense. +sptr_t ScintillaQt::DefWndProc(unsigned int, uptr_t, sptr_t) +{ + return 0; +} + + +// Manage the timer. +void ScintillaQt::SetTicking(bool on) +{ + if (timer.ticking != on) + { + timer.ticking = on; + + if (timer.ticking) + qtimer.start(timer.tickSize); + else + qtimer.stop(); + } + + timer.ticksToWait = caret.period; +} + + +// Grab or release the mouse (and keyboard). +void ScintillaQt::SetMouseCapture(bool on) +{ + if (mouseDownCaptures) + if (on) + qsb->viewport()->grabMouse(); + else + qsb->viewport()->releaseMouse(); + + capturedMouse = on; +} + + +// Return true if the mouse/keyboard are currently grabbed. +bool ScintillaQt::HaveMouseCapture() +{ + return capturedMouse; +} + + +// Set the position of the vertical scrollbar. +void ScintillaQt::SetVerticalScrollPos() +{ + qsb->verticalScrollBar()->setValue(topLine); +} + + +// Set the position of the horizontal scrollbar. +void ScintillaQt::SetHorizontalScrollPos() +{ + qsb->horizontalScrollBar()->setValue(xOffset); +} + + +// Set the extent of the vertical and horizontal scrollbars and return true if +// the view needs re-drawing. +bool ScintillaQt::ModifyScrollBars(int nMax,int nPage) +{ + qsb->verticalScrollBar()->setMinimum(0); + qsb->horizontalScrollBar()->setMinimum(0); + + qsb->verticalScrollBar()->setMaximum(nMax - nPage + 1); + qsb->horizontalScrollBar()->setMaximum(scrollWidth); + + qsb->verticalScrollBar()->setSingleStep(1); + + qsb->verticalScrollBar()->setPageStep(nPage); + qsb->horizontalScrollBar()->setPageStep(scrollWidth / 10); + + return true; +} + + +// Called after SCI_SETWRAPMODE and SCI_SETHSCROLLBAR. +void ScintillaQt::ReconfigureScrollBars() +{ + // Hide or show the scrollbars if needed. + bool hsb = (horizontalScrollBarVisible && wrapState == eWrapNone); + + qsb->setHorizontalScrollBarPolicy(hsb ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); + qsb->setVerticalScrollBarPolicy(verticalScrollBarVisible ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); +} + + +// Notify interested parties of any change in the document. +void ScintillaQt::NotifyChange() +{ + emit qsb->SCEN_CHANGE(); +} + + +// Notify interested parties of various events. This is the main mapping +// between Scintilla notifications and Qt signals. +void ScintillaQt::NotifyParent(SCNotification scn) +{ + switch (scn.nmhdr.code) + { + case SCN_CALLTIPCLICK: + emit qsb->SCN_CALLTIPCLICK(scn.position); + break; + + case SCN_AUTOCCANCELLED: + emit qsb->SCN_AUTOCCANCELLED(); + break; + + case SCN_AUTOCCHARDELETED: + emit qsb->SCN_AUTOCCHARDELETED(); + break; + + case SCN_AUTOCSELECTION: + emit qsb->SCN_AUTOCSELECTION(scn.text, scn.lParam); + break; + + case SCN_CHARADDED: + emit qsb->SCN_CHARADDED(scn.ch); + break; + + case SCN_DOUBLECLICK: + emit qsb->SCN_DOUBLECLICK(scn.position, scn.line, scn.modifiers); + break; + + case SCN_DWELLEND: + emit qsb->SCN_DWELLEND(scn.position, scn.x, scn.y); + break; + + case SCN_DWELLSTART: + emit qsb->SCN_DWELLSTART(scn.position, scn.x, scn.y); + break; + + case SCN_HOTSPOTCLICK: + emit qsb->SCN_HOTSPOTCLICK(scn.position, scn.modifiers); + break; + + case SCN_HOTSPOTDOUBLECLICK: + emit qsb->SCN_HOTSPOTDOUBLECLICK(scn.position, scn.modifiers); + break; + + case SCN_INDICATORCLICK: + emit qsb->SCN_INDICATORCLICK(scn.position, scn.modifiers); + break; + + case SCN_INDICATORRELEASE: + emit qsb->SCN_INDICATORRELEASE(scn.position, scn.modifiers); + break; + + case SCN_MACRORECORD: + emit qsb->SCN_MACRORECORD(scn.message, scn.wParam, + reinterpret_cast(scn.lParam)); + break; + + case SCN_MARGINCLICK: + emit qsb->SCN_MARGINCLICK(scn.position, scn.modifiers, scn.margin); + break; + + case SCN_MODIFIED: + emit qsb->SCN_MODIFIED(scn.position, scn.modificationType, scn.text, + scn.length, scn.linesAdded, scn.line, scn.foldLevelNow, + scn.foldLevelPrev, scn.token, scn.annotationLinesAdded); + break; + + case SCN_MODIFYATTEMPTRO: + emit qsb->SCN_MODIFYATTEMPTRO(); + break; + + case SCN_NEEDSHOWN: + emit qsb->SCN_NEEDSHOWN(scn.position, scn.length); + break; + + case SCN_PAINTED: + emit qsb->SCN_PAINTED(); + break; + + case SCN_SAVEPOINTLEFT: + emit qsb->SCN_SAVEPOINTLEFT(); + break; + + case SCN_SAVEPOINTREACHED: + emit qsb->SCN_SAVEPOINTREACHED(); + break; + + case SCN_STYLENEEDED: + emit qsb->SCN_STYLENEEDED(scn.position); + break; + + case SCN_UPDATEUI: + emit qsb->SCN_UPDATEUI(); + break; + + case SCN_USERLISTSELECTION: + emit qsb->SCN_USERLISTSELECTION(scn.text, scn.wParam); + break; + + case SCN_ZOOM: + emit qsb->SCN_ZOOM(); + break; + + default: + qWarning("Unknown notification: %u", scn.nmhdr.code); + } +} + + +// Convert a text range to a QString. +QString ScintillaQt::textRange(const SelectionText *text) +{ + if (!text->s) + return QString(); + + if (IsUnicodeMode()) + return QString::fromUtf8(text->s); + + return QString::fromLatin1(text->s); +} + + +// Copy the selected text to the clipboard. +void ScintillaQt::CopyToClipboard(const SelectionText &selectedText) +{ + QApplication::clipboard()->setMimeData( + qsb->toMimeData(textRange(&selectedText))); +} + + +// Implement copy. +void ScintillaQt::Copy() +{ + if (currentPos != anchor) + { + SelectionText text; + + CopySelectionRange(&text); + CopyToClipboard(text); + } +} + + +// Implement pasting text. +void ScintillaQt::Paste() +{ + pasteFromClipboard(QClipboard::Clipboard); +} + + +// Paste text from either the clipboard or selection. +void ScintillaQt::pasteFromClipboard(QClipboard::Mode mode) +{ + const QMimeData *source = QApplication::clipboard()->mimeData(mode); + + if (!source || !qsb->canInsertFromMimeData(source)) + return; + + QString str = qsb->fromMimeData(source); + + pdoc->BeginUndoAction(); + + ClearSelection(); + + int len; + const char *s; + + QByteArray bytes; + + if (IsUnicodeMode()) + { + bytes = str.toUtf8(); + + len = bytes.length(); + s = bytes.data(); + } + else + { + bytes = str.toLatin1(); + len = bytes.length(); + s = bytes.data(); + } + + if (len) + pdoc->InsertString(currentPos, s, len); + + SetEmptySelection(currentPos + len); + + pdoc->EndUndoAction(); + + NotifyChange(); + Redraw(); +} + + +// Create a call tip window. +void ScintillaQt::CreateCallTipWindow(PRectangle rc) +{ + if (!ct.wCallTip.Created()) + ct.wCallTip = ct.wDraw = new SciCallTip(qsb, this); + + SciCallTip *w = reinterpret_cast(ct.wCallTip.GetID()); + + w->resize(rc.right - rc.left, rc.bottom - rc.top); + ct.wCallTip.Show(); +} + + +// Add an item to the right button menu. +void ScintillaQt::AddToPopUp(const char *label, int cmd, bool enabled) +{ + SciPopup *pm = static_cast(popup.GetID()); + + if (*label) + pm->addItem(qApp->translate("ContextMenu", label), cmd, enabled, this); + else + pm->addSeparator(); +} + + +// Claim the selection. +void ScintillaQt::ClaimSelection() +{ + bool isSel = (currentPos != anchor); + + if (isSel) + { + QClipboard *cb = QApplication::clipboard(); + + // If we support X11 style selection then make it available now. + if (cb->supportsSelection()) + { + SelectionText text; + + CopySelectionRange(&text); + + if (text.s) + cb->setText(textRange(&text), QClipboard::Selection); + } + + primarySelection = true; + } + else + primarySelection = false; + + emit qsb->QSCN_SELCHANGED(isSel); +} + + +// Unclaim the selection. +void ScintillaQt::UnclaimSelection() +{ + if (primarySelection) + { + primarySelection = false; + qsb->viewport()->update(); + } +} + + +// Implemented to provide compatibility with the Windows version. +sptr_t ScintillaQt::DirectFunction(ScintillaQt *sciThis, unsigned int iMessage, + uptr_t wParam, sptr_t lParam) +{ + return sciThis->WndProc(iMessage,wParam,lParam); +} + + +// Draw the contents of the widget. +void ScintillaQt::paintEvent(QPaintEvent *e) +{ + Surface *sw = Surface::Allocate(); + + if (!sw) + return; + + paintState = painting; + + const QRect &qr = e->rect(); + + rcPaint.left = qr.left(); + rcPaint.top = qr.top(); + rcPaint.right = qr.right() + 1; + rcPaint.bottom = qr.bottom() + 1; + + PRectangle rcText = GetTextRectangle(); + paintingAllText = rcPaint.Contains(rcText); + + QPainter painter(qsb->viewport()); + + sw->Init(&painter); + sw->SetUnicodeMode(CodePage() == SC_CP_UTF8); + Paint(sw, rcPaint); + + delete sw; + + // If the painting area was insufficient to cover the new style or brace + // highlight positions then repaint the whole thing. + if (paintState == paintAbandoned) + qsb->viewport()->update(); + + paintState = notPainting; +} diff --git a/harbour/contrib/hbide/qscintilla/qt/ScintillaQt.h b/harbour/contrib/hbide/qscintilla/qt/ScintillaQt.h new file mode 100644 index 0000000000..fc1c10cd9f --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/ScintillaQt.h @@ -0,0 +1,125 @@ +// The definition of the Qt specific subclass of ScintillaBase. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef SCINTILLAQT_H +#define SCINTILLAQT_H + + +#include +#include + +// These are needed because scintilla class header files don't seem to manage +// their own dependencies properly. +#include +#include +#include "Platform.h" +#include "Scintilla.h" +#include "SVector.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "CellBuffer.h" +#include "CharClassify.h" +#include "RunStyles.h" +#include "Decoration.h" +#include "Document.h" +#include "Style.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Indicator.h" +#include "ViewStyle.h" +#include "KeyMap.h" +#include "ContractionState.h" +#include "PositionCache.h" +#include "Editor.h" +#include "AutoComplete.h" +#include "CallTip.h" +#include "SString.h" +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" + +#include "ScintillaBase.h" + + +class QPaintEvent; +class QDropEvent; + +class QsciScintillaBase; +class SciCallTip; +class SciPopup; + + +class ScintillaQt : public ScintillaBase +{ + friend class QsciScintillaBase; + friend class SciCallTip; + friend class SciPopup; + +public: + ScintillaQt(QsciScintillaBase *qsb_); + virtual ~ScintillaQt(); + + virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, + sptr_t lParam); + +private: + void Initialise(); + void Finalise(); + void StartDrag(); + sptr_t DefWndProc(unsigned int, uptr_t, sptr_t); + void SetTicking(bool); + void SetMouseCapture(bool on); + bool HaveMouseCapture(); + void SetVerticalScrollPos(); + void SetHorizontalScrollPos(); + bool ModifyScrollBars(int nMax, int nPage); + void ReconfigureScrollBars(); + void NotifyChange(); + void NotifyParent(SCNotification scn); + void CopyToClipboard(const SelectionText &selectedText); + void Copy(); + void Paste(); + void CreateCallTipWindow(PRectangle rc); + void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); + void ClaimSelection(); + void UnclaimSelection(); + static sptr_t DirectFunction(ScintillaQt *sci, unsigned int iMessage, + uptr_t wParam,sptr_t lParam); + + QString textRange(const SelectionText *text); + void paintEvent(QPaintEvent *e); + void pasteFromClipboard(QClipboard::Mode mode); + + bool capturedMouse; + QsciScintillaBase *qsb; + QTimer qtimer; +}; + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/moc_SciClasses.cpp b/harbour/contrib/hbide/qscintilla/qt/moc_SciClasses.cpp new file mode 100644 index 0000000000..6cb91bfb3b --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/moc_SciClasses.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'SciClasses.h' +** +** Created: Wed May 19 22:56:02 2010 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "SciClasses.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'SciClasses.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.6.2. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_SciCallTip[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_SciCallTip[] = { + "SciCallTip\0" +}; + +const QMetaObject SciCallTip::staticMetaObject = { + { &QWidget::staticMetaObject, qt_meta_stringdata_SciCallTip, + qt_meta_data_SciCallTip, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &SciCallTip::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *SciCallTip::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *SciCallTip::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_SciCallTip)) + return static_cast(const_cast< SciCallTip*>(this)); + return QWidget::qt_metacast(_clname); +} + +int SciCallTip::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_SciPopup[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 14, 10, 9, 9, 0x08, + + 0 // eod +}; + +static const char qt_meta_stringdata_SciPopup[] = { + "SciPopup\0\0cmd\0on_triggered(int)\0" +}; + +const QMetaObject SciPopup::staticMetaObject = { + { &QMenu::staticMetaObject, qt_meta_stringdata_SciPopup, + qt_meta_data_SciPopup, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &SciPopup::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *SciPopup::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *SciPopup::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_SciPopup)) + return static_cast(const_cast< SciPopup*>(this)); + return QMenu::qt_metacast(_clname); +} + +int SciPopup::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QMenu::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: on_triggered((*reinterpret_cast< int(*)>(_a[1]))); break; + default: ; + } + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_SciListBox[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 12, 11, 11, 11, 0x08, + + 0 // eod +}; + +static const char qt_meta_stringdata_SciListBox[] = { + "SciListBox\0\0handleSelection()\0" +}; + +const QMetaObject SciListBox::staticMetaObject = { + { &QListWidget::staticMetaObject, qt_meta_stringdata_SciListBox, + qt_meta_data_SciListBox, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &SciListBox::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *SciListBox::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *SciListBox::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_SciListBox)) + return static_cast(const_cast< SciListBox*>(this)); + return QListWidget::qt_metacast(_clname); +} + +int SciListBox::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QListWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: handleSelection(); break; + default: ; + } + _id -= 1; + } + return _id; +} +QT_END_MOC_NAMESPACE diff --git a/harbour/contrib/hbide/qscintilla/qt/moc_qscilexer.cpp b/harbour/contrib/hbide/qscintilla/qt/moc_qscilexer.cpp new file mode 100644 index 0000000000..f2455dfb2b --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/moc_qscilexer.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'qscilexer.h' +** +** Created: Wed May 19 22:54:33 2010 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "qscilexer.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'qscilexer.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.6.2. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_QsciLexer[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 14, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 5, // signalCount + + // signals: signature, parameters, type, tag, flags + 19, 11, 10, 10, 0x05, + 60, 44, 10, 10, 0x05, + 93, 85, 10, 10, 0x05, + 116, 11, 10, 10, 0x05, + 150, 141, 10, 10, 0x05, + + // slots: signature, parameters, type, tag, flags + 207, 191, 10, 10, 0x0a, + 231, 11, 10, 10, 0x0a, + 254, 252, 10, 10, 0x2a, + 285, 271, 10, 10, 0x0a, + 314, 306, 10, 10, 0x2a, + 331, 85, 10, 10, 0x0a, + 352, 350, 10, 10, 0x2a, + 367, 11, 10, 10, 0x0a, + 388, 252, 10, 10, 0x2a, + + 0 // eod +}; + +static const char qt_meta_stringdata_QsciLexer[] = { + "QsciLexer\0\0c,style\0colorChanged(QColor,int)\0" + "eolfilled,style\0eolFillChanged(bool,int)\0" + "f,style\0fontChanged(QFont,int)\0" + "paperChanged(QColor,int)\0prop,val\0" + "propertyChanged(const char*,const char*)\0" + "autoindentstyle\0setAutoIndentStyle(int)\0" + "setColor(QColor,int)\0c\0setColor(QColor)\0" + "eoffill,style\0setEolFill(bool,int)\0" + "eoffill\0setEolFill(bool)\0setFont(QFont,int)\0" + "f\0setFont(QFont)\0setPaper(QColor,int)\0" + "setPaper(QColor)\0" +}; + +const QMetaObject QsciLexer::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_QsciLexer, + qt_meta_data_QsciLexer, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &QsciLexer::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *QsciLexer::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *QsciLexer::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QsciLexer)) + return static_cast(const_cast< QsciLexer*>(this)); + return QObject::qt_metacast(_clname); +} + +int QsciLexer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: colorChanged((*reinterpret_cast< const QColor(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 1: eolFillChanged((*reinterpret_cast< bool(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 2: fontChanged((*reinterpret_cast< const QFont(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 3: paperChanged((*reinterpret_cast< const QColor(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 4: propertyChanged((*reinterpret_cast< const char*(*)>(_a[1])),(*reinterpret_cast< const char*(*)>(_a[2]))); break; + case 5: setAutoIndentStyle((*reinterpret_cast< int(*)>(_a[1]))); break; + case 6: setColor((*reinterpret_cast< const QColor(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 7: setColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 8: setEolFill((*reinterpret_cast< bool(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 9: setEolFill((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 10: setFont((*reinterpret_cast< const QFont(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 11: setFont((*reinterpret_cast< const QFont(*)>(_a[1]))); break; + case 12: setPaper((*reinterpret_cast< const QColor(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 13: setPaper((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + default: ; + } + _id -= 14; + } + return _id; +} + +// SIGNAL 0 +void QsciLexer::colorChanged(const QColor & _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void QsciLexer::eolFillChanged(bool _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 1, _a); +} + +// SIGNAL 2 +void QsciLexer::fontChanged(const QFont & _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 2, _a); +} + +// SIGNAL 3 +void QsciLexer::paperChanged(const QColor & _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 3, _a); +} + +// SIGNAL 4 +void QsciLexer::propertyChanged(const char * _t1, const char * _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 4, _a); +} +QT_END_MOC_NAMESPACE diff --git a/harbour/contrib/hbide/qscintilla/qt/moc_qscilexercpp.cpp b/harbour/contrib/hbide/qscintilla/qt/moc_qscilexercpp.cpp new file mode 100644 index 0000000000..d9a20bffb6 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/moc_qscilexercpp.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'qscilexercpp.h' +** +** Created: Wed May 19 22:54:48 2010 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "qscilexercpp.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'qscilexercpp.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.6.2. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_QsciLexerCPP[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 5, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 19, 14, 13, 13, 0x0a, + 39, 14, 13, 13, 0x0a, + 61, 14, 13, 13, 0x0a, + 82, 14, 13, 13, 0x0a, + 114, 108, 13, 13, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_QsciLexerCPP[] = { + "QsciLexerCPP\0\0fold\0setFoldAtElse(bool)\0" + "setFoldComments(bool)\0setFoldCompact(bool)\0" + "setFoldPreprocessor(bool)\0style\0" + "setStylePreprocessor(bool)\0" +}; + +const QMetaObject QsciLexerCPP::staticMetaObject = { + { &QsciLexer::staticMetaObject, qt_meta_stringdata_QsciLexerCPP, + qt_meta_data_QsciLexerCPP, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &QsciLexerCPP::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *QsciLexerCPP::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *QsciLexerCPP::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QsciLexerCPP)) + return static_cast(const_cast< QsciLexerCPP*>(this)); + return QsciLexer::qt_metacast(_clname); +} + +int QsciLexerCPP::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QsciLexer::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: setFoldAtElse((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 1: setFoldComments((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 2: setFoldCompact((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 3: setFoldPreprocessor((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 4: setStylePreprocessor((*reinterpret_cast< bool(*)>(_a[1]))); break; + default: ; + } + _id -= 5; + } + return _id; +} +QT_END_MOC_NAMESPACE diff --git a/harbour/contrib/hbide/qscintilla/qt/moc_qsciscintilla.cpp b/harbour/contrib/hbide/qscintilla/qt/moc_qsciscintilla.cpp new file mode 100644 index 0000000000..8e842ee344 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/moc_qsciscintilla.cpp @@ -0,0 +1,424 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'qsciscintilla.h' +** +** Created: Wed May 19 22:55:16 2010 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "qsciscintilla.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'qsciscintilla.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.6.2. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_QsciScintilla[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 102, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 9, // signalCount + + // signals: signature, parameters, type, tag, flags + 24, 15, 14, 14, 0x05, + 59, 55, 14, 14, 0x05, + 79, 14, 14, 14, 0x05, + 112, 94, 14, 14, 0x05, + 157, 14, 14, 14, 0x05, + 183, 181, 14, 14, 0x05, + 209, 14, 14, 14, 0x05, + 228, 14, 14, 14, 0x05, + 252, 242, 14, 14, 0x05, + + // slots: signature, parameters, type, tag, flags + 288, 283, 14, 14, 0x0a, + 304, 14, 14, 14, 0x0a, + 326, 14, 14, 14, 0x0a, + 349, 14, 14, 14, 0x0a, + 376, 14, 14, 14, 0x0a, + 386, 14, 14, 14, 0x0a, + 394, 14, 14, 14, 0x0a, + 401, 14, 14, 14, 0x0a, + 407, 14, 14, 14, 0x0a, + 434, 429, 14, 14, 0x0a, + 466, 457, 14, 14, 0x0a, + 480, 14, 14, 14, 0x2a, + 490, 429, 14, 14, 0x0a, + 504, 429, 14, 14, 0x0a, + 516, 283, 14, 14, 0x0a, + 548, 532, 14, 14, 0x0a, + 574, 14, 14, 14, 0x0a, + 596, 14, 14, 14, 0x0a, + 604, 14, 14, 14, 0x0a, + 611, 14, 14, 14, 0x0a, + 632, 14, 14, 14, 0x0a, + 664, 14, 14, 14, 0x0a, + 703, 696, 14, 14, 0x0a, + 719, 14, 14, 14, 0x2a, + 731, 14, 14, 14, 0x0a, + 758, 755, 14, 14, 0x0a, + 805, 797, 14, 14, 0x0a, + 847, 840, 14, 14, 0x0a, + 888, 881, 14, 14, 0x0a, + 941, 934, 14, 14, 0x0a, + 984, 973, 14, 14, 0x0a, + 1007, 1004, 14, 14, 0x0a, + 1045, 1036, 14, 14, 0x0a, + 1077, 1073, 14, 14, 0x0a, + 1109, 1073, 14, 14, 0x0a, + 1152, 1145, 14, 14, 0x0a, + 1184, 1178, 14, 14, 0x0a, + 1205, 1203, 14, 14, 0x0a, + 1233, 1222, 14, 14, 0x0a, + 1265, 1260, 14, 14, 0x0a, + 1293, 1285, 14, 14, 0x0a, + 1328, 1316, 14, 14, 0x0a, + 1359, 1354, 14, 14, 0x2a, + 1398, 1381, 14, 14, 0x0a, + 1422, 1145, 14, 14, 0x0a, + 1449, 1073, 14, 14, 0x0a, + 1493, 1073, 14, 14, 0x0a, + 1542, 1537, 14, 14, 0x0a, + 1571, 1178, 14, 14, 0x0a, + 1602, 1596, 14, 14, 0x0a, + 1623, 14, 14, 14, 0x2a, + 1634, 1073, 14, 14, 0x0a, + 1670, 1668, 14, 14, 0x0a, + 1692, 1073, 14, 14, 0x0a, + 1738, 1726, 14, 14, 0x0a, + 1781, 1769, 14, 14, 0x0a, + 1822, 1810, 14, 14, 0x0a, + 1866, 1853, 14, 14, 0x0a, + 1899, 1890, 14, 14, 0x0a, + 1927, 181, 14, 14, 0x0a, + 1945, 1203, 14, 14, 0x0a, + 1965, 1962, 14, 14, 0x0a, + 2017, 1983, 14, 14, 0x0a, + 2047, 1073, 14, 14, 0x0a, + 2083, 1073, 14, 14, 0x0a, + 2126, 2119, 14, 14, 0x0a, + 2146, 1178, 14, 14, 0x0a, + 2163, 283, 14, 14, 0x0a, + 2183, 2180, 14, 14, 0x0a, + 2197, 1260, 14, 14, 0x0a, + 2243, 1260, 14, 14, 0x0a, + 2265, 14, 14, 14, 0x0a, + 2272, 429, 14, 14, 0x0a, + 2292, 2286, 14, 14, 0x0a, + 2304, 14, 14, 14, 0x0a, + 2313, 2286, 14, 14, 0x0a, + 2326, 14, 14, 14, 0x0a, + 2341, 2336, 14, 14, 0x0a, + 2357, 2353, 14, 14, 0x08, + 2391, 2381, 14, 14, 0x08, + 2433, 2412, 14, 14, 0x08, + 2538, 2464, 14, 14, 0x08, + 2611, 2602, 14, 14, 0x08, + 2657, 14, 14, 14, 0x08, + 2682, 14, 14, 14, 0x08, + 2704, 55, 14, 14, 0x08, + 2733, 14, 14, 14, 0x08, + 2773, 2765, 14, 14, 0x08, + 2822, 2814, 14, 14, 0x08, + 2871, 2857, 14, 14, 0x08, + 2914, 2906, 14, 14, 0x08, + 2947, 2814, 14, 14, 0x08, + 2982, 14, 14, 14, 0x08, + + 0 // eod +}; + +static const char qt_meta_stringdata_QsciScintilla[] = { + "QsciScintilla\0\0line,pos\0" + "cursorPositionChanged(int,int)\0yes\0" + "copyAvailable(bool)\0linesChanged()\0" + "margin,line,state\0" + "marginClicked(int,int,Qt::KeyboardModifiers)\0" + "modificationAttempted()\0m\0" + "modificationChanged(bool)\0selectionChanged()\0" + "textChanged()\0id,string\0" + "userListActivated(int,QString)\0text\0" + "append(QString)\0autoCompleteFromAll()\0" + "autoCompleteFromAPIs()\0" + "autoCompleteFromDocument()\0callTip()\0" + "clear()\0copy()\0cut()\0ensureCursorVisible()\0" + "line\0ensureLineVisible(int)\0children\0" + "foldAll(bool)\0foldAll()\0foldLine(int)\0" + "indent(int)\0insert(QString)\0text,line,index\0" + "insertAt(QString,int,int)\0" + "moveToMatchingBrace()\0paste()\0redo()\0" + "removeSelectedText()\0" + "resetSelectionBackgroundColor()\0" + "resetSelectionForegroundColor()\0select\0" + "selectAll(bool)\0selectAll()\0" + "selectToMatchingBrace()\0cs\0" + "setAutoCompletionCaseSensitivity(bool)\0" + "replace\0setAutoCompletionReplaceWord(bool)\0" + "single\0setAutoCompletionShowSingle(bool)\0" + "source\0setAutoCompletionSource(AutoCompletionSource)\0" + "thresh\0setAutoCompletionThreshold(int)\0" + "autoindent\0setAutoIndent(bool)\0bm\0" + "setBraceMatching(BraceMatch)\0unindent\0" + "setBackspaceUnindents(bool)\0col\0" + "setCaretForegroundColor(QColor)\0" + "setCaretLineBackgroundColor(QColor)\0" + "enable\0setCaretLineVisible(bool)\0width\0" + "setCaretWidth(int)\0c\0setColor(QColor)\0" + "line,index\0setCursorPosition(int,int)\0" + "mode\0setEolMode(EolMode)\0visible\0" + "setEolVisibility(bool)\0fold,margin\0" + "setFolding(FoldStyle,int)\0fold\0" + "setFolding(FoldStyle)\0line,indentation\0" + "setIndentation(int,int)\0" + "setIndentationGuides(bool)\0" + "setIndentationGuidesBackgroundColor(QColor)\0" + "setIndentationGuidesForegroundColor(QColor)\0" + "tabs\0setIndentationsUseTabs(bool)\0" + "setIndentationWidth(int)\0lexer\0" + "setLexer(QsciLexer*)\0setLexer()\0" + "setMarginsBackgroundColor(QColor)\0f\0" + "setMarginsFont(QFont)\0" + "setMarginsForegroundColor(QColor)\0" + "margin,lnrs\0setMarginLineNumbers(int,bool)\0" + "margin,mask\0setMarginMarkerMask(int,int)\0" + "margin,sens\0setMarginSensitivity(int,bool)\0" + "margin,width\0setMarginWidth(int,int)\0" + "margin,s\0setMarginWidth(int,QString)\0" + "setModified(bool)\0setPaper(QColor)\0" + "ro\0setReadOnly(bool)\0" + "lineFrom,indexFrom,lineTo,indexTo\0" + "setSelection(int,int,int,int)\0" + "setSelectionBackgroundColor(QColor)\0" + "setSelectionForegroundColor(QColor)\0" + "indent\0setTabIndents(bool)\0setTabWidth(int)\0" + "setText(QString)\0cp\0setUtf8(bool)\0" + "setWhitespaceVisibility(WhitespaceVisibility)\0" + "setWrapMode(WrapMode)\0undo()\0unindent(int)\0" + "range\0zoomIn(int)\0zoomIn()\0zoomOut(int)\0" + "zoomOut()\0size\0zoomTo(int)\0dir\0" + "handleCallTipClick(int)\0charadded\0" + "handleCharAdded(int)\0pos,margin,modifiers\0" + "handleMarginClick(int,int,int)\0" + "pos,mtype,text,len,added,line,foldNow,foldPrev,token,annotationLinesAd" + "ded\0" + "handleModified(int,int,const char*,int,int,int,int,int,int,int)\0" + "prop,val\0handlePropertyChange(const char*,const char*)\0" + "handleSavePointReached()\0handleSavePointLeft()\0" + "handleSelectionChanged(bool)\0" + "handleAutoCompletionSelection()\0text,id\0" + "handleUserListSelection(const char*,int)\0" + "c,style\0handleStyleColorChange(QColor,int)\0" + "eolfill,style\0handleStyleEolFillChange(bool,int)\0" + "f,style\0handleStyleFontChange(QFont,int)\0" + "handleStylePaperChange(QColor,int)\0" + "handleUpdateUI()\0" +}; + +const QMetaObject QsciScintilla::staticMetaObject = { + { &QsciScintillaBase::staticMetaObject, qt_meta_stringdata_QsciScintilla, + qt_meta_data_QsciScintilla, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &QsciScintilla::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *QsciScintilla::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *QsciScintilla::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QsciScintilla)) + return static_cast(const_cast< QsciScintilla*>(this)); + return QsciScintillaBase::qt_metacast(_clname); +} + +int QsciScintilla::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QsciScintillaBase::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: cursorPositionChanged((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 1: copyAvailable((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 2: linesChanged(); break; + case 3: marginClicked((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< Qt::KeyboardModifiers(*)>(_a[3]))); break; + case 4: modificationAttempted(); break; + case 5: modificationChanged((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 6: selectionChanged(); break; + case 7: textChanged(); break; + case 8: userListActivated((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2]))); break; + case 9: append((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 10: autoCompleteFromAll(); break; + case 11: autoCompleteFromAPIs(); break; + case 12: autoCompleteFromDocument(); break; + case 13: callTip(); break; + case 14: clear(); break; + case 15: copy(); break; + case 16: cut(); break; + case 17: ensureCursorVisible(); break; + case 18: ensureLineVisible((*reinterpret_cast< int(*)>(_a[1]))); break; + case 19: foldAll((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 20: foldAll(); break; + case 21: foldLine((*reinterpret_cast< int(*)>(_a[1]))); break; + case 22: indent((*reinterpret_cast< int(*)>(_a[1]))); break; + case 23: insert((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 24: insertAt((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3]))); break; + case 25: moveToMatchingBrace(); break; + case 26: paste(); break; + case 27: redo(); break; + case 28: removeSelectedText(); break; + case 29: resetSelectionBackgroundColor(); break; + case 30: resetSelectionForegroundColor(); break; + case 31: selectAll((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 32: selectAll(); break; + case 33: selectToMatchingBrace(); break; + case 34: setAutoCompletionCaseSensitivity((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 35: setAutoCompletionReplaceWord((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 36: setAutoCompletionShowSingle((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 37: setAutoCompletionSource((*reinterpret_cast< AutoCompletionSource(*)>(_a[1]))); break; + case 38: setAutoCompletionThreshold((*reinterpret_cast< int(*)>(_a[1]))); break; + case 39: setAutoIndent((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 40: setBraceMatching((*reinterpret_cast< BraceMatch(*)>(_a[1]))); break; + case 41: setBackspaceUnindents((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 42: setCaretForegroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 43: setCaretLineBackgroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 44: setCaretLineVisible((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 45: setCaretWidth((*reinterpret_cast< int(*)>(_a[1]))); break; + case 46: setColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 47: setCursorPosition((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 48: setEolMode((*reinterpret_cast< EolMode(*)>(_a[1]))); break; + case 49: setEolVisibility((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 50: setFolding((*reinterpret_cast< FoldStyle(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 51: setFolding((*reinterpret_cast< FoldStyle(*)>(_a[1]))); break; + case 52: setIndentation((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 53: setIndentationGuides((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 54: setIndentationGuidesBackgroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 55: setIndentationGuidesForegroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 56: setIndentationsUseTabs((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 57: setIndentationWidth((*reinterpret_cast< int(*)>(_a[1]))); break; + case 58: setLexer((*reinterpret_cast< QsciLexer*(*)>(_a[1]))); break; + case 59: setLexer(); break; + case 60: setMarginsBackgroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 61: setMarginsFont((*reinterpret_cast< const QFont(*)>(_a[1]))); break; + case 62: setMarginsForegroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 63: setMarginLineNumbers((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< bool(*)>(_a[2]))); break; + case 64: setMarginMarkerMask((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 65: setMarginSensitivity((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< bool(*)>(_a[2]))); break; + case 66: setMarginWidth((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 67: setMarginWidth((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2]))); break; + case 68: setModified((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 69: setPaper((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 70: setReadOnly((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 71: setSelection((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3])),(*reinterpret_cast< int(*)>(_a[4]))); break; + case 72: setSelectionBackgroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 73: setSelectionForegroundColor((*reinterpret_cast< const QColor(*)>(_a[1]))); break; + case 74: setTabIndents((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 75: setTabWidth((*reinterpret_cast< int(*)>(_a[1]))); break; + case 76: setText((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 77: setUtf8((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 78: setWhitespaceVisibility((*reinterpret_cast< WhitespaceVisibility(*)>(_a[1]))); break; + case 79: setWrapMode((*reinterpret_cast< WrapMode(*)>(_a[1]))); break; + case 80: undo(); break; + case 81: unindent((*reinterpret_cast< int(*)>(_a[1]))); break; + case 82: zoomIn((*reinterpret_cast< int(*)>(_a[1]))); break; + case 83: zoomIn(); break; + case 84: zoomOut((*reinterpret_cast< int(*)>(_a[1]))); break; + case 85: zoomOut(); break; + case 86: zoomTo((*reinterpret_cast< int(*)>(_a[1]))); break; + case 87: handleCallTipClick((*reinterpret_cast< int(*)>(_a[1]))); break; + case 88: handleCharAdded((*reinterpret_cast< int(*)>(_a[1]))); break; + case 89: handleMarginClick((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3]))); break; + case 90: handleModified((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< const char*(*)>(_a[3])),(*reinterpret_cast< int(*)>(_a[4])),(*reinterpret_cast< int(*)>(_a[5])),(*reinterpret_cast< int(*)>(_a[6])),(*reinterpret_cast< int(*)>(_a[7])),(*reinterpret_cast< int(*)>(_a[8])),(*reinterpret_cast< int(*)>(_a[9])),(*reinterpret_cast< int(*)>(_a[10]))); break; + case 91: handlePropertyChange((*reinterpret_cast< const char*(*)>(_a[1])),(*reinterpret_cast< const char*(*)>(_a[2]))); break; + case 92: handleSavePointReached(); break; + case 93: handleSavePointLeft(); break; + case 94: handleSelectionChanged((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 95: handleAutoCompletionSelection(); break; + case 96: handleUserListSelection((*reinterpret_cast< const char*(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 97: handleStyleColorChange((*reinterpret_cast< const QColor(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 98: handleStyleEolFillChange((*reinterpret_cast< bool(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 99: handleStyleFontChange((*reinterpret_cast< const QFont(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 100: handleStylePaperChange((*reinterpret_cast< const QColor(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 101: handleUpdateUI(); break; + default: ; + } + _id -= 102; + } + return _id; +} + +// SIGNAL 0 +void QsciScintilla::cursorPositionChanged(int _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void QsciScintilla::copyAvailable(bool _t1) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; + QMetaObject::activate(this, &staticMetaObject, 1, _a); +} + +// SIGNAL 2 +void QsciScintilla::linesChanged() +{ + QMetaObject::activate(this, &staticMetaObject, 2, 0); +} + +// SIGNAL 3 +void QsciScintilla::marginClicked(int _t1, int _t2, Qt::KeyboardModifiers _t3) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)) }; + QMetaObject::activate(this, &staticMetaObject, 3, _a); +} + +// SIGNAL 4 +void QsciScintilla::modificationAttempted() +{ + QMetaObject::activate(this, &staticMetaObject, 4, 0); +} + +// SIGNAL 5 +void QsciScintilla::modificationChanged(bool _t1) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; + QMetaObject::activate(this, &staticMetaObject, 5, _a); +} + +// SIGNAL 6 +void QsciScintilla::selectionChanged() +{ + QMetaObject::activate(this, &staticMetaObject, 6, 0); +} + +// SIGNAL 7 +void QsciScintilla::textChanged() +{ + QMetaObject::activate(this, &staticMetaObject, 7, 0); +} + +// SIGNAL 8 +void QsciScintilla::userListActivated(int _t1, const QString & _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 8, _a); +} +QT_END_MOC_NAMESPACE diff --git a/harbour/contrib/hbide/qscintilla/qt/moc_qsciscintillabase.cpp b/harbour/contrib/hbide/qscintilla/qt/moc_qsciscintillabase.cpp new file mode 100644 index 0000000000..6407d6eee6 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/moc_qsciscintillabase.cpp @@ -0,0 +1,337 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'qsciscintillabase.h' +** +** Created: Wed May 19 22:55:29 2010 +** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include "qsciscintillabase.h" +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'qsciscintillabase.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 62 +#error "This file was generated using the moc from 4.6.2. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_QsciScintillaBase[] = { + + // content: + 4, // revision + 0, // classname + 0, 0, // classinfo + 30, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 26, // signalCount + + // signals: signature, parameters, type, tag, flags + 23, 19, 18, 18, 0x05, + 45, 18, 18, 18, 0x05, + 66, 18, 18, 18, 0x05, + 108, 89, 18, 18, 0x05, + 144, 18, 18, 18, 0x05, + 168, 158, 18, 18, 0x05, + 200, 190, 18, 18, 0x05, + 243, 219, 18, 18, 0x05, + 275, 272, 18, 18, 0x05, + 301, 272, 18, 18, 0x05, + 348, 329, 18, 18, 0x05, + 374, 329, 18, 18, 0x05, + 406, 329, 18, 18, 0x05, + 434, 329, 18, 18, 0x05, + 464, 272, 18, 18, 0x05, + 524, 498, 18, 18, 0x05, + 563, 553, 18, 18, 0x05, + 625, 18, 18, 18, 0x05, + 649, 647, 18, 18, 0x05, + 672, 18, 18, 18, 0x05, + 686, 18, 18, 18, 0x05, + 706, 18, 18, 18, 0x05, + 738, 729, 18, 18, 0x05, + 759, 18, 18, 18, 0x05, + 774, 647, 18, 18, 0x05, + 813, 18, 18, 18, 0x05, + + // slots: signature, parameters, type, tag, flags + 824, 18, 18, 18, 0x08, + 844, 838, 18, 18, 0x08, + 859, 838, 18, 18, 0x08, + 874, 18, 18, 18, 0x08, + + 0 // eod +}; + +static const char qt_meta_stringdata_QsciScintillaBase[] = { + "QsciScintillaBase\0\0yes\0QSCN_SELCHANGED(bool)\0" + "SCN_AUTOCCANCELLED()\0SCN_AUTOCCHARDELETED()\0" + "selection,position\0" + "SCN_AUTOCSELECTION(const char*,int)\0" + "SCEN_CHANGE()\0direction\0SCN_CALLTIPCLICK(int)\0" + "charadded\0SCN_CHARADDED(int)\0" + "position,line,modifiers\0" + "SCN_DOUBLECLICK(int,int,int)\0,,\0" + "SCN_DWELLEND(int,int,int)\0" + "SCN_DWELLSTART(int,int,int)\0" + "position,modifiers\0SCN_HOTSPOTCLICK(int,int)\0" + "SCN_HOTSPOTDOUBLECLICK(int,int)\0" + "SCN_INDICATORCLICK(int,int)\0" + "SCN_INDICATORRELEASE(int,int)\0" + "SCN_MACRORECORD(uint,ulong,void*)\0" + "position,modifiers,margin\0" + "SCN_MARGINCLICK(int,int,int)\0,,,,,,,,,\0" + "SCN_MODIFIED(int,int,const char*,int,int,int,int,int,int,int)\0" + "SCN_MODIFYATTEMPTRO()\0,\0SCN_NEEDSHOWN(int,int)\0" + "SCN_PAINTED()\0SCN_SAVEPOINTLEFT()\0" + "SCN_SAVEPOINTREACHED()\0position\0" + "SCN_STYLENEEDED(int)\0SCN_UPDATEUI()\0" + "SCN_USERLISTSELECTION(const char*,int)\0" + "SCN_ZOOM()\0handleTimer()\0value\0" + "handleVSb(int)\0handleHSb(int)\0" + "handleSelection()\0" +}; + +const QMetaObject QsciScintillaBase::staticMetaObject = { + { &QAbstractScrollArea::staticMetaObject, qt_meta_stringdata_QsciScintillaBase, + qt_meta_data_QsciScintillaBase, 0 } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &QsciScintillaBase::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *QsciScintillaBase::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *QsciScintillaBase::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_QsciScintillaBase)) + return static_cast(const_cast< QsciScintillaBase*>(this)); + return QAbstractScrollArea::qt_metacast(_clname); +} + +int QsciScintillaBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QAbstractScrollArea::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: QSCN_SELCHANGED((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 1: SCN_AUTOCCANCELLED(); break; + case 2: SCN_AUTOCCHARDELETED(); break; + case 3: SCN_AUTOCSELECTION((*reinterpret_cast< const char*(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 4: SCEN_CHANGE(); break; + case 5: SCN_CALLTIPCLICK((*reinterpret_cast< int(*)>(_a[1]))); break; + case 6: SCN_CHARADDED((*reinterpret_cast< int(*)>(_a[1]))); break; + case 7: SCN_DOUBLECLICK((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3]))); break; + case 8: SCN_DWELLEND((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3]))); break; + case 9: SCN_DWELLSTART((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3]))); break; + case 10: SCN_HOTSPOTCLICK((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 11: SCN_HOTSPOTDOUBLECLICK((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 12: SCN_INDICATORCLICK((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 13: SCN_INDICATORRELEASE((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 14: SCN_MACRORECORD((*reinterpret_cast< uint(*)>(_a[1])),(*reinterpret_cast< ulong(*)>(_a[2])),(*reinterpret_cast< void*(*)>(_a[3]))); break; + case 15: SCN_MARGINCLICK((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3]))); break; + case 16: SCN_MODIFIED((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])),(*reinterpret_cast< const char*(*)>(_a[3])),(*reinterpret_cast< int(*)>(_a[4])),(*reinterpret_cast< int(*)>(_a[5])),(*reinterpret_cast< int(*)>(_a[6])),(*reinterpret_cast< int(*)>(_a[7])),(*reinterpret_cast< int(*)>(_a[8])),(*reinterpret_cast< int(*)>(_a[9])),(*reinterpret_cast< int(*)>(_a[10]))); break; + case 17: SCN_MODIFYATTEMPTRO(); break; + case 18: SCN_NEEDSHOWN((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 19: SCN_PAINTED(); break; + case 20: SCN_SAVEPOINTLEFT(); break; + case 21: SCN_SAVEPOINTREACHED(); break; + case 22: SCN_STYLENEEDED((*reinterpret_cast< int(*)>(_a[1]))); break; + case 23: SCN_UPDATEUI(); break; + case 24: SCN_USERLISTSELECTION((*reinterpret_cast< const char*(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break; + case 25: SCN_ZOOM(); break; + case 26: handleTimer(); break; + case 27: handleVSb((*reinterpret_cast< int(*)>(_a[1]))); break; + case 28: handleHSb((*reinterpret_cast< int(*)>(_a[1]))); break; + case 29: handleSelection(); break; + default: ; + } + _id -= 30; + } + return _id; +} + +// SIGNAL 0 +void QsciScintillaBase::QSCN_SELCHANGED(bool _t1) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void QsciScintillaBase::SCN_AUTOCCANCELLED() +{ + QMetaObject::activate(this, &staticMetaObject, 1, 0); +} + +// SIGNAL 2 +void QsciScintillaBase::SCN_AUTOCCHARDELETED() +{ + QMetaObject::activate(this, &staticMetaObject, 2, 0); +} + +// SIGNAL 3 +void QsciScintillaBase::SCN_AUTOCSELECTION(const char * _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 3, _a); +} + +// SIGNAL 4 +void QsciScintillaBase::SCEN_CHANGE() +{ + QMetaObject::activate(this, &staticMetaObject, 4, 0); +} + +// SIGNAL 5 +void QsciScintillaBase::SCN_CALLTIPCLICK(int _t1) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; + QMetaObject::activate(this, &staticMetaObject, 5, _a); +} + +// SIGNAL 6 +void QsciScintillaBase::SCN_CHARADDED(int _t1) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; + QMetaObject::activate(this, &staticMetaObject, 6, _a); +} + +// SIGNAL 7 +void QsciScintillaBase::SCN_DOUBLECLICK(int _t1, int _t2, int _t3) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)) }; + QMetaObject::activate(this, &staticMetaObject, 7, _a); +} + +// SIGNAL 8 +void QsciScintillaBase::SCN_DWELLEND(int _t1, int _t2, int _t3) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)) }; + QMetaObject::activate(this, &staticMetaObject, 8, _a); +} + +// SIGNAL 9 +void QsciScintillaBase::SCN_DWELLSTART(int _t1, int _t2, int _t3) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)) }; + QMetaObject::activate(this, &staticMetaObject, 9, _a); +} + +// SIGNAL 10 +void QsciScintillaBase::SCN_HOTSPOTCLICK(int _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 10, _a); +} + +// SIGNAL 11 +void QsciScintillaBase::SCN_HOTSPOTDOUBLECLICK(int _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 11, _a); +} + +// SIGNAL 12 +void QsciScintillaBase::SCN_INDICATORCLICK(int _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 12, _a); +} + +// SIGNAL 13 +void QsciScintillaBase::SCN_INDICATORRELEASE(int _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 13, _a); +} + +// SIGNAL 14 +void QsciScintillaBase::SCN_MACRORECORD(unsigned int _t1, unsigned long _t2, void * _t3) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)) }; + QMetaObject::activate(this, &staticMetaObject, 14, _a); +} + +// SIGNAL 15 +void QsciScintillaBase::SCN_MARGINCLICK(int _t1, int _t2, int _t3) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)) }; + QMetaObject::activate(this, &staticMetaObject, 15, _a); +} + +// SIGNAL 16 +void QsciScintillaBase::SCN_MODIFIED(int _t1, int _t2, const char * _t3, int _t4, int _t5, int _t6, int _t7, int _t8, int _t9, int _t10) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)), const_cast(reinterpret_cast(&_t3)), const_cast(reinterpret_cast(&_t4)), const_cast(reinterpret_cast(&_t5)), const_cast(reinterpret_cast(&_t6)), const_cast(reinterpret_cast(&_t7)), const_cast(reinterpret_cast(&_t8)), const_cast(reinterpret_cast(&_t9)), const_cast(reinterpret_cast(&_t10)) }; + QMetaObject::activate(this, &staticMetaObject, 16, _a); +} + +// SIGNAL 17 +void QsciScintillaBase::SCN_MODIFYATTEMPTRO() +{ + QMetaObject::activate(this, &staticMetaObject, 17, 0); +} + +// SIGNAL 18 +void QsciScintillaBase::SCN_NEEDSHOWN(int _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 18, _a); +} + +// SIGNAL 19 +void QsciScintillaBase::SCN_PAINTED() +{ + QMetaObject::activate(this, &staticMetaObject, 19, 0); +} + +// SIGNAL 20 +void QsciScintillaBase::SCN_SAVEPOINTLEFT() +{ + QMetaObject::activate(this, &staticMetaObject, 20, 0); +} + +// SIGNAL 21 +void QsciScintillaBase::SCN_SAVEPOINTREACHED() +{ + QMetaObject::activate(this, &staticMetaObject, 21, 0); +} + +// SIGNAL 22 +void QsciScintillaBase::SCN_STYLENEEDED(int _t1) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; + QMetaObject::activate(this, &staticMetaObject, 22, _a); +} + +// SIGNAL 23 +void QsciScintillaBase::SCN_UPDATEUI() +{ + QMetaObject::activate(this, &staticMetaObject, 23, 0); +} + +// SIGNAL 24 +void QsciScintillaBase::SCN_USERLISTSELECTION(const char * _t1, int _t2) +{ + void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)), const_cast(reinterpret_cast(&_t2)) }; + QMetaObject::activate(this, &staticMetaObject, 24, _a); +} + +// SIGNAL 25 +void QsciScintillaBase::SCN_ZOOM() +{ + QMetaObject::activate(this, &staticMetaObject, 25, 0); +} +QT_END_MOC_NAMESPACE diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciabstractapis.cpp b/harbour/contrib/hbide/qscintilla/qt/qsciabstractapis.cpp new file mode 100644 index 0000000000..c9676df213 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciabstractapis.cpp @@ -0,0 +1,62 @@ +// This module implements the QsciAbstractAPIs class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qsciabstractapis.h" + +#include "qscilexer.h" + + +// The ctor. +QsciAbstractAPIs::QsciAbstractAPIs(QsciLexer *lexer) + : QObject(lexer), + lex(lexer) +{ + lexer->setAPIs(this); +} + + +// The dtor. +QsciAbstractAPIs::~QsciAbstractAPIs() +{ +} + + +// Return the lexer. +QsciLexer *QsciAbstractAPIs::lexer() const +{ + return lex; +} + + +// Called when the user has made a selection from the auto-completion list. +void QsciAbstractAPIs::autoCompletionSelected(const QString &selection) +{ + Q_UNUSED( selection ); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciabstractapis.h b/harbour/contrib/hbide/qscintilla/qt/qsciabstractapis.h new file mode 100644 index 0000000000..0946e252a6 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciabstractapis.h @@ -0,0 +1,110 @@ +// This module defines interface to the QsciAbstractAPIs class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCIABSTRACTAPIS_H +#define QSCIABSTRACTAPIS_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include +#include + +#include + +#include +#include + + +class QsciLexer; + + +//! \brief The QsciAbstractAPIs class represents the interface to the textual +//! API information used in call tips and for auto-completion. A sub-class +//! will provide the actual implementation of the interface. +//! +//! API information is specific to a particular language lexer but can be +//! shared by multiple instances of the lexer. +class QSCINTILLA_EXPORT QsciAbstractAPIs : public QObject +{ + Q_OBJECT + +public: + //! Constructs a QsciAbstractAPIs instance attached to lexer \a lexer. \a + //! lexer becomes the instance's parent object although the instance can + //! also be subsequently attached to other lexers. + QsciAbstractAPIs(QsciLexer *lexer); + + //! Destroy the QsciAbstractAPIs instance. + virtual ~QsciAbstractAPIs(); + + //! Return the lexer that the instance is attached to. + QsciLexer *lexer() const; + + //! Update the list \a list with API entries derived from \a context. \a + //! context is the list of words in the text preceding the cursor position. + //! The characters that make up a word and the characters that separate + //! words are defined by the lexer. The last word is a partial word and + //! may be empty if the user has just entered a word separator. + virtual void updateAutoCompletionList(const QStringList &context, + QStringList &list) = 0; + + //! This is called when the user selects the entry \a selection from the + //! auto-completion list. A sub-class can use this as a hint to provide + //! more specific API entries in future calls to + //! updateAutoCompletionList(). The default implementation does nothing. + virtual void autoCompletionSelected(const QString &selection); + + //! Return the call tips valid for the context \a context. (Note that the + //! last word of the context will always be empty.) \a commas is the number + //! of commas the user has typed after the context and before the cursor + //! position. The exact position of the list of call tips can be adjusted + //! by specifying a corresponding left character shift in \a shifts. This + //! is normally done to correct for any displayed context according to \a + //! style. + //! + //! \sa updateAutoCompletionList() + virtual QStringList callTips(const QStringList &context, int commas, + QsciScintilla::CallTipsStyle style, + QList &shifts) = 0; + +private: + QsciLexer *lex; + + QsciAbstractAPIs(const QsciAbstractAPIs &); + QsciAbstractAPIs &operator=(const QsciAbstractAPIs &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciapis.cpp b/harbour/contrib/hbide/qscintilla/qt/qsciapis.cpp new file mode 100644 index 0000000000..4124f39092 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciapis.cpp @@ -0,0 +1,961 @@ +// This module implements the QsciAPIs class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include + +#include "qsciapis.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "qscilexer.h" + + + +// The version number of the prepared API information format. +const unsigned char PreparedDataFormatVersion = 0; + + +// This class contains prepared API information. +struct QsciAPIsPrepared +{ + // The word dictionary is a map of individual words and a list of positions + // each occurs in the sorted list of APIs. A position is a tuple of the + // index into the list of APIs and the index into the particular API. + QMap wdict; + + // The case dictionary maps the case insensitive words to the form in which + // they are to be used. It is only used if the language is case + // insensitive. + QMap cdict; + + + // The raw API information. + QStringList raw_apis; + + QStringList apiWords(int api_idx, const QStringList &wseps, + bool strip_image) const; + static QString apiBaseName(const QString &api); +}; + + + +// Return a particular API entry as a list of words. +QStringList QsciAPIsPrepared::apiWords(int api_idx, const QStringList &wseps, + bool strip_image) const +{ + QString base = apiBaseName(raw_apis[api_idx]); + + // Remove any embedded image reference if necessary. + if (strip_image) + { + int tail = base.indexOf('?'); + + if (tail >= 0) + base.truncate(tail); + } + + if (wseps.isEmpty()) + return QStringList(base); + + return base.split(wseps.first()); +} + + +// Return the name of an API function, ie. without the arguments. +QString QsciAPIsPrepared::apiBaseName(const QString &api) +{ + QString base = api; + int tail = base.indexOf('('); + + if (tail >= 0) + base.truncate(tail); + + return base; +} + + +// The user event type that signals that the worker thread has started. +const QEvent::Type WorkerStarted = static_cast(QEvent::User + 1012); + + +// The user event type that signals that the worker thread has finished. +const QEvent::Type WorkerFinished = static_cast(QEvent::User + 1013); + + +// The user event type that signals that the worker thread has aborted. +const QEvent::Type WorkerAborted = static_cast(QEvent::User + 1014); + + +// This class is the worker thread that post-processes the API set. +class QsciAPIsWorker : public QThread +{ +public: + QsciAPIsWorker(QsciAPIs *apis); + virtual ~QsciAPIsWorker(); + + virtual void run(); + + QsciAPIsPrepared *prepared; + +private: + QsciAPIs *proxy; + bool abort; +}; + + +// The worker thread ctor. +QsciAPIsWorker::QsciAPIsWorker(QsciAPIs *apis) + : proxy(apis), prepared(0), abort(false) +{ +} + + +// The worker thread dtor. +QsciAPIsWorker::~QsciAPIsWorker() +{ + // Tell the thread to stop. There is no need to bother with a mutex. + abort = true; + + // Wait for it to do so and hit it if it doesn't. + if (!wait(500)) + terminate(); + + if (prepared) + delete prepared; +} + + +// The worker thread entry point. +void QsciAPIsWorker::run() +{ + // Sanity check. + if (!prepared) + return; + + // Tell the main thread we have started. + QApplication::postEvent(proxy, new QEvent(WorkerStarted)); + + // Sort the full list. + prepared->raw_apis.sort(); + + QStringList wseps = proxy->lexer()->autoCompletionWordSeparators(); + bool cs = proxy->lexer()->caseSensitive(); + + // Split each entry into separate words but ignoring any arguments. + for (int a = 0; a < prepared->raw_apis.count(); ++a) + { + // Check to see if we should stop. + if (abort) + break; + + QStringList words = prepared->apiWords(a, wseps, true); + + for (int w = 0; w < words.count(); ++w) + { + const QString &word = words[w]; + + // Add the word's position to any existing list for this word. + QsciAPIs::WordIndexList wil = prepared->wdict[word]; + + // If the language is case insensitive and we haven't seen this + // word before then save it in the case dictionary. + if (!cs && wil.count() == 0) + prepared->cdict[word.toUpper()] = word; + + wil.append(QsciAPIs::WordIndex(a, w)); + prepared->wdict[word] = wil; + } + } + + + // Tell the main thread we have finished. + QApplication::postEvent(proxy, new QEvent(abort ? WorkerAborted : WorkerFinished)); +} + + +// The ctor. +QsciAPIs::QsciAPIs(QsciLexer *lexer) + : QsciAbstractAPIs(lexer), + worker(0), origin_len(0) +{ + prep = new QsciAPIsPrepared; +} + + +// The dtor. +QsciAPIs::~QsciAPIs() +{ + deleteWorker(); + delete prep; +} + + +// Delete the worker thread if there is one. +void QsciAPIs::deleteWorker() +{ + if (worker) + { + delete worker; + worker = 0; + } +} + + +//! Handle termination events from the worker thread. +bool QsciAPIs::event(QEvent *e) +{ + switch (e->type()) + { + case WorkerStarted: + emit apiPreparationStarted(); + return true; + + case WorkerAborted: + deleteWorker(); + emit apiPreparationCancelled(); + return true; + + case WorkerFinished: + delete prep; + old_context.clear(); + + prep = worker->prepared; + worker->prepared = 0; + deleteWorker(); + + // Allow the raw API information to be modified. + apis = prep->raw_apis; + + emit apiPreparationFinished(); + + return true; + + default: + break; + } + + return QObject::event(e); +} + + +// Clear the current raw API entries. +void QsciAPIs::clear() +{ + apis.clear(); +} + + +// Clear out all API information. +bool QsciAPIs::load(const QString &fname) +{ + QFile f(fname); + + if (!f.open(QIODevice::ReadOnly)) + return false; + + QTextStream ts(&f); + + for (;;) + { + QString line = ts.readLine(); + + if (line.isEmpty()) + break; + + apis.append(line); + } + + return true; +} + + +// Add a single API entry. +void QsciAPIs::add(const QString &entry) +{ + apis.append(entry); +} + + +// Remove a single API entry. +void QsciAPIs::remove(const QString &entry) +{ + int idx = apis.indexOf(entry); + + if (idx >= 0) + apis.removeAt(idx); +} + + +// Position the "origin" cursor into the API entries according to the user +// supplied context. +QStringList QsciAPIs::positionOrigin(const QStringList &context, QString &path) +{ + // Get the list of words and see if the context is the same as last time we + // were called. + QStringList new_context; + bool same_context = (old_context.count() > 0 && old_context.count() < context.count()); + + for (int i = 0; i < context.count(); ++i) + { + QString word = context[i]; + + if (!lexer()->caseSensitive()) + word = word.toUpper(); + + if (i < old_context.count() && old_context[i] != word) + same_context = false; + + new_context << word; + } + + // If the context has changed then reset the origin. + if (!same_context) + origin_len = 0; + + // If we have a current origin (ie. the user made a specific selection in + // the current context) then adjust the origin to include the last complete + // word as the user may have entered more parts of the name without using + // auto-completion. + if (origin_len > 0) + { + const QString wsep = lexer()->autoCompletionWordSeparators().first(); + + int start_new = old_context.count(); + int end_new = new_context.count() - 1; + + QString fixed = *origin; + fixed.truncate(origin_len); + + path = fixed; + + while (start_new < end_new) + { + // Add this word to the current path. + path.append(wsep); + path.append(new_context[start_new]); + origin_len = path.length(); + + // Skip entries in the current origin that don't match the path. + while (origin != prep->raw_apis.end()) + { + // See if the current origin has come to an end. + if (!originStartsWith(fixed, wsep)) + origin = prep->raw_apis.end(); + else if (originStartsWith(path, wsep)) + break; + else + ++origin; + } + + if (origin == prep->raw_apis.end()) + break; + + ++start_new; + } + + // If the new text wasn't recognised then reset the origin. + if (origin == prep->raw_apis.end()) + origin_len = 0; + } + + if (origin_len == 0) + path.truncate(0); + + // Save the "committed" context for next time. + old_context = new_context; + old_context.removeLast(); + + return new_context; +} + + +// Return true if the origin starts with the given path. +bool QsciAPIs::originStartsWith(const QString &path, const QString &wsep) +{ + const QString &orig = *origin; + + if (!orig.startsWith(path)) + return false; + + // Check that the path corresponds to the end of a word, ie. that what + // follows in the origin is either a word separator or a (. + QString tail = orig.mid(path.length()); + + return (!tail.isEmpty() && (tail.startsWith(wsep) || tail.at(0) == '(')); +} + + +// Add auto-completion words to an existing list. +void QsciAPIs::updateAutoCompletionList(const QStringList &context, + QStringList &list) +{ + QString path; + QStringList new_context = positionOrigin(context, path); + + if (origin_len > 0) + { + const QString wsep = lexer()->autoCompletionWordSeparators().first(); + QStringList::const_iterator it = origin; + + unambiguous_context = path; + + while (it != prep->raw_apis.end()) + { + QString base = QsciAPIsPrepared::apiBaseName(*it); + + if (!base.startsWith(path)) + break; + + // Make sure we have something after the path. + if (base != path) + { + // Get the word we are interested in (ie. the one after the + // current origin in path). + QString w = base.mid(origin_len + wsep.length()).split(wsep).first(); + + // Append the space, we know the origin is unambiguous. + w.append(' '); + + if (!list.contains(w)) + list << w; + } + + ++it; + } + } + else + { + // At the moment we assume we will add words from multiple contexts. + unambiguous_context.truncate(0); + + bool unambig = true; + QStringList with_context; + + if (new_context.last().isEmpty()) + lastCompleteWord(new_context[new_context.count() - 2], with_context, unambig); + else + lastPartialWord(new_context.last(), with_context, unambig); + + for (int i = 0; i < with_context.count(); ++i) + { + // Remove any unambigious context. + QString noc = with_context[i]; + + if (unambig) + { + int op = noc.indexOf('('); + + if (op >= 0) + noc.truncate(op); + } + + list << noc; + } + } +} + + +// Get the index list for a particular word if there is one. +const QsciAPIs::WordIndexList *QsciAPIs::wordIndexOf(const QString &word) const +{ + QString csword; + + // Indirect through the case dictionary if the language isn't case + // sensitive. + if (lexer()->caseSensitive()) + csword = word; + else + { + csword = prep->cdict[word]; + + if (csword.isEmpty()) + return 0; + } + + // Get the possible API entries if any. + const WordIndexList *wl = &prep->wdict[csword]; + + if (wl->isEmpty()) + return 0; + + return wl; +} + + +// Add auto-completion words based on the last complete word entered. +void QsciAPIs::lastCompleteWord(const QString &word, QStringList &with_context, bool &unambig) +{ + // Get the possible API entries if any. + const WordIndexList *wl = wordIndexOf(word); + + if (wl) + addAPIEntries(*wl, true, with_context, unambig); +} + + +// Add auto-completion words based on the last partial word entered. +void QsciAPIs::lastPartialWord(const QString &word, QStringList &with_context, bool &unambig) +{ + if (lexer()->caseSensitive()) + { + QMap::const_iterator it = prep->wdict.lowerBound(word); + + while (it != prep->wdict.end()) + { + if (!it.key().startsWith(word)) + break; + + addAPIEntries(it.value(), false, with_context, unambig); + + ++it; + } + } + else + { + QMap::const_iterator it = prep->cdict.lowerBound(word); + + while (it != prep->cdict.end()) + { + if (!it.key().startsWith(word)) + break; + + addAPIEntries(prep->wdict[it.value()], false, with_context, unambig); + + ++it; + } + } +} + + +// Handle the selection of an entry in the auto-completion list. +void QsciAPIs::autoCompletionSelected(const QString &selection) +{ + // If the selection is an API (ie. it has a space separating the selected + // word and the optional origin) then remember the origin. + QStringList lst = selection.split(' '); + + if (lst.count() != 2) + { + origin_len = 0; + return; + } + + const QString &path = lst[1]; + QString owords; + + if (path.isEmpty()) + owords = unambiguous_context; + else + { + // Check the parenthesis. + if (!path.startsWith("(") || !path.endsWith(")")) + { + origin_len = 0; + return; + } + + // Remove the parenthesis. + owords = path.mid(1, path.length() - 2); + } + + origin = qLowerBound(prep->raw_apis, owords); + origin_len = owords.length(); +} + + +// Add auto-completion words for a particular word (defined by where it appears +// in the APIs) and depending on whether the word was complete (when it's +// actually the next word in the API entry that is of interest) or not. +void QsciAPIs::addAPIEntries(const WordIndexList &wl, bool complete, + QStringList &with_context, bool &unambig) +{ + QStringList wseps = lexer()->autoCompletionWordSeparators(); + + for (int w = 0; w < wl.count(); ++w) + { + const WordIndex &wi = wl[w]; + + QStringList api_words = prep->apiWords(wi.first, wseps, false); + + int idx = wi.second; + + if (complete) + { + // Skip if this is the last word. + if (++idx >= api_words.count()) + continue; + } + + QString api_word; + + if (idx == 0) + api_word = api_words[0] + ' '; + else + { + QStringList orgl = api_words.mid(0, idx); + + QString org = orgl.join(wseps.first()); + + api_word = QString("%1 (%2)").arg(api_words[idx]).arg(org); + + // See if the origin has been used before. + if (unambig) + if (unambiguous_context.isEmpty()) + unambiguous_context = org; + else if (unambiguous_context != org) + { + unambiguous_context.truncate(0); + unambig = false; + } + } + + if (!with_context.contains(api_word)) + with_context.append(api_word); + } +} + + +// Return the call tip for a function. +QStringList QsciAPIs::callTips(const QStringList &context, int commas, + QsciScintilla::CallTipsStyle style, + QList &shifts) +{ + QString path; + QStringList new_context = positionOrigin(context, path); + QStringList wseps = lexer()->autoCompletionWordSeparators(); + QStringList cts; + + if (origin_len > 0) + { + QStringList::const_iterator it = origin; + QString prev; + + // Work out the length of the context. + const QString &wsep = wseps.first(); + QStringList strip = path.split(wsep); + strip.removeLast(); + int ctstart = strip.join(wsep).length(); + + if (ctstart) + ctstart += wsep.length(); + + int shift; + + if (style == QsciScintilla::CallTipsContext) + { + shift = ctstart; + ctstart = 0; + } + else + shift = 0; + + // Make sure we only look at the functions we are interested in. + path.append('('); + + while (it != prep->raw_apis.end() && (*it).startsWith(path)) + { + QString w = (*it).mid(ctstart); + + if (w != prev && enoughCommas(w, commas)) + { + shifts << shift; + cts << w; + prev = w; + } + + ++it; + } + } + else + { + const QString &fname = new_context[new_context.count() - 2]; + + // Find everywhere the function name appears in the APIs. + const WordIndexList *wil = wordIndexOf(fname); + + if (wil) + for (int i = 0; i < wil->count(); ++i) + { + const WordIndex &wi = (*wil)[i]; + QStringList awords = prep->apiWords(wi.first, wseps, true); + + // Check the word is the function name and not part of any + // context. + if ((int)wi.second != awords.count() - 1) + continue; + + const QString &api = prep->raw_apis[wi.first]; + + int tail = api.indexOf('('); + + if (tail < 0) + continue; + + if (!enoughCommas(api, commas)) + continue; + + if (style == QsciScintilla::CallTipsNoContext) + { + shifts << 0; + cts << (fname + api.mid(tail)); + } + else + { + shifts << tail - fname.length(); + cts << api; + } + } + } + + return cts; +} + + +// Return true if a string has enough commas in the argument list. +bool QsciAPIs::enoughCommas(const QString &s, int commas) +{ + int end = s.indexOf(')'); + + if (end < 0) + return false; + + QString w = s.left(end); + + return (w.count(',') >= commas); +} + + +// Ensure the list is ready. +void QsciAPIs::prepare() +{ + // Handle the trivial case. + if (worker) + return; + + QsciAPIsPrepared *new_apis = new QsciAPIsPrepared; + new_apis->raw_apis = apis; + + worker = new QsciAPIsWorker(this); + worker->prepared = new_apis; + worker->start(); +} + + +// Cancel any current preparation. +void QsciAPIs::cancelPreparation() +{ + deleteWorker(); +} + + +// Check that a prepared API file exists. +bool QsciAPIs::isPrepared(const QString &fname) const +{ + QString pname = prepName(fname); + + if (pname.isEmpty()) + return false; + + QFileInfo fi(pname); + + return fi.exists(); +} + + +// Load the prepared API information. +bool QsciAPIs::loadPrepared(const QString &fname) +{ + QString pname = prepName(fname); + + if (pname.isEmpty()) + return false; + + // Read the prepared data and decompress it. + QFile pf(pname); + + if (!pf.open(QIODevice::ReadOnly)) + return false; + + QByteArray cpdata = pf.readAll(); + + pf.close(); + + if (cpdata.count() == 0) + return false; + + QByteArray pdata = qUncompress(cpdata); + + // Extract the data. + QDataStream pds(pdata); + + unsigned char vers; + pds >> vers; + + if (vers > PreparedDataFormatVersion) + return false; + + char *lex_name; + pds >> lex_name; + + if (qstrcmp(lex_name, lexer()->lexer()) != 0) + { + delete[] lex_name; + return false; + } + + delete[] lex_name; + + prep->wdict.clear(); + pds >> prep->wdict; + + if (!lexer()->caseSensitive()) + { + // Build up the case dictionary. + prep->cdict.clear(); + + QMap::const_iterator it = prep->wdict.begin(); + + while (it != prep->wdict.end()) + { + prep->cdict[it.key().toUpper()] = it.key(); + + ++it; + } + + } + + prep->raw_apis.clear(); + pds >> prep->raw_apis; + + // Allow the raw API information to be modified. + apis = prep->raw_apis; + + return true; +} + + +// Save the prepared API information. +bool QsciAPIs::savePrepared(const QString &fname) const +{ + QString pname = prepName(fname, true); + + if (pname.isEmpty()) + return false; + + // Write the prepared data to a memory buffer. + QByteArray pdata; + QDataStream pds(&pdata, QIODevice::WriteOnly); + + // Use a serialisation format supported by Qt v3.0 and later. + pds.setVersion(QDataStream::Qt_3_0); + pds << PreparedDataFormatVersion; + pds << lexer()->lexer(); + pds << prep->wdict; + pds << prep->raw_apis; + + // Compress the data and write it. + QFile pf(pname); + + if (!pf.open(QIODevice::WriteOnly|QIODevice::Truncate)) + return false; + + if (pf.write(qCompress(pdata)) < 0) + { + pf.close(); + return false; + } + + pf.close(); + return true; +} + + +// Return the name of the default prepared API file. +QString QsciAPIs::defaultPreparedName() const +{ + return prepName(QString()); +} + + +// Return the name of a prepared API file. +QString QsciAPIs::prepName(const QString &fname, bool mkpath) const +{ + // Handle the tivial case. + if (!fname.isEmpty()) + return fname; + + QString pdname; + char *qsci = getenv("QSCIDIR"); + + if (qsci) + pdname = qsci; + else + { + static const char *qsci_dir = ".qsci"; + + QDir pd = QDir::home(); + + if (mkpath && !pd.exists(qsci_dir) && !pd.mkdir(qsci_dir)) + return QString(); + + pdname = pd.filePath(qsci_dir); + } + + return QString("%1/%2.pap").arg(pdname).arg(lexer()->lexer()); +} + + +// Return installed API files. +QStringList QsciAPIs::installedAPIFiles() const +{ + QString qtdir = QLibraryInfo::location(QLibraryInfo::DataPath); + + QDir apidir = QDir(QString("%1/qsci/api/%2").arg(qtdir).arg(lexer()->lexer())); + QStringList fnames; + + QStringList filters; + filters << "*.api"; + + QFileInfoList flist = apidir.entryInfoList(filters, QDir::Files, QDir::IgnoreCase); + + foreach (QFileInfo fi, flist) + fnames << fi.absoluteFilePath(); + + return fnames; +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciapis.h b/harbour/contrib/hbide/qscintilla/qt/qsciapis.h new file mode 100644 index 0000000000..3e2d8f606a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciapis.h @@ -0,0 +1,232 @@ +// This module defines interface to the QsciAPIs class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCIAPIS_H +#define QSCIAPIS_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include +#include +#include + +#include + +#include +#include +#include + + +class QsciAPIsPrepared; +class QsciAPIsWorker; +class QsciLexer; + + +//! \brief The QsciAPIs class provies an implementation of the textual API +//! information used in call tips and for auto-completion. +//! +//! Raw API information is read from one or more files. Each API function is +//! described by a single line of text comprising the function's name, followed +//! by the function's optional comma separated parameters enclosed in +//! parenthesis, and finally followed by optional explanatory text. +//! +//! A function name may be followed by a `?' and a number. The number is used +//! by auto-completion to display a registered QPixmap with the function name. +//! +//! All function names are used by auto-completion, but only those that include +//! function parameters are used in call tips. +//! +//! QScintilla only deals with prepared API information and not the raw +//! information described above. This is done so that large APIs can be +//! handled while still being responsive to user input. The conversion of raw +//! information to prepared information is time consuming (think tens of +//! seconds) and implemented in a separate thread. Prepared information can +//! be quickly saved to and loaded from files. Such files are portable between +//! different architectures. +//! +//! QScintilla based applications that want to support large APIs would +//! normally provide the user with the ability to specify a set of, possibly +//! project specific, raw API files and convert them to prepared files that are +//! loaded quickly when the application is invoked. +class QSCINTILLA_EXPORT QsciAPIs : public QsciAbstractAPIs +{ + Q_OBJECT + +public: + //! Constructs a QsciAPIs instance attached to lexer \a lexer. \a lexer + //! becomes the instance's parent object although the instance can also be + //! subsequently attached to other lexers. + QsciAPIs(QsciLexer *lexer); + + //! Destroy the QsciAPIs instance. + virtual ~QsciAPIs(); + + //! Add the single raw API entry \a entry to the current set. + //! + //! \sa clear(), load(), remove() + void add(const QString &entry); + + //! Deletes all raw API information. + //! + //! \sa add(), load(), remove() + void clear(); + + //! Load the API information from the file named \a fname, adding it to the + //! current set. Returns true if successful, otherwise false. + bool load(const QString &fname); + + //! Remove the single raw API entry \a entry from the current set. + //! + //! \sa add(), clear(), load() + void remove(const QString &entry); + + //! Convert the current raw API information to prepared API information. + //! This is implemented by a separate thread. + //! + //! \sa cancelPreparation() + void prepare(); + + //! Cancel the conversion of the current raw API information to prepared + //! API information. + //! + //! \sa prepare() + void cancelPreparation(); + + //! Return the default name of the prepared API information file. It is + //! based on the name of the associated lexer and in the directory defined + //! by the QSCIDIR environment variable. If the environment variable isn't + //! set then $HOME/.qsci is used. + QString defaultPreparedName() const; + + //! Check to see is a prepared API information file named \a fname exists. + //! If \a fname is empty then the value returned by defaultPreparedName() + //! is used. Returns true if successful, otherwise false. + //! + //! \sa defaultPreparedName() + bool isPrepared(const QString &fname = QString()) const; + + //! Load the prepared API information from the file named \a fname. If + //! \a fname is empty then a name is constructed based on the name of the + //! associated lexer and saved in the directory defined by the QSCIDIR + //! environment variable. If the environment variable isn't set then + //! $HOME/.qsci is used. Returns true if successful, otherwise false. + bool loadPrepared(const QString &fname = QString()); + + //! Save the prepared API information to the file named \a fname. If + //! \a fname is empty then a name is constructed based on the name of the + //! associated lexer and saved in the directory defined by the QSCIDIR + //! environment variable. If the environment variable isn't set then + //! $HOME/.qsci is used. Returns true if successful, otherwise false. + bool savePrepared(const QString &fname = QString()) const; + + //! \reimp + virtual void updateAutoCompletionList(const QStringList &context, + QStringList &list); + + //! \reimp + virtual void autoCompletionSelected(const QString &sel); + + //! \reimp + virtual QStringList callTips(const QStringList &context, int commas, + QsciScintilla::CallTipsStyle style, + QList &shifts); + + //! \internal Reimplemented to receive termination events from the worker + //! thread. + virtual bool event(QEvent *e); + + //! Return a list of the installed raw API file names for the associated + //! lexer. + QStringList installedAPIFiles() const; + +signals: + //! This signal is emitted when the conversion of raw API information to + //! prepared API information has been cancelled. + //! + //! \sa apiPreparationFinished(), apiPreparationStarted() + void apiPreparationCancelled(); + + //! This signal is emitted when the conversion of raw API information to + //! prepared API information starts and can be used to give some visual + //! feedback to the user. + //! + //! \sa apiPreparationCancelled(), apiPreparationFinished() + void apiPreparationStarted(); + + //! This signal is emitted when the conversion of raw API information to + //! prepared API information has finished. + //! + //! \sa apiPreparationCancelled(), apiPreparationStarted() + void apiPreparationFinished(); + +private: + friend class QsciAPIsPrepared; + friend class QsciAPIsWorker; + + // This indexes a word in a set of raw APIs. The first part indexes the + // entry in the set, the second part indexes the word within the entry. + typedef QPair WordIndex; + + // This is a list of word indexes. + typedef QList WordIndexList; + + QsciAPIsWorker *worker; + QStringList old_context; + QStringList::const_iterator origin; + int origin_len; + QString unambiguous_context; + QStringList apis; + QsciAPIsPrepared *prep; + + static bool enoughCommas(const QString &s, int commas); + + QStringList positionOrigin(const QStringList &context, QString &path); + bool originStartsWith(const QString &path, const QString &wsep); + const WordIndexList *wordIndexOf(const QString &word) const; + void lastCompleteWord(const QString &word, QStringList &with_context, + bool &unambig); + void lastPartialWord(const QString &word, QStringList &with_context, + bool &unambig); + void addAPIEntries(const WordIndexList &wl, bool complete, + QStringList &with_context, bool &unambig); + QString prepName(const QString &fname, bool mkpath = false) const; + void deleteWorker(); + + QsciAPIs(const QsciAPIs &); + QsciAPIs &operator=(const QsciAPIs &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscicommand.cpp b/harbour/contrib/hbide/qscintilla/qt/qscicommand.cpp new file mode 100644 index 0000000000..e74e608341 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscicommand.cpp @@ -0,0 +1,208 @@ +// This module implements the QsciCommand class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscicommand.h" + +#include +#include + +#include "qsciscintilla.h" +#include "qsciscintillabase.h" + + +static int convert(int key); + + +// The ctor. +QsciCommand::QsciCommand(QsciScintilla *qs, int msg, int key, int altkey, + const char *desc) + : qsCmd(qs), msgCmd(msg), qkey(key), qaltkey(altkey), descCmd(desc) +{ + scikey = convert(qkey); + + if (scikey) + qsCmd->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, scikey, + msgCmd); + + scialtkey = convert(qaltkey); + + if (scialtkey) + qsCmd->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, scialtkey, + msgCmd); +} + + +// Bind a key to a command. +void QsciCommand::setKey(int key) +{ + bindKey(key,qkey,scikey); +} + + +// Bind an alternate key to a command. +void QsciCommand::setAlternateKey(int altkey) +{ + bindKey(altkey,qaltkey,scialtkey); +} + + +// Do the hard work of binding a key. +void QsciCommand::bindKey(int key,int &qk,int &scik) +{ + int new_scikey; + + // Ignore if it is invalid, allowing for the fact that we might be + // unbinding it. + if (key) + { + new_scikey = convert(key); + + if (!new_scikey) + return; + } + else + new_scikey = 0; + + if (scik) + qsCmd->SendScintilla(QsciScintillaBase::SCI_CLEARCMDKEY, scik); + + qk = key; + scik = new_scikey; + + if (scik) + qsCmd->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, scik, msgCmd); +} + + +// See if a key is valid. +bool QsciCommand::validKey(int key) +{ + return convert(key); +} + + +// Convert a Qt character to the Scintilla equivalent. Return zero if it is +// invalid. +static int convert(int key) +{ + // Convert the modifiers. + int sci_mod = 0; + + if (key & Qt::SHIFT) + sci_mod |= QsciScintillaBase::SCMOD_SHIFT; + + if (key & Qt::CTRL) + sci_mod |= QsciScintillaBase::SCMOD_CTRL; + + if (key & Qt::ALT) + sci_mod |= QsciScintillaBase::SCMOD_ALT; + + key &= ~Qt::MODIFIER_MASK; + + // Convert the key. + int sci_key; + + if (key > 0x7f) + switch (key) + { + case Qt::Key_Down: + sci_key = QsciScintillaBase::SCK_DOWN; + break; + + case Qt::Key_Up: + sci_key = QsciScintillaBase::SCK_UP; + break; + + case Qt::Key_Left: + sci_key = QsciScintillaBase::SCK_LEFT; + break; + + case Qt::Key_Right: + sci_key = QsciScintillaBase::SCK_RIGHT; + break; + + case Qt::Key_Home: + sci_key = QsciScintillaBase::SCK_HOME; + break; + + case Qt::Key_End: + sci_key = QsciScintillaBase::SCK_END; + break; + + case Qt::Key_PageUp: + sci_key = QsciScintillaBase::SCK_PRIOR; + break; + + case Qt::Key_PageDown: + sci_key = QsciScintillaBase::SCK_NEXT; + break; + + case Qt::Key_Delete: + sci_key = QsciScintillaBase::SCK_DELETE; + break; + + case Qt::Key_Insert: + sci_key = QsciScintillaBase::SCK_INSERT; + break; + + case Qt::Key_Escape: + sci_key = QsciScintillaBase::SCK_ESCAPE; + break; + + case Qt::Key_Backspace: + sci_key = QsciScintillaBase::SCK_BACK; + break; + + case Qt::Key_Tab: + sci_key = QsciScintillaBase::SCK_TAB; + break; + + case Qt::Key_Return: + sci_key = QsciScintillaBase::SCK_RETURN; + break; + + default: + sci_key = 0; + } + else + sci_key = key; + + if (sci_key) + sci_key |= (sci_mod << 16); + + return sci_key; +} + + +// Return the translated user friendly description. +QString QsciCommand::description() const +{ + return qApp->translate("QsciCommand", descCmd); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscicommand.h b/harbour/contrib/hbide/qscintilla/qt/qscicommand.h new file mode 100644 index 0000000000..f1fb5c7fe5 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscicommand.h @@ -0,0 +1,112 @@ +// This defines the interface to the QsciCommand class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCICOMMAND_H +#define QSCICOMMAND_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + +#include + + +class QsciScintilla; + + +//! \brief The QsciCommand class represents an internal editor command that may +//! have one or two keys bound to it. +//! +//! Methods are provided to change the keys bound to the command and to remove +//! a key binding. Each command has a user friendly description of the command +//! for use in key mapping dialogs. +class QSCINTILLA_EXPORT QsciCommand +{ +public: + //! Binds the key \a key to the command. If \a key is 0 then the key + //! binding is removed. If \a key is invalid then the key binding is + //! unchanged. Valid keys are any visible or control character or any + //! of \c Key_Down, \c Key_Up, \c Key_Left, \c Key_Right, \c Key_Home, + //! \c Key_End, \c Key_PageUp, \c Key_PageDown, \c Key_Delete, + //! \c Key_Insert, \c Key_Escape, \c Key_Backspace, \c Key_Tab and + //! \c Key_Return. Keys may be modified with any combination of \c SHIFT, + //! \c CTRL and \c ALT. + //! + //! \sa key(), setAlternateKey(), validKey() + void setKey(int key); + + //! Binds the alternate key \a altkey to the command. If \a key is 0 + //! then the alternate key binding is removed. + //! + //! \sa alternateKey(), setKey(), validKey() + void setAlternateKey(int altkey); + + //! The key that is currently bound to the command is returned. + //! + //! \sa setKey(), alternateKey() + int key() const {return qkey;} + + //! The alternate key that is currently bound to the command is + //! returned. + //! + //! \sa setAlternateKey(), key() + int alternateKey() const {return qaltkey;} + + //! If the key \a key is valid then true is returned. + static bool validKey(int key); + + //! The user friendly description of the command is returned. + QString description() const; + +private: + friend class QsciCommandSet; + + QsciCommand(QsciScintilla *qs, int msg, int key, int altkey, + const char *desc); + + int msgId() const {return msgCmd;} + void bindKey(int key,int &qk,int &scik); + + QsciScintilla *qsCmd; + int msgCmd; + int qkey, scikey, qaltkey, scialtkey; + const char *descCmd; + + QsciCommand(const QsciCommand &); + QsciCommand &operator=(const QsciCommand &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscicommandset.cpp b/harbour/contrib/hbide/qscintilla/qt/qscicommandset.cpp new file mode 100644 index 0000000000..430866afff --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscicommandset.cpp @@ -0,0 +1,676 @@ +// This module implements the QsciCommandSet class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscicommandset.h" + +#include + +#include "qsciscintilla.h" +#include "qsciscintillabase.h" + + +// The ctor. +QsciCommandSet::QsciCommandSet(QsciScintilla *qs) : qsci(qs) +{ + struct sci_cmd { + int msg; + int key; + int altkey; + const char *desc; + }; + + // This is based on the default table in src/KeyMap.cxx. + static struct sci_cmd cmd_table[] = { + { + QsciScintillaBase::SCI_LINEDOWN, + Qt::Key_Down, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move down one line") + }, + { + QsciScintillaBase::SCI_LINEDOWNEXTEND, + Qt::Key_Down | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection down one line") + }, + { + QsciScintillaBase::SCI_LINESCROLLDOWN, + Qt::Key_Down | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Scroll view down one line") + }, + { + QsciScintillaBase::SCI_LINEDOWNRECTEXTEND, + Qt::Key_Down | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection down one line") + }, + { + QsciScintillaBase::SCI_LINEUP, + Qt::Key_Up, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move up one line") + }, + { + QsciScintillaBase::SCI_LINEUPEXTEND, + Qt::Key_Up | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection up one line") + }, + { + QsciScintillaBase::SCI_LINESCROLLUP, + Qt::Key_Up | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Scroll view up one line") + }, + { + QsciScintillaBase::SCI_LINEUPRECTEXTEND, + Qt::Key_Up | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection up one line") + }, + { + QsciScintillaBase::SCI_PARAUP, + Qt::Key_BracketLeft | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move up one paragraph") + }, + { + QsciScintillaBase::SCI_PARAUPEXTEND, + Qt::Key_BracketLeft | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection up one paragraph") + }, + { + QsciScintillaBase::SCI_PARADOWN, + Qt::Key_BracketRight | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move down one paragraph") + }, + { + QsciScintillaBase::SCI_PARADOWNEXTEND, + Qt::Key_BracketRight | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection down one paragraph") + }, + { + QsciScintillaBase::SCI_CHARLEFT, + Qt::Key_Left, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move left one character") + }, + { + QsciScintillaBase::SCI_CHARLEFTEXTEND, + Qt::Key_Left | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection left one character") + }, + { + QsciScintillaBase::SCI_WORDLEFT, + Qt::Key_Left | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move left one word") + }, + { + QsciScintillaBase::SCI_WORDLEFTEXTEND, + Qt::Key_Left | Qt::SHIFT | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection left one word") + }, + { + QsciScintillaBase::SCI_CHARLEFTRECTEXTEND, + Qt::Key_Left | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection left one character") + }, + { + QsciScintillaBase::SCI_CHARRIGHT, + Qt::Key_Right, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move right one character") + }, + { + QsciScintillaBase::SCI_CHARRIGHTEXTEND, + Qt::Key_Right | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection right one character") + }, + { + QsciScintillaBase::SCI_WORDRIGHT, + Qt::Key_Right | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move right one word") + }, + { + QsciScintillaBase::SCI_WORDRIGHTEXTEND, + Qt::Key_Right | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection right one word") + }, + { + QsciScintillaBase::SCI_CHARRIGHTRECTEXTEND, + Qt::Key_Right | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection right one character") + }, + { + QsciScintillaBase::SCI_WORDPARTLEFT, + Qt::Key_Slash | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move left one word part") + }, + { + QsciScintillaBase::SCI_WORDPARTLEFTEXTEND, + Qt::Key_Slash | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection left one word part") + }, + { + QsciScintillaBase::SCI_WORDPARTRIGHT, + Qt::Key_Backslash | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move right one word part") + }, + { + QsciScintillaBase::SCI_WORDPARTRIGHTEXTEND, + Qt::Key_Backslash | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection right one word part") + }, + { + QsciScintillaBase::SCI_VCHOME, + Qt::Key_Home, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move to first visible character in line") + }, + { + QsciScintillaBase::SCI_VCHOMEEXTEND, + Qt::Key_Home | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection to first visible character in line") + }, + { + QsciScintillaBase::SCI_DOCUMENTSTART, + Qt::Key_Home | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move to start of text") + }, + { + QsciScintillaBase::SCI_DOCUMENTSTARTEXTEND, + Qt::Key_Home | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection to start of text") + }, + { + QsciScintillaBase::SCI_HOMEDISPLAY, + Qt::Key_Home | Qt::ALT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move to start of displayed line") + }, + { + QsciScintillaBase::SCI_HOMEDISPLAYEXTEND, + 0, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection to start of line") + }, + { + QsciScintillaBase::SCI_VCHOMERECTEXTEND, + Qt::Key_Home | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection to first visible character in line") + }, + { + QsciScintillaBase::SCI_LINEEND, + Qt::Key_End, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move to end of line") + }, + { + QsciScintillaBase::SCI_LINEENDEXTEND, + Qt::Key_End | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection to end of line") + }, + { + QsciScintillaBase::SCI_DOCUMENTEND, + Qt::Key_End | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move to end of text") + }, + { + QsciScintillaBase::SCI_DOCUMENTENDEXTEND, + Qt::Key_End | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection to end of text") + }, + { + QsciScintillaBase::SCI_LINEENDDISPLAY, + Qt::Key_End | Qt::ALT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move to end of displayed line") + }, + { + QsciScintillaBase::SCI_LINEENDDISPLAYEXTEND, + 0, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection to end of displayed line") + }, + { + QsciScintillaBase::SCI_LINEENDRECTEXTEND, + Qt::Key_End | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection to end of line") + }, + { + QsciScintillaBase::SCI_PAGEUP, + Qt::Key_PageUp, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move up one page") + }, + { + QsciScintillaBase::SCI_PAGEUPEXTEND, + Qt::Key_PageUp | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection up one page") + }, + { + QsciScintillaBase::SCI_PAGEUPRECTEXTEND, + Qt::Key_PageUp | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection up one page") + }, + { + QsciScintillaBase::SCI_PAGEDOWN, + Qt::Key_PageDown, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move down one page") + }, + { + QsciScintillaBase::SCI_PAGEDOWNEXTEND, + Qt::Key_PageDown | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend selection down one page") + }, + { + QsciScintillaBase::SCI_PAGEDOWNRECTEXTEND, + Qt::Key_PageDown | Qt::ALT | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Extend rectangular selection down one page") + }, + { + QsciScintillaBase::SCI_CLEAR, + Qt::Key_Delete, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete current character") + }, + { + QsciScintillaBase::SCI_CUT, + Qt::Key_X | Qt::CTRL, + Qt::Key_Delete | Qt::SHIFT, + QT_TRANSLATE_NOOP("QsciCommand", + "Cut selection") + }, + { + QsciScintillaBase::SCI_DELWORDRIGHT, + Qt::Key_Delete | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete word to right") + }, + { + QsciScintillaBase::SCI_DELLINERIGHT, + Qt::Key_Delete | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete line to right") + }, + { + QsciScintillaBase::SCI_EDITTOGGLEOVERTYPE, + Qt::Key_Insert, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Toggle insert/overtype") + }, + { + QsciScintillaBase::SCI_PASTE, + Qt::Key_V | Qt::CTRL, + Qt::Key_Insert | Qt::SHIFT, + QT_TRANSLATE_NOOP("QsciCommand", + "Paste") + }, + { + QsciScintillaBase::SCI_COPY, + Qt::Key_C | Qt::CTRL, + Qt::Key_Insert | Qt::CTRL, + QT_TRANSLATE_NOOP("QsciCommand", + "Copy selection") + }, + { + QsciScintillaBase::SCI_CANCEL, + Qt::Key_Escape, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Cancel") + }, + { + QsciScintillaBase::SCI_DELETEBACK, + Qt::Key_Backspace, + Qt::Key_Backspace | Qt::SHIFT, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete previous character") + }, + { + QsciScintillaBase::SCI_DELWORDLEFT, + Qt::Key_Backspace | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete word to left") + }, + { + QsciScintillaBase::SCI_UNDO, + Qt::Key_Z | Qt::CTRL, + Qt::Key_Backspace | Qt::ALT, + QT_TRANSLATE_NOOP("QsciCommand", + "Undo the last command") + }, + { + QsciScintillaBase::SCI_DELLINELEFT, + Qt::Key_Backspace | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete line to left") + }, + { + QsciScintillaBase::SCI_REDO, + Qt::Key_Y | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Redo last command") + }, + { + QsciScintillaBase::SCI_SELECTALL, + Qt::Key_A | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Select all text") + }, + { + QsciScintillaBase::SCI_TAB, + Qt::Key_Tab, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Indent one level") + }, + { + QsciScintillaBase::SCI_BACKTAB, + Qt::Key_Tab | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Move back one indentation level") + }, + { + QsciScintillaBase::SCI_NEWLINE, + Qt::Key_Return, + Qt::Key_Return | Qt::SHIFT, + QT_TRANSLATE_NOOP("QsciCommand", + "Insert new line") + }, + { + QsciScintillaBase::SCI_ZOOMIN, + Qt::Key_Plus | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Zoom in") + }, + { + QsciScintillaBase::SCI_ZOOMOUT, + Qt::Key_Minus | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Zoom out") + }, + { + QsciScintillaBase::SCI_SETZOOM, + 0, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Set zoom") + }, + { + QsciScintillaBase::SCI_FORMFEED, + 0, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Formfeed") + }, + { + QsciScintillaBase::SCI_LINECUT, + Qt::Key_L | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Cut current line") + }, + { + QsciScintillaBase::SCI_LINEDELETE, + Qt::Key_L | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete current line") + }, + { + QsciScintillaBase::SCI_LINECOPY, + Qt::Key_T | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Copy current line") + }, + { + QsciScintillaBase::SCI_LINETRANSPOSE, + Qt::Key_T | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Swap current and previous lines") + }, + { + QsciScintillaBase::SCI_SELECTIONDUPLICATE, + Qt::Key_D | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Duplicate selection") + }, + { + QsciScintillaBase::SCI_LOWERCASE, + Qt::Key_U | Qt::CTRL, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Convert selection to lower case") + }, + { + QsciScintillaBase::SCI_UPPERCASE, + Qt::Key_U | Qt::CTRL | Qt::SHIFT, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Convert selection to upper case") + }, + { + QsciScintillaBase::SCI_DELETEBACKNOTLINE, + 0, + 0, + QT_TRANSLATE_NOOP("QsciCommand", + "Delete previous character if not at line start") + }, + }; + + // Clear the default map. + qsci->SendScintilla(QsciScintillaBase::SCI_CLEARALLCMDKEYS); + + // By default control characters don't do anything (rather than insert the + // control character into the text). + for (int k = 'A'; k <= 'Z'; ++k) + qsci->SendScintilla(QsciScintillaBase::SCI_ASSIGNCMDKEY, + k + (QsciScintillaBase::SCMOD_CTRL << 16), + QsciScintillaBase::SCI_NULL); + + for (int i = 0; i < sizeof (cmd_table) / sizeof (cmd_table[0]); ++i) + cmds.append(new QsciCommand(qsci, cmd_table[i].msg, cmd_table[i].key, + cmd_table[i].altkey, cmd_table[i].desc)); +} + + +// The dtor. +QsciCommandSet::~QsciCommandSet() +{ + for (int i = 0; i < cmds.count(); ++i) + delete cmds.at(i); +} + + +// Read the command set from settings. +bool QsciCommandSet::readSettings(QSettings &qs, const char *prefix) +{ + bool rc = true; + QString skey; + + for (int i = 0; i < cmds.count(); ++i) + { + QsciCommand *cmd = cmds.at(i); + + skey.sprintf("%s/keymap/c%d/", prefix, cmd->msgId()); + + int key; + bool ok; + + // Read the key. + ok = qs.contains(skey + "key"); + key = qs.value(skey + "key", 0).toInt(); + + if (ok) + cmd->setKey(key); + else + rc = false; + + // Read the alternate key. + ok = qs.contains(skey + "alt"); + key = qs.value(skey + "alt", 0).toInt(); + + if (ok) + cmd->setAlternateKey(key); + else + rc = false; + } + + return rc; +} + + +// Write the command set to settings. +bool QsciCommandSet::writeSettings(QSettings &qs, const char *prefix) +{ + bool rc = true; + QString skey; + + for (int i = 0; i < cmds.count(); ++i) + { + QsciCommand *cmd = cmds.at(i); + + skey.sprintf("%s/keymap/c%d/", prefix, cmd->msgId()); + + // Write the key. + qs.setValue(skey + "key", cmd->key()); + + // Write the alternate key. + qs.setValue(skey + "alt", cmd->key()); + } + + return rc; +} + + +// Clear the key bindings. +void QsciCommandSet::clearKeys() +{ + for (int i = 0; i < cmds.count(); ++i) + cmds.at(i)->setKey(0); +} + + +// Clear the alternate key bindings. +void QsciCommandSet::clearAlternateKeys() +{ + for (int i = 0; i < cmds.count(); ++i) + cmds.at(i)->setAlternateKey(0); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscicommandset.h b/harbour/contrib/hbide/qscintilla/qt/qscicommandset.h new file mode 100644 index 0000000000..265eafbe8b --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscicommandset.h @@ -0,0 +1,98 @@ +// This defines the interface to the QsciCommandSet class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCICOMMANDSET_H +#define QSCICOMMANDSET_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + +#include + +#include +#include + + +class QSettings; +class QsciScintilla; + + +//! \brief The QsciCommandSet class represents the set of all internal editor +//! commands that may have keys bound. +//! +//! Methods are provided to access the individual commands and to read and +//! write the current bindings from and to settings files. +class QSCINTILLA_EXPORT QsciCommandSet +{ +public: + //! The key bindings for each command in the set are read from the + //! settings \a qs. \a prefix is prepended to the key of each entry. + //! true is returned if there was no error. + //! + //! \sa writeSettings() + bool readSettings(QSettings &qs, const char *prefix = "/Scintilla"); + + //! The key bindings for each command in the set are written to the + //! settings \a qs. \a prefix is prepended to the key of each entry. + //! true is returned if there was no error. + //! + //! \sa readSettings() + bool writeSettings(QSettings &qs, const char *prefix = "/Scintilla"); + + //! The commands in the set are returned as a list. + QList &commands() {return cmds;} + + //! The primary keys bindings for all commands are removed. + void clearKeys(); + + //! The alternate keys bindings for all commands are removed. + void clearAlternateKeys(); + +private: + friend class QsciScintilla; + + QsciCommandSet(QsciScintilla *qs); + ~QsciCommandSet(); + + QsciScintilla *qsci; + QList cmds; + + QsciCommandSet(const QsciCommandSet &); + QsciCommandSet &operator=(const QsciCommandSet &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscidocument.cpp b/harbour/contrib/hbide/qscintilla/qt/qscidocument.cpp new file mode 100644 index 0000000000..c257bd748f --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscidocument.cpp @@ -0,0 +1,156 @@ +// This module implements the QsciDocument class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscidocument.h" +#include "qsciscintillabase.h" + + +// This internal class encapsulates the underlying document and is shared by +// QsciDocument instances. +class QsciDocumentP +{ +public: + QsciDocumentP() : doc(0), nr_displays(0), nr_attaches(1), modified(false) {} + + void *doc; // The Scintilla document. + int nr_displays; // The number of displays. + int nr_attaches; // The number of attaches. + bool modified; // Set if not at a save point. +}; + + +// The ctor. +QsciDocument::QsciDocument() +{ + pdoc = new QsciDocumentP(); +} + + +// The dtor. +QsciDocument::~QsciDocument() +{ + detach(); +} + + +// The copy ctor. +QsciDocument::QsciDocument(const QsciDocument &that) +{ + attach(that); +} + + +// The assignment operator. +QsciDocument &QsciDocument::operator=(const QsciDocument &that) +{ + if (pdoc != that.pdoc) + { + detach(); + attach(that); + } + + return *this; +} + + +// Attach an existing document to this one. +void QsciDocument::attach(const QsciDocument &that) +{ + ++that.pdoc->nr_attaches; + pdoc = that.pdoc; +} + + +// Detach the underlying document. +void QsciDocument::detach() +{ + if (!pdoc) + return; + + if (--pdoc->nr_attaches == 0) + { + if (pdoc->doc && pdoc->nr_displays == 0) + { + QsciScintillaBase *qsb = QsciScintillaBase::pool(); + + // Release the explicit reference to the document. If the pool is + // empty then we just accept the memory leak. + if (qsb) + qsb->SendScintilla(QsciScintillaBase::SCI_RELEASEDOCUMENT, 0, + pdoc->doc); + } + + delete pdoc; + } + + pdoc = 0; +} + + +// Undisplay and detach the underlying document. +void QsciDocument::undisplay(QsciScintillaBase *qsb) +{ + if (--pdoc->nr_attaches == 0) + delete pdoc; + else if (--pdoc->nr_displays == 0) + { + // Create an explicit reference to the document to keep it alive. + qsb->SendScintilla(QsciScintillaBase::SCI_ADDREFDOCUMENT, 0, pdoc->doc); + } + + pdoc = 0; +} + + +// Display the underlying document. +void QsciDocument::display(QsciScintillaBase *qsb, const QsciDocument *from) +{ + void *ndoc = (from ? from->pdoc->doc : 0); + + qsb->SendScintilla(QsciScintillaBase::SCI_SETDOCPOINTER, 0, ndoc); + ndoc = qsb->SendScintillaPtrResult(QsciScintillaBase::SCI_GETDOCPOINTER); + + pdoc->doc = ndoc; + ++pdoc->nr_displays; +} + + +// Return the modified state of the document. +bool QsciDocument::isModified() const +{ + return pdoc->modified; +} + + +// Set the modified state of the document. +void QsciDocument::setModified(bool m) +{ + pdoc->modified = m; +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscidocument.h b/harbour/contrib/hbide/qscintilla/qt/qscidocument.h new file mode 100644 index 0000000000..bed1208312 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscidocument.h @@ -0,0 +1,79 @@ +// This defines the interface to the QsciDocument class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCIDOCUMENT_H +#define QSCIDOCUMENT_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + + +class QsciScintillaBase; +class QsciDocumentP; + + +//! \brief The QsciDocument class represents a document to be edited. +//! +//! It is an opaque class that can be attached to multiple instances of +//! QsciScintilla to create different simultaneous views of the same document. +//! QsciDocument uses implicit sharing so that copying class instances is a +//! cheap operation. +class QSCINTILLA_EXPORT QsciDocument +{ +public: + //! Create a new unattached document. + QsciDocument(); + virtual ~QsciDocument(); + + QsciDocument(const QsciDocument &); + QsciDocument &operator=(const QsciDocument &); + +private: + friend class QsciScintilla; + + void attach(const QsciDocument &that); + void detach(); + void display(QsciScintillaBase *qsb, const QsciDocument *from); + void undisplay(QsciScintillaBase *qsb); + + bool isModified() const; + void setModified(bool m); + + QsciDocumentP *pdoc; +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciglobal.h b/harbour/contrib/hbide/qscintilla/qt/qsciglobal.h new file mode 100644 index 0000000000..8f49dcf848 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciglobal.h @@ -0,0 +1,66 @@ +// This module defines various things common to all of the Scintilla Qt port. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCIGLOBAL_H +#define QSCIGLOBAL_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + + +#define QSCINTILLA_VERSION 0x020404 +#define QSCINTILLA_VERSION_STR "snapshot-2.4.4-63f1a7a1d8e2" + + +// Under Windows, define QSCINTILLA_MAKE_DLL to create a Scintilla DLL, or +// define QSCINTILLA_DLL to link against a Scintilla DLL, or define neither +// to either build or link against a static Scintilla library. +#if defined(Q_WS_WIN) + +#if defined(QSCINTILLA_DLL) +#define QSCINTILLA_EXPORT __declspec(dllimport) +#elif defined(QSCINTILLA_MAKE_DLL) +#define QSCINTILLA_EXPORT __declspec(dllexport) +#endif + +#endif + +#if !defined(QSCINTILLA_EXPORT) +#define QSCINTILLA_EXPORT +#endif + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscilexer.cpp b/harbour/contrib/hbide/qscintilla/qt/qscilexer.cpp new file mode 100644 index 0000000000..20aff1d334 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscilexer.cpp @@ -0,0 +1,680 @@ +// This module implements the QsciLexer class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscilexer.h" + +#include +#include +#include +#include + +#include "qsciapis.h" +#include "qsciscintilla.h" +#include "qsciscintillabase.h" + + +// The ctor. +QsciLexer::QsciLexer(QObject *parent) + : QObject(parent), + autoIndStyle(-1), apiSet(0), attached_editor(0) +{ +#if defined(Q_OS_WIN) + defFont = QFont("Verdana",10); +#else + defFont = QFont("Bitstream Vera Sans",9); +#endif + + // Set the default fore and background colours. + QPalette pal = QApplication::palette(); + defColor = pal.text().color(); + defPaper = pal.base().color(); + + // Putting this on the heap means we can keep the style getters const. + style_map = new StyleDataMap; + style_map->style_data_set = false; +} + + +// The dtor. +QsciLexer::~QsciLexer() +{ + delete style_map; +} + + +// Set the attached editor. +void QsciLexer::setEditor(QsciScintilla *editor) +{ + attached_editor = editor; + + if (attached_editor) + { + attached_editor->SendScintilla(QsciScintillaBase::SCI_SETSTYLEBITS, + styleBitsNeeded()); + } +} + + +// Return the lexer name. +const char *QsciLexer::lexer() const +{ + return 0; +} + + +// Return the lexer identifier. +int QsciLexer::lexerId() const +{ + return QsciScintillaBase::SCLEX_CONTAINER; +} + + +// Return the number of style bits needed by the lexer. +int QsciLexer::styleBitsNeeded() const +{ + if (!attached_editor) + return 5; + + return attached_editor->SendScintilla(QsciScintillaBase::SCI_GETSTYLEBITSNEEDED); +} + + +// Make sure the style defaults have been set. +void QsciLexer::setStyleDefaults() const +{ + if (!style_map->style_data_set) + { + for (int i = 0; i < 128; ++i) + if (!description(i).isEmpty()) + styleData(i); + + style_map->style_data_set = true; + } +} + + +// Return a reference to a style's data, setting up the defaults if needed. +QsciLexer::StyleData &QsciLexer::styleData(int style) const +{ + StyleData &sd = style_map->style_data[style]; + + // See if this is a new style by checking if the colour is valid. + if (!sd.color.isValid()) + { + sd.color = defaultColor(style); + sd.paper = defaultPaper(style); + sd.font = defaultFont(style); + sd.eol_fill = defaultEolFill(style); + } + + return sd; +} + + +// Set the APIs associated with the lexer. +void QsciLexer::setAPIs(QsciAbstractAPIs *apis) +{ + apiSet = apis; +} + + +// Return a pointer to the current APIs if there are any. +QsciAbstractAPIs *QsciLexer::apis() const +{ + return apiSet; +} + + +// Default implementation to return the set of fill up characters that can end +// auto-completion. +const char *QsciLexer::autoCompletionFillups() const +{ + return "("; +} + + +// Default implementation to return the view used for indentation guides. +int QsciLexer::indentationGuideView() const +{ + return QsciScintillaBase::SC_IV_LOOKBOTH; +} + + +// Default implementation to return the list of character sequences that can +// separate auto-completion words. +QStringList QsciLexer::autoCompletionWordSeparators() const +{ + return QStringList(); +} + + +// Default implementation to return the list of keywords that can start a +// block. +const char *QsciLexer::blockStartKeyword(int *) const +{ + return 0; +} + + +// Default implementation to return the list of characters that can start a +// block. +const char *QsciLexer::blockStart(int *) const +{ + return 0; +} + + +// Default implementation to return the list of characters that can end a +// block. +const char *QsciLexer::blockEnd(int *) const +{ + return 0; +} + + +// Default implementation to return the style used for braces. +int QsciLexer::braceStyle() const +{ + return -1; +} + + +// Default implementation to return the number of lines to look back when +// auto-indenting. +int QsciLexer::blockLookback() const +{ + return 20; +} + + +// Default implementation to return the case sensitivity of the language. +bool QsciLexer::caseSensitive() const +{ + return true; +} + + +// Default implementation to return the characters that make up a word. +const char *QsciLexer::wordCharacters() const +{ + return 0; +} + + +// Default implementation to return the style used for whitespace. +int QsciLexer::defaultStyle() const +{ + return 0; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexer::color(int style) const +{ + return styleData(style).color; +} + + +// Returns the background colour of the text for a style. +QColor QsciLexer::paper(int style) const +{ + return styleData(style).paper; +} + + +// Returns the font for a style. +QFont QsciLexer::font(int style) const +{ + return styleData(style).font; +} + + +// Returns the end-of-line fill for a style. +bool QsciLexer::eolFill(int style) const +{ + return styleData(style).eol_fill; +} + + +// Returns the set of keywords. +const char *QsciLexer::keywords(int) const +{ + return 0; +} + + +// Returns the default EOL fill for a style. +bool QsciLexer::defaultEolFill(int) const +{ + return false; +} + + +// Returns the default font for a style. +QFont QsciLexer::defaultFont(int) const +{ + return defaultFont(); +} + + +// Returns the default font. +QFont QsciLexer::defaultFont() const +{ + return defFont; +} + + +// Sets the default font. +void QsciLexer::setDefaultFont(const QFont &f) +{ + defFont = f; +} + + +// Returns the default text colour for a style. +QColor QsciLexer::defaultColor(int) const +{ + return defaultColor(); +} + + +// Returns the default text colour. +QColor QsciLexer::defaultColor() const +{ + return defColor; +} + + +// Sets the default text colour. +void QsciLexer::setDefaultColor(const QColor &c) +{ + defColor = c; +} + + +// Returns the default paper colour for a styles. +QColor QsciLexer::defaultPaper(int) const +{ + return defaultPaper(); +} + + +// Returns the default paper colour. +QColor QsciLexer::defaultPaper() const +{ + return defPaper; +} + + +// Sets the default paper colour. +void QsciLexer::setDefaultPaper(const QColor &c) +{ + defPaper = c; + + // Normally the default values are only intended to provide defaults when a + // lexer is first setup because once a style has been referenced then a + // copy of the default is made. However the default paper is a special + // case because there is no other way to set the background colour used + // where there is no text. Therefore we also actively set it. + setPaper(c, QsciScintillaBase::STYLE_DEFAULT); +} + + +// Read properties from the settings. +bool QsciLexer::readProperties(QSettings &,const QString &) +{ + return true; +} + + +// Refresh all properties. +void QsciLexer::refreshProperties() +{ +} + + +// Write properties to the settings. +bool QsciLexer::writeProperties(QSettings &,const QString &) const +{ + return true; +} + + +// Restore the user settings. +bool QsciLexer::readSettings(QSettings &qs,const char *prefix) +{ + bool ok, flag, rc = true; + int num; + QString key, full_key; + QStringList fdesc; + + setStyleDefaults(); + + // Read the styles. + for (int i = 0; i < 128; ++i) + { + // Ignore invalid styles. + if (description(i).isEmpty()) + continue; + + key.sprintf("%s/%s/style%d/",prefix,language(),i); + + // Read the foreground colour. + full_key = key + "color"; + + ok = qs.contains(full_key); + num = qs.value(full_key).toInt(); + + if (ok) + setColor(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff), i); + else + rc = false; + + // Read the end-of-line fill. + full_key = key + "eolfill"; + + ok = qs.contains(full_key); + flag = qs.value(full_key, false).toBool(); + + if (ok) + setEolFill(flag, i); + else + rc = false; + + // Read the font + full_key = key + "font"; + + ok = qs.contains(full_key); + fdesc = qs.value(full_key).toStringList(); + + if (ok && fdesc.count() == 5) + { + QFont f; + + f.setFamily(fdesc[0]); + f.setPointSize(fdesc[1].toInt()); + f.setBold(fdesc[2].toInt()); + f.setItalic(fdesc[3].toInt()); + f.setUnderline(fdesc[4].toInt()); + + setFont(f, i); + } + else + rc = false; + + // Read the background colour. + full_key = key + "paper"; + + ok = qs.contains(full_key); + num = qs.value(full_key).toInt(); + + if (ok) + setPaper(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff), i); + else + rc = false; + } + + // Read the properties. + key.sprintf("%s/%s/properties/",prefix,language()); + + if (!readProperties(qs,key)) + rc = false; + + refreshProperties(); + + // Read the rest. + key.sprintf("%s/%s/",prefix,language()); + + // Read the default foreground colour. + full_key = key + "defaultcolor"; + + ok = qs.contains(full_key); + num = qs.value(full_key).toInt(); + + if (ok) + setDefaultColor(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff)); + else + rc = false; + + // Read the default background colour. + full_key = key + "defaultpaper"; + + ok = qs.contains(full_key); + num = qs.value(full_key).toInt(); + + if (ok) + setDefaultPaper(QColor((num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff)); + else + rc = false; + + // Read the default font. + full_key = key + "defaultfont"; + + ok = qs.contains(full_key); + fdesc = qs.value(full_key).toStringList(); + + if (ok && fdesc.count() == 5) + { + QFont f; + + f.setFamily(fdesc[0]); + f.setPointSize(fdesc[1].toInt()); + f.setBold(fdesc[2].toInt()); + f.setItalic(fdesc[3].toInt()); + f.setUnderline(fdesc[4].toInt()); + + setDefaultFont(f); + } + else + rc = false; + + full_key = key + "autoindentstyle"; + + ok = qs.contains(full_key); + num = qs.value(full_key).toInt(); + + if (ok) + setAutoIndentStyle(num); + else + rc = false; + + return rc; +} + + +// Save the user settings. +bool QsciLexer::writeSettings(QSettings &qs,const char *prefix) const +{ + bool rc = true; + QString key, fmt("%1"); + int num; + QStringList fdesc; + + setStyleDefaults(); + + // Write the styles. + for (int i = 0; i < 128; ++i) + { + // Ignore invalid styles. + if (description(i).isEmpty()) + continue; + + QColor c; + + key.sprintf("%s/%s/style%d/",prefix,language(),i); + + // Write the foreground colour. + c = color(i); + num = (c.red() << 16) | (c.green() << 8) | c.blue(); + + qs.setValue(key + "color", num); + + // Write the end-of-line fill. + qs.setValue(key + "eolfill", eolFill(i)); + + // Write the font + QFont f = font(i); + + fdesc.clear(); + fdesc += f.family(); + fdesc += fmt.arg(f.pointSize()); + + // The casts are for Borland. + fdesc += fmt.arg((int)f.bold()); + fdesc += fmt.arg((int)f.italic()); + fdesc += fmt.arg((int)f.underline()); + + qs.setValue(key + "font", fdesc); + + // Write the background colour. + c = paper(i); + num = (c.red() << 16) | (c.green() << 8) | c.blue(); + + qs.setValue(key + "paper", num); + } + + // Write the properties. + key.sprintf("%s/%s/properties/",prefix,language()); + + if (!writeProperties(qs,key)) + rc = false; + + // Write the rest. + key.sprintf("%s/%s/",prefix,language()); + + // Write the default foreground colour. + num = (defColor.red() << 16) | (defColor.green() << 8) | defColor.blue(); + + qs.setValue(key + "defaultcolor", num); + + // Write the default background colour. + num = (defPaper.red() << 16) | (defPaper.green() << 8) | defPaper.blue(); + + qs.setValue(key + "defaultpaper", num); + + // Write the default font + fdesc.clear(); + fdesc += defFont.family(); + fdesc += fmt.arg(defFont.pointSize()); + + // The casts are for Borland. + fdesc += fmt.arg((int)defFont.bold()); + fdesc += fmt.arg((int)defFont.italic()); + fdesc += fmt.arg((int)defFont.underline()); + + qs.setValue(key + "defaultfont", fdesc); + + qs.setValue(key + "autoindentstyle", autoIndStyle); + + return rc; +} + + +// Return the auto-indentation style. +int QsciLexer::autoIndentStyle() +{ + // We can't do this in the ctor because we want the virtuals to work. + if (autoIndStyle < 0) + autoIndStyle = (blockStartKeyword() || blockStart() || blockEnd()) ? + 0 : QsciScintilla::AiMaintain; + + return autoIndStyle; +} + + +// Set the auto-indentation style. +void QsciLexer::setAutoIndentStyle(int autoindentstyle) +{ + autoIndStyle = autoindentstyle; +} + + +// Set the foreground colour for a style. +void QsciLexer::setColor(const QColor &c, int style) +{ + if (style >= 0) + { + styleData(style).color = c; + emit colorChanged(c, style); + } + else + for (int i = 0; i < 128; ++i) + if (!description(i).isEmpty()) + setColor(c, i); +} + + +// Set the end-of-line fill for a style. +void QsciLexer::setEolFill(bool eolfill, int style) +{ + if (style >= 0) + { + styleData(style).eol_fill = eolfill; + emit eolFillChanged(eolfill, style); + } + else + for (int i = 0; i < 128; ++i) + if (!description(i).isEmpty()) + setEolFill(eolfill, i); +} + + +// Set the font for a style. +void QsciLexer::setFont(const QFont &f, int style) +{ + if (style >= 0) + { + styleData(style).font = f; + emit fontChanged(f, style); + } + else + for (int i = 0; i < 128; ++i) + if (!description(i).isEmpty()) + setFont(f, i); +} + + +// Set the background colour for a style. +void QsciLexer::setPaper(const QColor &c, int style) +{ + if (style >= 0) + { + styleData(style).paper = c; + emit paperChanged(c, style); + } + else + { + for (int i = 0; i < 128; ++i) + if (!description(i).isEmpty()) + setPaper(c, i); + + emit paperChanged(c, QsciScintillaBase::STYLE_DEFAULT); + } +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscilexer.h b/harbour/contrib/hbide/qscintilla/qt/qscilexer.h new file mode 100644 index 0000000000..d0fc215f8e --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscilexer.h @@ -0,0 +1,365 @@ +// This defines the interface to the QsciLexer class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXER_H +#define QSCILEXER_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include +#include +#include +#include +#include + +#include + + +class QSettings; + +class QsciAbstractAPIs; +class QsciScintilla; + + +//! \brief The QsciLexer class is an abstract class used as a base for language +//! lexers. +//! +//! A lexer scans the text breaking it up into separate language objects, e.g. +//! keywords, strings, operators. The lexer then uses a different style to +//! draw each object. A style is identified by a style number and has a number +//! of attributes, including colour and font. A specific language lexer will +//! implement appropriate default styles which can be overriden by an +//! application by further sub-classing the specific language lexer. +//! +//! A lexer may provide one or more sets of words to be recognised as keywords. +//! Most lexers only provide one set, but some may support languages embedded +//! in other languages and provide several sets. +//! +//! QsciLexer provides convenience methods for saving and restoring user +//! preferences for fonts and colours. +//! +//! If you want to write a lexer for a new language then you can add it to the +//! underlying Scintilla code and implement a corresponding QsciLexer sub-class +//! to manage the different styles used. Alternatively you can implement a +//! sub-class of QsciLexerCustom. +class QSCINTILLA_EXPORT QsciLexer : public QObject +{ + Q_OBJECT + +public: + //! Construct a QsciLexer with parent \a parent. \a parent is typically + //! the QsciScintilla instance. + QsciLexer(QObject *parent = 0); + + //! Destroy the QSciLexer. + virtual ~QsciLexer(); + + //! Returns the name of the language. It must be re-implemented by a + //! sub-class. + virtual const char *language() const = 0; + + //! Returns the name of the lexer. If 0 is returned then the lexer's + //! numeric identifier is used. The default implementation returns 0. + //! + //! \sa lexerId() + virtual const char *lexer() const; + + //! Returns the identifier (i.e. a QsciScintillaBase::SCLEX_* value) of the + //! lexer. This is only used if lexer() returns 0. The default + //! implementation returns QsciScintillaBase::SCLEX_CONTAINER. + //! + //! \sa lexer() + virtual int lexerId() const; + + //! Returns the current API set or 0 if there isn't one. + //! + //! \sa setAPIs() + QsciAbstractAPIs *apis() const; + + //! \internal Returns the characters that can fill up auto-completion. + virtual const char *autoCompletionFillups() const; + + //! \internal Returns the list of character sequences that can separate + //! auto-completion words. The first in the list is assumed to be the + //! sequence used to separate words in the lexer's API files. + virtual QStringList autoCompletionWordSeparators() const; + + //! Returns the auto-indentation style. The default is 0 if the + //! language is block structured, or QsciScintilla::AiMaintain if not. + //! + //! \sa setAutoIndentStyle(), QsciScintilla::AiMaintain, + //! QsciScintilla::AiOpening, QsciScintilla::AiClosing + int autoIndentStyle(); + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the end of a block for + //! auto-indentation. The style is returned via \a style. + virtual const char *blockEnd(int *style = 0) const; + + //! \internal Returns the number of lines prior to the current one when + //! determining the scope of a block when auto-indenting. + virtual int blockLookback() const; + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the start of a block for + //! auto-indentation. The style is returned via \a style. + virtual const char *blockStart(int *style = 0) const; + + //! \internal Returns a space separated list of keywords in a + //! particular style that define the start of a block for + //! auto-indentation. The style is returned via \a style. + virtual const char *blockStartKeyword(int *style = 0) const; + + //! \internal Returns the style used for braces for brace matching. + virtual int braceStyle() const; + + //! \internal Returns true if the language is case sensitive. The default + //! is true. + virtual bool caseSensitive() const; + + //! Returns the foreground colour of the text for style number \a style. + //! The default colour is that returned by defaultColor(). + //! + //! \sa defaultColor(), paper() + virtual QColor color(int style) const; + + //! Returns the end-of-line for style number \a style. The default is + //! false. + virtual bool eolFill(int style) const; + + //! Returns the font for style number \a style. The default font is + //! that returned by defaultFont(). + //! + //! \sa defaultFont() + virtual QFont font(int style) const; + + //! \internal Returns the view used for indentation guides. + virtual int indentationGuideView() const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. 0 is returned if there + //! is no such set. + virtual const char *keywords(int set) const; + + //! \internal Returns the number of the style used for whitespace. The + //! default implementation returns 0 which is the convention adopted by + //! most lexers. + virtual int defaultStyle() const; + + //! Returns the descriptive name for style number \a style. If the + //! style is invalid for this language then an empty QString is returned. + //! This is intended to be used in user preference dialogs. + virtual QString description(int style) const = 0; + + //! Returns the background colour of the text for style number + //! \a style. + //! + //! \sa defaultPaper(), color() + virtual QColor paper(int style) const; + + //! Returns the default text colour. + //! + //! \sa setDefaultColor() + QColor defaultColor() const; + + //! Returns the default text colour for style number \a style. + virtual QColor defaultColor(int style) const; + + //! Returns the default end-of-line for style number \a style. The default + //! is false. + virtual bool defaultEolFill(int style) const; + + //! Returns the default font. + //! + //! \sa setDefaultFont() + QFont defaultFont() const; + + //! Returns the default font for style number \a style. + virtual QFont defaultFont(int style) const; + + //! Returns the default paper colour. + //! + //! \sa setDefaultPaper() + QColor defaultPaper() const; + + //! Returns the default paper colour for style number \a style. + virtual QColor defaultPaper(int style) const; + + //! Returns the QsciScintilla instance that the lexer is currently attached + //! to or 0 if it is unattached. + QsciScintilla *editor() const {return attached_editor;} + + //! The current set of APIs is set to \a apis. If \a apis is 0 then any + //! existing APIs for this lexer are removed. + //! + //! \sa apis() + void setAPIs(QsciAbstractAPIs *apis); + + //! The default text colour is set to \a c. + //! + //! \sa defaultColor(), color() + void setDefaultColor(const QColor &c); + + //! The default font is set to \a f. + //! + //! \sa defaultFont(), font() + void setDefaultFont(const QFont &f); + + //! The default paper colour is set to \a c. + //! + //! \sa defaultPaper(), paper() + void setDefaultPaper(const QColor &c); + + //! \internal Set the QsciScintilla instance that the lexer is attached to. + virtual void setEditor(QsciScintilla *editor); + + //! The colour, paper, font and end-of-line for each style number, and + //! all lexer specific properties are read from the settings \a qs. + //! \a prefix is prepended to the key of each entry. true is returned + //! if there was no error. + //! + //! \sa writeSettings(), QsciScintilla::setLexer() + bool readSettings(QSettings &qs,const char *prefix = "/Scintilla"); + + //! Causes all properties to be refreshed by emitting the + //! propertyChanged() signal as required. + virtual void refreshProperties(); + + //! Returns the number of style bits needed by the lexer. Normally this + //! should only be re-implemented by custom lexers. + virtual int styleBitsNeeded() const; + + //! \internal Returns the string of characters that comprise a word. + //! The default is 0 which implies the upper and lower case alphabetic + //! characters and underscore. + virtual const char *wordCharacters() const; + + //! The colour, paper, font and end-of-line for each style number, and + //! all lexer specific properties are written to the settings \a qs. + //! \a prefix is prepended to the key of each entry. true is returned + //! if there was no error. + //! + //! \sa readSettings() + bool writeSettings(QSettings &qs, + const char *prefix = "/Scintilla") const; + +public slots: + //! The auto-indentation style is set to \a autoindentstyle. + //! + //! \sa autoIndentStyle(), QsciScintilla::AiMaintain, + //! QsciScintilla::AiOpening, QsciScintilla::AiClosing + virtual void setAutoIndentStyle(int autoindentstyle); + + //! The foreground colour for style number \a style is set to \a c. If + //! \a style is -1 then the colour is set for all styles. + virtual void setColor(const QColor &c,int style = -1); + + //! The end-of-line fill for style number \a style is set to + //! \a eoffill. If \a style is -1 then the fill is set for all styles. + virtual void setEolFill(bool eoffill,int style = -1); + + //! The font for style number \a style is set to \a f. If \a style is + //! -1 then the font is set for all styles. + virtual void setFont(const QFont &f,int style = -1); + + //! The background colour for style number \a style is set to \a c. If + //! \a style is -1 then the colour is set for all styles. + virtual void setPaper(const QColor &c,int style = -1); + +signals: + //! This signal is emitted when the foreground colour of style number + //! \a style has changed. The new colour is \a c. + void colorChanged(const QColor &c,int style); + + //! This signal is emitted when the end-of-file fill of style number + //! \a style has changed. The new fill is \a eolfilled. + void eolFillChanged(bool eolfilled,int style); + + //! This signal is emitted when the font of style number \a style has + //! changed. The new font is \a f. + void fontChanged(const QFont &f,int style); + + //! This signal is emitted when the background colour of style number + //! \a style has changed. The new colour is \a c. + void paperChanged(const QColor &c,int style); + + //! This signal is emitted when the value of the lexer property \a prop + //! needs to be changed. The new value is \a val. + void propertyChanged(const char *prop, const char *val); + +protected: + //! The lexer's properties are read from the settings \a qs. \a prefix + //! (which has a trailing '/') should be used as a prefix to the key of + //! each setting. true is returned if there is no error. + //! + virtual bool readProperties(QSettings &qs,const QString &prefix); + + //! The lexer's properties are written to the settings \a qs. + //! \a prefix (which has a trailing '/') should be used as a prefix to + //! the key of each setting. true is returned if there is no error. + //! + virtual bool writeProperties(QSettings &qs,const QString &prefix) const; + +private: + struct StyleData { + QFont font; + QColor color; + QColor paper; + bool eol_fill; + }; + + struct StyleDataMap { + bool style_data_set; + QMap style_data; + }; + + StyleDataMap *style_map; + + int autoIndStyle; + QFont defFont; + QColor defColor; + QColor defPaper; + QsciAbstractAPIs *apiSet; + QsciScintilla *attached_editor; + + void setStyleDefaults() const; + StyleData &styleData(int style) const; + + QsciLexer(const QsciLexer &); + QsciLexer &operator=(const QsciLexer &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscilexercpp.cpp b/harbour/contrib/hbide/qscintilla/qt/qscilexercpp.cpp new file mode 100644 index 0000000000..6d5614d448 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscilexercpp.cpp @@ -0,0 +1,518 @@ +// This module implements the QsciLexerCPP class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscilexercpp.h" + +#include +#include +#include + + +// The ctor. +QsciLexerCPP::QsciLexerCPP(QObject *parent, bool caseInsensitiveKeywords) + : QsciLexer(parent), + fold_atelse(false), fold_comments(false), fold_compact(true), + fold_preproc(true), style_preproc(false), dollars(true), + nocase(caseInsensitiveKeywords) +{ +} + + +// The dtor. +QsciLexerCPP::~QsciLexerCPP() +{ +} + + +// Returns the language name. +const char *QsciLexerCPP::language() const +{ + return "C++"; +} + + +// Returns the lexer name. +const char *QsciLexerCPP::lexer() const +{ + return (nocase ? "cppnocase" : "cpp"); +} + + +// Return the set of character sequences that can separate auto-completion +// words. +QStringList QsciLexerCPP::autoCompletionWordSeparators() const +{ + QStringList wl; + + wl << "::" << "->" << "."; + + return wl; +} + + +// Return the list of keywords that can start a block. +const char *QsciLexerCPP::blockStartKeyword(int *style) const +{ + if (style) + *style = Keyword; + + return "case catch class default do else finally for if private " + "protected public struct try union while"; +} + + +// Return the list of characters that can start a block. +const char *QsciLexerCPP::blockStart(int *style) const +{ + if (style) + *style = Operator; + + return "{"; +} + + +// Return the list of characters that can end a block. +const char *QsciLexerCPP::blockEnd(int *style) const +{ + if (style) + *style = Operator; + + return "}"; +} + + +// Return the style used for braces. +int QsciLexerCPP::braceStyle() const +{ + return Operator; +} + + +// Return the string of characters that comprise a word. +const char *QsciLexerCPP::wordCharacters() const +{ + return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_#"; +} + + +// Returns the foreground colour of the text for a style. +QColor QsciLexerCPP::defaultColor(int style) const +{ + switch (style) + { + case Default: + return QColor(0x80,0x80,0x80); + + case Comment: + case CommentLine: + return QColor(0x00,0x7f,0x00); + + case CommentDoc: + case CommentLineDoc: + return QColor(0x3f,0x70,0x3f); + + case Number: + return QColor(0x00,0x7f,0x7f); + + case Keyword: + return QColor(0x00,0x00,0x7f); + + case DoubleQuotedString: + case SingleQuotedString: + return QColor(0x7f,0x00,0x7f); + + case PreProcessor: + return QColor(0x7f,0x7f,0x00); + + case Operator: + case UnclosedString: + return QColor(0x00,0x00,0x00); + + case Identifier: + break; + + case Regex: + return QColor(0x3f,0x7f,0x3f); + + case CommentDocKeyword: + return QColor(0x30,0x60,0xa0); + + case CommentDocKeywordError: + return QColor(0x80,0x40,0x20); + } + + return QsciLexer::defaultColor(style); +} + + +// Returns the end-of-line fill for a style. +bool QsciLexerCPP::defaultEolFill(int style) const +{ + if (style == UnclosedString) + return true; + + return QsciLexer::defaultEolFill(style); +} + + +// Returns the font of the text for a style. +QFont QsciLexerCPP::defaultFont(int style) const +{ + QFont f; + + switch (style) + { + case Comment: + case CommentLine: + case CommentDoc: + case CommentLineDoc: + case CommentDocKeyword: + case CommentDocKeywordError: +#if defined(Q_OS_WIN) + f = QFont("Comic Sans MS",9); +#else + f = QFont("Bitstream Vera Serif",9); +#endif + break; + + case Keyword: + case Operator: + f = QsciLexer::defaultFont(style); + f.setBold(true); + break; + + case DoubleQuotedString: + case SingleQuotedString: + case UnclosedString: +#if defined(Q_OS_WIN) + f = QFont("Courier New",10); +#else + f = QFont("Bitstream Vera Sans Mono",9); +#endif + break; + + default: + f = QsciLexer::defaultFont(style); + } + + return f; +} + + +// Returns the set of keywords. +const char *QsciLexerCPP::keywords(int set) const +{ + if (set == 1) + return + "and and_eq asm auto bitand bitor bool break case " + "catch char class compl const const_cast continue " + "default delete do double dynamic_cast else enum " + "explicit export extern false float for friend goto if " + "inline int long mutable namespace new not not_eq " + "operator or or_eq private protected public register " + "reinterpret_cast return short signed sizeof static " + "static_cast struct switch template this throw true " + "try typedef typeid typename union unsigned using " + "virtual void volatile wchar_t while xor xor_eq"; + + if (set == 3) + return + "a addindex addtogroup anchor arg attention author b " + "brief bug c class code date def defgroup deprecated " + "dontinclude e em endcode endhtmlonly endif " + "endlatexonly endlink endverbatim enum example " + "exception f$ f[ f] file fn hideinitializer " + "htmlinclude htmlonly if image include ingroup " + "internal invariant interface latexonly li line link " + "mainpage name namespace nosubgrouping note overload " + "p page par param post pre ref relates remarks return " + "retval sa section see showinitializer since skip " + "skipline struct subsection test throw todo typedef " + "union until var verbatim verbinclude version warning " + "weakgroup $ @ \\ & < > # { }"; + + return 0; +} + + +// Returns the user name of a style. +QString QsciLexerCPP::description(int style) const +{ + switch (style) + { + case Default: + return tr("Default"); + + case Comment: + return tr("C comment"); + + case CommentLine: + return tr("C++ comment"); + + case CommentDoc: + return tr("JavaDoc style C comment"); + + case Number: + return tr("Number"); + + case Keyword: + return tr("Keyword"); + + case DoubleQuotedString: + return tr("Double-quoted string"); + + case SingleQuotedString: + return tr("Single-quoted string"); + + case UUID: + return tr("IDL UUID"); + + case PreProcessor: + return tr("Pre-processor block"); + + case Operator: + return tr("Operator"); + + case Identifier: + return tr("Identifier"); + + case UnclosedString: + return tr("Unclosed string"); + + case CommentLineDoc: + return tr("JavaDoc style C++ comment"); + + case KeywordSet2: + return tr("Secondary keywords and identifiers"); + + case CommentDocKeyword: + return tr("JavaDoc keyword"); + + case CommentDocKeywordError: + return tr("JavaDoc keyword error"); + + case GlobalClass: + return tr("Global classes and typedefs"); + } + + return QString(); +} + + +// Returns the background colour of the text for a style. +QColor QsciLexerCPP::defaultPaper(int style) const +{ + if (style == UnclosedString) + return QColor(0xe0,0xc0,0xe0); + + return QsciLexer::defaultPaper(style); +} + + +// Refresh all properties. +void QsciLexerCPP::refreshProperties() +{ + setAtElseProp(); + setCommentProp(); + setCompactProp(); + setPreprocProp(); + setStylePreprocProp(); + setDollarsProp(); +} + + +// Read properties from the settings. +bool QsciLexerCPP::readProperties(QSettings &qs,const QString &prefix) +{ + int rc = true; + + fold_atelse = qs.value(prefix + "foldatelse", false).toBool(); + fold_comments = qs.value(prefix + "foldcomments", false).toBool(); + fold_compact = qs.value(prefix + "foldcompact", true).toBool(); + fold_preproc = qs.value(prefix + "foldpreprocessor", true).toBool(); + style_preproc = qs.value(prefix + "stylepreprocessor", false).toBool(); + dollars = qs.value(prefix + "dollars", true).toBool(); + + return rc; +} + + +// Write properties to the settings. +bool QsciLexerCPP::writeProperties(QSettings &qs,const QString &prefix) const +{ + int rc = true; + + qs.setValue(prefix + "foldatelse", fold_atelse); + qs.setValue(prefix + "foldcomments", fold_comments); + qs.setValue(prefix + "foldcompact", fold_compact); + qs.setValue(prefix + "foldpreprocessor", fold_preproc); + qs.setValue(prefix + "stylepreprocessor", style_preproc); + qs.setValue(prefix + "dollars", dollars); + + return rc; +} + + +// Return true if else can be folded. +bool QsciLexerCPP::foldAtElse() const +{ + return fold_atelse; +} + + +// Set if else can be folded. +void QsciLexerCPP::setFoldAtElse(bool fold) +{ + fold_atelse = fold; + + setAtElseProp(); +} + + +// Set the "fold.at.else" property. +void QsciLexerCPP::setAtElseProp() +{ + emit propertyChanged("fold.at.else",(fold_atelse ? "1" : "0")); +} + + +// Return true if comments can be folded. +bool QsciLexerCPP::foldComments() const +{ + return fold_comments; +} + + +// Set if comments can be folded. +void QsciLexerCPP::setFoldComments(bool fold) +{ + fold_comments = fold; + + setCommentProp(); +} + + +// Set the "fold.comment" property. +void QsciLexerCPP::setCommentProp() +{ + emit propertyChanged("fold.comment",(fold_comments ? "1" : "0")); +} + + +// Return true if folds are compact. +bool QsciLexerCPP::foldCompact() const +{ + return fold_compact; +} + + +// Set if folds are compact +void QsciLexerCPP::setFoldCompact(bool fold) +{ + fold_compact = fold; + + setCompactProp(); +} + + +// Set the "fold.compact" property. +void QsciLexerCPP::setCompactProp() +{ + emit propertyChanged("fold.compact",(fold_compact ? "1" : "0")); +} + + +// Return true if preprocessor blocks can be folded. +bool QsciLexerCPP::foldPreprocessor() const +{ + return fold_preproc; +} + + +// Set if preprocessor blocks can be folded. +void QsciLexerCPP::setFoldPreprocessor(bool fold) +{ + fold_preproc = fold; + + setPreprocProp(); +} + + +// Set the "fold.preprocessor" property. +void QsciLexerCPP::setPreprocProp() +{ + emit propertyChanged("fold.preprocessor",(fold_preproc ? "1" : "0")); +} + + +// Return true if preprocessor lines are styled. +bool QsciLexerCPP::stylePreprocessor() const +{ + return style_preproc; +} + + +// Set if preprocessor lines are styled. +void QsciLexerCPP::setStylePreprocessor(bool style) +{ + style_preproc = style; + + setStylePreprocProp(); +} + + +// Set the "styling.within.preprocessor" property. +void QsciLexerCPP::setStylePreprocProp() +{ + emit propertyChanged("styling.within.preprocessor",(style_preproc ? "1" : "0")); +} + + +// Return true if '$' characters are allowed. +bool QsciLexerCPP::dollarsAllowed() const +{ + return dollars; +} + + +// Set if '$' characters are allowed. +void QsciLexerCPP::setDollarsAllowed(bool allowed) +{ + dollars = allowed; + + setDollarsProp(); +} + + +// Set the "lexer.cpp.allow.dollars" property. +void QsciLexerCPP::setDollarsProp() +{ + emit propertyChanged("lexer.cpp.allow.dollars",(dollars ? "1" : "0")); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscilexercpp.h b/harbour/contrib/hbide/qscintilla/qt/qscilexercpp.h new file mode 100644 index 0000000000..3314adabaa --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscilexercpp.h @@ -0,0 +1,296 @@ +// This defines the interface to the QsciLexerCPP class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCILEXERCPP_H +#define QSCILEXERCPP_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + +#include +#include + + +//! \brief The QsciLexerCPP class encapsulates the Scintilla C++ +//! lexer. +class QSCINTILLA_EXPORT QsciLexerCPP : public QsciLexer +{ + Q_OBJECT + +public: + //! This enum defines the meanings of the different styles used by the + //! C++ lexer. + enum { + //! The default. + Default = 0, + + //! A C comment. + Comment = 1, + + //! A C++ comment line. + CommentLine = 2, + + //! A JavaDoc/Doxygen style C comment. + CommentDoc = 3, + + //! A number. + Number = 4, + + //! A keyword. + Keyword = 5, + + //! A double-quoted string. + DoubleQuotedString = 6, + + //! A single-quoted string. + SingleQuotedString = 7, + + //! An IDL UUID. + UUID = 8, + + //! A pre-processor block. + PreProcessor = 9, + + //! An operator. + Operator = 10, + + //! An identifier + Identifier = 11, + + //! The end of a line where a string is not closed. + UnclosedString = 12, + + //! A C# verbatim string. + VerbatimString = 13, + + //! A JavaScript regular expression. + Regex = 14, + + //! A JavaDoc/Doxygen style C++ comment line. + CommentLineDoc = 15, + + //! A keyword defined in keyword set number 2. The class must + //! be sub-classed and re-implement keywords() to make use of + //! this style. + KeywordSet2 = 16, + + //! A JavaDoc/Doxygen keyword. + CommentDocKeyword = 17, + + //! A JavaDoc/Doxygen keyword error. + CommentDocKeywordError = 18, + + //! A global class or typedef defined in keyword set number 4. + //! The class must be sub-classed and re-implement keywords() + //! to make use of this style. + GlobalClass = 19 + }; + + //! Construct a QsciLexerCPP with parent \a parent. \a parent is typically + //! the QsciScintilla instance. \a caseInsensitiveKeywords is true if the + //! lexer ignores the case of keywords. + QsciLexerCPP(QObject *parent = 0, bool caseInsensitiveKeywords = false); + + //! Destroys the QsciLexerCPP instance. + virtual ~QsciLexerCPP(); + + //! Returns the name of the language. + const char *language() const; + + //! Returns the name of the lexer. Some lexers support a number of + //! languages. + const char *lexer() const; + + //! \internal Returns the character sequences that can separate + //! auto-completion words. + QStringList autoCompletionWordSeparators() const; + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the end of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockEnd(int *style = 0) const; + + //! \internal Returns a space separated list of words or characters in + //! a particular style that define the start of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockStart(int *style = 0) const; + + //! \internal Returns a space separated list of keywords in a + //! particular style that define the start of a block for + //! auto-indentation. The styles is returned via \a style. + const char *blockStartKeyword(int *style = 0) const; + + //! \internal Returns the style used for braces for brace matching. + int braceStyle() const; + + //! \internal Returns the string of characters that comprise a word. + const char *wordCharacters() const; + + //! Returns the foreground colour of the text for style number \a style. + //! + //! \sa defaultPaper() + QColor defaultColor(int style) const; + + //! Returns the end-of-line fill for style number \a style. + bool defaultEolFill(int style) const; + + //! Returns the font for style number \a style. + QFont defaultFont(int style) const; + + //! Returns the background colour of the text for style number \a style. + //! + //! \sa defaultColor() + QColor defaultPaper(int style) const; + + //! Returns the set of keywords for the keyword set \a set recognised + //! by the lexer as a space separated string. + const char *keywords(int set) const; + + //! Returns the descriptive name for style number \a style. If the + //! style is invalid for this language then an empty QString is returned. + //! This is intended to be used in user preference dialogs. + QString description(int style) const; + + //! Causes all properties to be refreshed by emitting the + //! propertyChanged() signal as required. + void refreshProperties(); + + //! Returns true if "} else {" lines can be folded. + //! + //! \sa setFoldAtElse() + bool foldAtElse() const; + + //! Returns true if multi-line comment blocks can be folded. + //! + //! \sa setFoldComments() + bool foldComments() const; + + //! Returns true if trailing blank lines are included in a fold block. + //! + //! \sa setFoldCompact() + bool foldCompact() const; + + //! Returns true if preprocessor blocks can be folded. + //! + //! \sa setFoldPreprocessor() + bool foldPreprocessor() const; + + //! Returns true if preprocessor lines (after the preprocessor + //! directive) are styled. + //! + //! \sa setStylePreprocessor() + bool stylePreprocessor() const; + + //! If \a allowed is true then '$' characters are allowed in identifier + //! names. The default is true. + //! + //! \sa dollarsAllowed() + void setDollarsAllowed(bool allowed); + + //! Returns true if '$' characters are allowed in identifier names. + //! + //! \sa setDollarsAllowed() + bool dollarsAllowed() const; + +public slots: + //! If \a fold is true then "} else {" lines can be folded. The + //! default is false. + //! + //! \sa foldAtElse() + virtual void setFoldAtElse(bool fold); + + //! If \a fold is true then multi-line comment blocks can be folded. + //! The default is false. + //! + //! \sa foldComments() + virtual void setFoldComments(bool fold); + + //! If \a fold is true then trailing blank lines are included in a fold + //! block. The default is true. + //! + //! \sa foldCompact() + virtual void setFoldCompact(bool fold); + + //! If \a fold is true then preprocessor blocks can be folded. The + //! default is true. + //! + //! \sa foldPreprocessor() + virtual void setFoldPreprocessor(bool fold); + + //! If \a style is true then preprocessor lines (after the preprocessor + //! directive) are styled. The default is false. + //! + //! \sa stylePreprocessor() + virtual void setStylePreprocessor(bool style); + +protected: + //! The lexer's properties are read from the settings \a qs. \a prefix + //! (which has a trailing '/') should be used as a prefix to the key of + //! each setting. true is returned if there is no error. + //! + //! \sa writeProperties() + bool readProperties(QSettings &qs,const QString &prefix); + + //! The lexer's properties are written to the settings \a qs. + //! \a prefix (which has a trailing '/') should be used as a prefix to + //! the key of each setting. true is returned if there is no error. + //! + //! \sa readProperties() + bool writeProperties(QSettings &qs,const QString &prefix) const; + +private: + void setAtElseProp(); + void setCommentProp(); + void setCompactProp(); + void setPreprocProp(); + void setStylePreprocProp(); + void setDollarsProp(); + + bool fold_atelse; + bool fold_comments; + bool fold_compact; + bool fold_preproc; + bool style_preproc; + bool dollars; + + bool nocase; + + QsciLexerCPP(const QsciLexerCPP &); + QsciLexerCPP &operator=(const QsciLexerCPP &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscimacro.cpp b/harbour/contrib/hbide/qscintilla/qt/qscimacro.cpp new file mode 100644 index 0000000000..5ef048aac6 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscimacro.cpp @@ -0,0 +1,312 @@ +// This module implements the QsciMacro class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscimacro.h" + +#include + +#include "qsciscintilla.h" + + +static int fromHex(unsigned char ch); + + + +// The ctor. +QsciMacro::QsciMacro(QsciScintilla *parent) + : QObject(parent), qsci(parent) +{ +} + + +// The ctor that initialises the macro. +QsciMacro::QsciMacro(const QString &asc, QsciScintilla *parent) + : QObject(parent), qsci(parent) +{ + load(asc); +} + + +// The dtor. +QsciMacro::~QsciMacro() +{ +} + + +// Clear the contents of the macro. +void QsciMacro::clear() +{ + macro.clear(); +} + + +// Read a macro from a string. +bool QsciMacro::load(const QString &asc) +{ + bool ok = true; + + macro.clear(); + + QStringList fields = asc.split(' '); + + int f = 0; + + while (f < fields.size()) + { + Macro cmd; + unsigned len; + + // Extract the 3 fixed fields. + if (f + 3 > fields.size()) + { + ok = false; + break; + } + + cmd.msg = fields[f++].toUInt(&ok); + + if (!ok) + break; + + cmd.wParam = fields[f++].toULong(&ok); + + if (!ok) + break; + + len = fields[f++].toUInt(&ok); + + if (!ok) + break; + + // Extract any text. + if (len) + { + if (f + 1 > fields.size()) + { + ok = false; + break; + } + + cmd.text.resize(len - 1); + + QByteArray ba = fields[f++].toAscii(); + const char *sp = ba.data(); + + char *dp = cmd.text.data(); + + if (!sp) + { + ok = false; + break; + } + + while (len--) + { + unsigned char ch; + + ch = *sp++; + + if (ch == '"' || ch <= ' ' || ch >= 0x7f) + { + ok = false; + break; + } + + if (ch == '\\') + { + int b1, b2; + + if ((b1 = fromHex(*sp++)) < 0 || + (b2 = fromHex(*sp++)) < 0) + { + ok = false; + break; + } + + ch = (b1 << 4) + b2; + } + + *dp++ = ch; + } + + if (!ok) + break; + } + + macro.append(cmd); + } + + if (!ok) + macro.clear(); + + return ok; +} + + +// Write a macro to a string. +QString QsciMacro::save() const +{ + QString ms; + + QList::const_iterator it; + + for (it = macro.begin(); it != macro.end(); ++it) + { + if (!ms.isEmpty()) + ms += ' '; + + unsigned len = (*it).text.size(); + QString m; + + ms += m.sprintf("%u %lu %u", (*it).msg, (*it).wParam, len); + + if (len) + { + // In Qt v3, if the length is greater than zero then it also + // includes the '\0', so we need to make sure that Qt v4 writes the + // '\0'. (That the '\0' is written at all is probably a historical + // bug - using size() instead of length() - which we don't fix so + // as not to break old macros.) + ++len; + + ms += ' '; + + const char *cp = (*it).text.data(); + + while (len--) + { + unsigned char ch = *cp++; + + if (ch == '\\' || ch == '"' || ch <= ' ' || ch >= 0x7f) + { + QString buf; + + ms += buf.sprintf("\\%02x", ch); + } + else + ms += ch; + } + } + } + + return ms; +} + + +// Play the macro. +void QsciMacro::play() +{ + if (!qsci) + return; + + QList::const_iterator it; + + for (it = macro.begin(); it != macro.end(); ++it) + qsci->SendScintilla((*it).msg, (*it).wParam, (*it).text.data()); +} + + +// Start recording. +void QsciMacro::startRecording() +{ + if (!qsci) + return; + + macro.clear(); + + connect(qsci, SIGNAL(SCN_MACRORECORD(unsigned int, unsigned long, void *)), + SLOT(record(unsigned int, unsigned long, void *))); + + qsci->SendScintilla(QsciScintillaBase::SCI_STARTRECORD); +} + + +// End recording. +void QsciMacro::endRecording() +{ + if (!qsci) + return; + + qsci->SendScintilla(QsciScintillaBase::SCI_STOPRECORD); + qsci->disconnect(this); +} + + +// Record a command. +void QsciMacro::record(unsigned int msg, unsigned long wParam, void *lParam) +{ + Macro m; + + m.msg = msg; + m.wParam = wParam; + + // Determine commands which need special handling of the parameters. + switch (msg) + { + case QsciScintillaBase::SCI_ADDTEXT: + m.text = QByteArray(reinterpret_cast(lParam), wParam); + break; + + case QsciScintillaBase::SCI_REPLACESEL: + if (!macro.isEmpty() && macro.last().msg == QsciScintillaBase::SCI_REPLACESEL) + { + // This is the command used for ordinary user input so it's a + // significant space reduction to append it to the previous + // command. + + macro.last().text.append(reinterpret_cast(lParam)); + return; + } + + /* Drop through. */ + + case QsciScintillaBase::SCI_INSERTTEXT: + case QsciScintillaBase::SCI_APPENDTEXT: + case QsciScintillaBase::SCI_SEARCHNEXT: + case QsciScintillaBase::SCI_SEARCHPREV: + m.text.append(reinterpret_cast(lParam)); + break; + } + + macro.append(m); +} + + +// Return the given hex character as a binary. +static int fromHex(unsigned char ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + + return -1; +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscimacro.h b/harbour/contrib/hbide/qscintilla/qt/qscimacro.h new file mode 100644 index 0000000000..f891908f7e --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscimacro.h @@ -0,0 +1,117 @@ +// This defines the interface to the QsciMacro class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCIMACRO_H +#define QSCIMACRO_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include +#include + +#include + +#include + + +class QsciScintilla; + + +//! \brief The QsciMacro class represents a sequence of recordable editor +//! commands. +//! +//! Methods are provided to convert convert a macro to and from a textual +//! representation so that they can be easily written to and read from +//! permanent storage. +class QSCINTILLA_EXPORT QsciMacro : public QObject +{ + Q_OBJECT + +public: + //! Construct a QsciMacro with parent \a parent. + QsciMacro(QsciScintilla *parent); + + //! Construct a QsciMacro from the printable ASCII representation \a asc, + //! with parent \a parent. + QsciMacro(const QString &asc, QsciScintilla *parent); + + //! Destroy the QsciMacro instance. + virtual ~QsciMacro(); + + //! Clear the contents of the macro. + void clear(); + + //! Load the macro from the printable ASCII representation \a asc. Returns + //! true if there was no error. + //! + //! \sa save() + bool load(const QString &asc); + + //! Return a printable ASCII representation of the macro. It is guaranteed + //! that only printable ASCII characters are used and that double quote + //! characters will not be used. + //! + //! \sa load() + QString save() const; + +public slots: + //! Play the macro. + virtual void play(); + + //! Start recording user commands and add them to the macro. + virtual void startRecording(); + + //! Stop recording user commands. + virtual void endRecording(); + +private slots: + void record(unsigned int msg, unsigned long wParam, void *lParam); + +private: + struct Macro { + unsigned int msg; + unsigned long wParam; + QByteArray text; + }; + + QsciScintilla *qsci; + QList macro; + + QsciMacro(const QsciMacro &); + QsciMacro &operator=(const QsciMacro &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciprinter.cpp b/harbour/contrib/hbide/qscintilla/qt/qsciprinter.cpp new file mode 100644 index 0000000000..6fe9db99b1 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciprinter.cpp @@ -0,0 +1,194 @@ +// This module implements the QsciPrinter class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qsciprinter.h" + +#include +#include + +#include + +#include "qsciscintillabase.h" + + +// The ctor. +QsciPrinter::QsciPrinter(QPrinter::PrinterMode mode) + : QPrinter(mode), mag(0), wrap(QsciScintilla::WrapWord) +{ +} + + +// The dtor. +QsciPrinter::~QsciPrinter() +{ +} + + +// Format the page before the document text is drawn. +void QsciPrinter::formatPage(QPainter &, bool, QRect &, int) +{ +} + + +// Print a range of lines to a printer. +int QsciPrinter::printRange(QsciScintillaBase *qsb, int from, int to) +{ + // Sanity check. + if (!qsb) + return false; + + // Setup the printing area. + QRect def_area; + + def_area.setX(0); + def_area.setY(0); + + def_area.setWidth(width()); + def_area.setHeight(height()); + + // Get the page range. + int pgFrom, pgTo; + + pgFrom = fromPage(); + pgTo = toPage(); + + // Find the position range. + long startPos, endPos; + + endPos = qsb->SendScintilla(QsciScintillaBase::SCI_GETLENGTH); + + startPos = (from > 0 ? qsb -> SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,from) : 0); + + if (to >= 0) + { + long toPos = qsb -> SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE,to + 1); + + if (endPos > toPos) + endPos = toPos; + } + + if (startPos >= endPos) + return false; + + QPainter painter(this); + bool reverse = (pageOrder() == LastPageFirst); + bool needNewPage = false; + + qsb -> SendScintilla(QsciScintillaBase::SCI_SETPRINTMAGNIFICATION,mag); + qsb -> SendScintilla(QsciScintillaBase::SCI_SETPRINTWRAPMODE,wrap); + + for (int i = 1; i <= numCopies(); ++i) + { + // If we are printing in reverse page order then remember the start + // position of each page. + QStack pageStarts; + + int currPage = 1; + long pos = startPos; + + while (pos < endPos) + { + // See if we have finished the requested page range. + if (pgTo > 0 && pgTo < currPage) + break; + + // See if we are going to render this page, or just see how much + // would fit onto it. + bool render = false; + + if (pgFrom == 0 || pgFrom <= currPage) + { + if (reverse) + pageStarts.push(pos); + else + { + render = true; + + if (needNewPage) + { + if (!newPage()) + return false; + } + else + needNewPage = true; + } + } + + QRect area = def_area; + + formatPage(painter,render,area,currPage); + pos = qsb -> SendScintilla(QsciScintillaBase::SCI_FORMATRANGE,render,&painter,area,pos,endPos); + + ++currPage; + } + + // All done if we are printing in normal page order. + if (!reverse) + continue; + + // Now go through each page on the stack and really print it. + while (!pageStarts.isEmpty()) + { + --currPage; + + long ePos = pos; + pos = pageStarts.pop(); + + if (needNewPage) + { + if (!newPage()) + return false; + } + else + needNewPage = true; + + QRect area = def_area; + + formatPage(painter,true,area,currPage); + qsb->SendScintilla(QsciScintillaBase::SCI_FORMATRANGE,true,&painter,area,pos,ePos); + } + } + + return true; +} + + +// Set the print magnification in points. +void QsciPrinter::setMagnification(int magnification) +{ + mag = magnification; +} + + +// Set the line wrap mode. +void QsciPrinter::setWrapMode(QsciScintilla::WrapMode wmode) +{ + wrap = wmode; +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciprinter.h b/harbour/contrib/hbide/qscintilla/qt/qsciprinter.h new file mode 100644 index 0000000000..fd73934633 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciprinter.h @@ -0,0 +1,118 @@ +// This module defines interface to the QsciPrinter class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCIPRINTER_H +#define QSCIPRINTER_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + +#include +#include + + +class QRect; +class QPainter; +class QsciScintillaBase; + + +//! \brief The QsciPrinter class is a sub-class of the Qt QPrinter class that +//! is able to print the text of a Scintilla document. +//! +//! The class can be further sub-classed to alter to layout of the text, adding +//! headers and footers for example. +class QSCINTILLA_EXPORT QsciPrinter : public QPrinter +{ +public: + //! Constructs a printer paint device with mode \a mode. + QsciPrinter(PrinterMode mode = ScreenResolution); + + //! Destroys the QsciPrinter instance. + virtual ~QsciPrinter(); + + //! Format a page, by adding headers and footers for example, before the + //! document text is drawn on it. \a painter is the painter to be used to + //! add customised text and graphics. \a drawing is true if the page is + //! actually being drawn rather than being sized. \a painter drawing + //! methods must only be called when \a drawing is true. \a area is the + //! area of the page that will be used to draw the text. This should be + //! modified if it is necessary to reserve space for any customised text or + //! graphics. By default the area is relative to the printable area of the + //! page. Use QPrinter::setFullPage() because calling printRange() if you + //! want to try and print over the whole page. \a pagenr is the number of + //! the page. The first page is numbered 1. + virtual void formatPage(QPainter &painter, bool drawing, QRect &area, + int pagenr); + + //! Return the number of points to add to each font when printing. + //! + //! \sa setMagnification() + int magnification() const {return mag;} + + //! Sets the number of points to add to each font when printing to \a + //! magnification. + //! + //! \sa magnification() + virtual void setMagnification(int magnification); + + //! Print a range of lines from the Scintilla instance \a qsb. \a from is + //! the first line to print and a negative value signifies the first line + //! of text. \a to is the last line to print and a negative value + //! signifies the last line of text. true is returned if there was no + //! error. + virtual int printRange(QsciScintillaBase *qsb, int from = -1, int to = -1); + + //! Return the line wrap mode used when printing. The default is + //! QsciScintilla::WrapWord. + //! + //! \sa setWrapMode() + QsciScintilla::WrapMode wrapMode() const {return wrap;} + + //! Sets the line wrap mode used when printing to \a wmode. + //! + //! \sa wrapMode() + virtual void setWrapMode(QsciScintilla::WrapMode wmode); + +private: + int mag; + QsciScintilla::WrapMode wrap; + + QsciPrinter(const QsciPrinter &); + QsciPrinter &operator=(const QsciPrinter &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciscintilla.cpp b/harbour/contrib/hbide/qscintilla/qt/qsciscintilla.cpp new file mode 100644 index 0000000000..41b97e5a59 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciscintilla.cpp @@ -0,0 +1,3621 @@ +// This module implements the "official" high-level API of the Qt port of +// Scintilla. It is modelled on QTextEdit - a method of the same name should +// behave in the same way. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qsciscintilla.h" + +#include +#include +#include +#include +#include + +#include "qsciabstractapis.h" +#include "qscicommandset.h" +#include "qscilexer.h" +#include "qscistyle.h" +#include "qscistyledtext.h" + + +// Make sure these match the values in Scintilla.h. We don't #include that +// file because it just causes more clashes. +#define KEYWORDSET_MAX 8 +#define MARKER_MAX 31 + +#define ScintillaStringData(s) (s).constData() +#define ScintillaStringLength(s) (s).size() + +// The list separators for auto-completion and user lists. +const char acSeparator = '\x03'; +const char userSeparator = '\x04'; + +// The default fold margin width. +static const int defaultFoldMarginWidth = 14; + +// The default set of characters that make up a word. +static const char *defaultWordChars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + +// The ctor. +QsciScintilla::QsciScintilla(QWidget *parent) + : QsciScintillaBase(parent), + allocatedMarkers(0), oldPos(-1), selText(false), fold(NoFoldStyle), + foldmargin(2), autoInd(false), braceMode(NoBraceMatch), + acSource(AcsNone), acThresh(-1), wchars(defaultWordChars), + call_tips_style(CallTipsNoContext), maxCallTips(-1), showSingle(false), + explicit_fillups(""), fillups_enabled(false) +{ + connect(this,SIGNAL(SCN_MODIFYATTEMPTRO()), + SIGNAL(modificationAttempted())); + + connect(this,SIGNAL(SCN_MODIFIED(int,int,const char *,int,int,int,int,int,int,int)), + SLOT(handleModified(int,int,const char *,int,int,int,int,int,int,int))); + connect(this,SIGNAL(SCN_CALLTIPCLICK(int)), + SLOT(handleCallTipClick(int))); + connect(this,SIGNAL(SCN_CHARADDED(int)), + SLOT(handleCharAdded(int))); + connect(this,SIGNAL(SCN_MARGINCLICK(int,int,int)), + SLOT(handleMarginClick(int,int,int))); + connect(this,SIGNAL(SCN_SAVEPOINTREACHED()), + SLOT(handleSavePointReached())); + connect(this,SIGNAL(SCN_SAVEPOINTLEFT()), + SLOT(handleSavePointLeft())); + connect(this,SIGNAL(SCN_UPDATEUI()), + SLOT(handleUpdateUI())); + connect(this,SIGNAL(QSCN_SELCHANGED(bool)), + SLOT(handleSelectionChanged(bool))); + connect(this,SIGNAL(SCN_AUTOCSELECTION(const char *,int)), + SLOT(handleAutoCompletionSelection())); + connect(this,SIGNAL(SCN_USERLISTSELECTION(const char *,int)), + SLOT(handleUserListSelection(const char *,int))); + + // Set the default font. + setFont(QApplication::font()); + + // Set the default fore and background colours. + QPalette pal = QApplication::palette(); + setColor(pal.text().color()); + setPaper(pal.base().color()); + +#if defined(Q_OS_WIN) + setEolMode(EolWindows); +#elif defined(Q_OS_MAC) + setEolMode(EolMac); +#else + setEolMode(EolUnix); +#endif + + // Capturing the mouse seems to cause problems on multi-head systems. Qt + // should do the right thing anyway. + SendScintilla(SCI_SETMOUSEDOWNCAPTURES, 0UL); + + SendScintilla(SCI_SETPROPERTY, "fold", "1"); + SendScintilla(SCI_SETPROPERTY, "fold.html", "1"); + + setMatchedBraceForegroundColor(Qt::blue); + setUnmatchedBraceForegroundColor(Qt::red); + + setAnnotationDisplay(AnnotationStandard); + setLexer(); + + // Set the visible policy. These are the same as SciTE's defaults + // which, presumably, are sensible. + SendScintilla(SCI_SETVISIBLEPOLICY, VISIBLE_STRICT | VISIBLE_SLOP, 4); + + // Create the standard command set. + stdCmds = new QsciCommandSet(this); + + doc.display(this,0); +} + + +// The dtor. +QsciScintilla::~QsciScintilla() +{ + // Detach any current lexer. + detachLexer(); + + doc.undisplay(this); + delete stdCmds; +} + + +// Return the current text colour. +QColor QsciScintilla::color() const +{ + return nl_text_colour; +} + + +// Set the text colour. +void QsciScintilla::setColor(const QColor &c) +{ + if (lex.isNull()) + { + // Assume style 0 applies to everything so that we don't need to use + // SCI_STYLECLEARALL which clears everything. + SendScintilla(SCI_STYLESETFORE, 0, c); + nl_text_colour = c; + } +} + + +// Return the current paper colour. +QColor QsciScintilla::paper() const +{ + return nl_paper_colour; +} + + +// Set the paper colour. +void QsciScintilla::setPaper(const QColor &c) +{ + if (lex.isNull()) + { + // Assume style 0 applies to everything so that we don't need to use + // SCI_STYLECLEARALL which clears everything. We still have to set the + // default style as well for the background without any text. + SendScintilla(SCI_STYLESETBACK, 0, c); + SendScintilla(SCI_STYLESETBACK, STYLE_DEFAULT, c); + nl_paper_colour = c; + } +} + + +// Set the default font. +void QsciScintilla::setFont(const QFont &f) +{ + if (lex.isNull()) + { + // Assume style 0 applies to everything so that we don't need to use + // SCI_STYLECLEARALL which clears everything. + setStylesFont(f, 0); + QWidget::setFont(f); + } +} + + +// Enable/disable auto-indent. +void QsciScintilla::setAutoIndent(bool autoindent) +{ + autoInd = autoindent; +} + + +// Set the brace matching mode. +void QsciScintilla::setBraceMatching(BraceMatch bm) +{ + braceMode = bm; +} + + +// Handle the addition of a character. +void QsciScintilla::handleCharAdded(int ch) +{ + // Ignore if there is a selection. + long pos = SendScintilla(SCI_GETSELECTIONSTART); + + if (pos != SendScintilla(SCI_GETSELECTIONEND) || pos == 0) + return; + + // If auto-completion is already active then see if this character is a + // start character. If it is then create a new list which will be a subset + // of the current one. The case where it isn't a start character seems to + // be handled correctly elsewhere. + if (isListActive()) + { + if (isStartChar(ch)) + { + cancelList(); + startAutoCompletion(acSource, false, false); + } + + return; + } + + // Handle call tips. + if (call_tips_style != CallTipsNone && !lex.isNull() && strchr("(),", ch) != NULL) + callTip(); + + // Handle auto-indentation. + if (autoInd) + if (lex.isNull() || (lex->autoIndentStyle() & AiMaintain)) + maintainIndentation(ch, pos); + else + autoIndentation(ch, pos); + + // See if we might want to start auto-completion. + if (!isCallTipActive() && acSource != AcsNone) + if (isStartChar(ch)) + startAutoCompletion(acSource, false, false); + else if (acThresh >= 1 && isWordCharacter(ch)) + startAutoCompletion(acSource, true, false); +} + + +// See if a call tip is active. +bool QsciScintilla::isCallTipActive() const +{ + return SendScintilla(SCI_CALLTIPACTIVE); +} + + +// Handle a possible change to any current call tip. +void QsciScintilla::callTip() +{ + QsciAbstractAPIs *apis = lex->apis(); + + if (!apis) + return; + + int pos, commas = 0; + bool found = false; + char ch; + + pos = SendScintilla(SCI_GETCURRENTPOS); + + // Move backwards through the line looking for the start of the current + // call tip and working out which argument it is. + while ((ch = getCharacter(pos)) != '\0') + { + if (ch == ',') + ++commas; + else if (ch == ')') + { + int depth = 1; + + // Ignore everything back to the start of the corresponding + // parenthesis. + while ((ch = getCharacter(pos)) != '\0') + { + if (ch == ')') + ++depth; + else if (ch == '(' && --depth == 0) + break; + } + } + else if (ch == '(') + { + found = true; + break; + } + } + + // Cancel any existing call tip. + SendScintilla(SCI_CALLTIPCANCEL); + + // Done if there is no new call tip to set. + if (!found) + return; + + QStringList context = apiContext(pos, pos, ctPos); + + if (context.isEmpty()) + return; + + // The last word is complete, not partial. + context << QString(); + + ct_cursor = 0; + ct_shifts.clear(); + ct_entries = apis->callTips(context, commas, call_tips_style, ct_shifts); + + int nr_entries = ct_entries.count(); + + if (nr_entries == 0) + return; + + if (maxCallTips > 0 && maxCallTips < nr_entries) + { + ct_entries = ct_entries.mid(0, maxCallTips); + nr_entries = maxCallTips; + } + + int shift; + QString ct; + + int nr_shifts = ct_shifts.count(); + + if (maxCallTips < 0 && nr_entries > 1) + { + shift = (nr_shifts > 0 ? ct_shifts.first() : 0); + ct = ct_entries[0]; + ct.prepend('\002'); + } + else + { + if (nr_shifts > nr_entries) + nr_shifts = nr_entries; + + // Find the biggest shift. + shift = 0; + + for (int i = 0; i < nr_shifts; ++i) + { + int sh = ct_shifts[i]; + + if (shift < sh) + shift = sh; + } + + ct = ct_entries.join("\n"); + } + + QByteArray ct_ba = ct.toLatin1(); + const char *cts = ct_ba.data(); + + SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), cts); + + // Done if there is more than one call tip. + if (nr_entries > 1) + return; + + // Highlight the current argument. + const char *astart; + + if (commas == 0) + astart = strchr(cts, '('); + else + for (astart = strchr(cts, ','); astart && --commas > 0; astart = strchr(astart + 1, ',')) + ; + + if (!astart || !*++astart) + return; + + // The end is at the next comma or unmatched closing parenthesis. + const char *aend; + int depth = 0; + + for (aend = astart; *aend; ++aend) + { + char ch = *aend; + + if (ch == ',' && depth == 0) + break; + else if (ch == '(') + ++depth; + else if (ch == ')') + { + if (depth == 0) + break; + + --depth; + } + } + + if (astart != aend) + SendScintilla(SCI_CALLTIPSETHLT, astart - cts, aend - cts); +} + + +// Handle a call tip click. +void QsciScintilla::handleCallTipClick(int dir) +{ + int nr_entries = ct_entries.count(); + + // Move the cursor while bounds checking. + if (dir == 1) + { + if (ct_cursor - 1 < 0) + return; + + --ct_cursor; + } + else if (dir == 2) + { + if (ct_cursor + 1 >= nr_entries) + return; + + ++ct_cursor; + } + else + return; + + int shift = (ct_shifts.count() > ct_cursor ? ct_shifts[ct_cursor] : 0); + QString ct = ct_entries[ct_cursor]; + + // Add the arrows. + if (ct_cursor < nr_entries - 1) + ct.prepend('\002'); + + if (ct_cursor > 0) + ct.prepend('\001'); + + SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), ct.toLatin1().data()); +} + + +// Shift the position of the call tip (to take any context into account) but +// don't go before the start of the line. +int QsciScintilla::adjustedCallTipPosition(int ctshift) const +{ + int ct = ctPos; + + if (ctshift) + { + int ctmin = SendScintilla(SCI_POSITIONFROMLINE, SendScintilla(SCI_LINEFROMPOSITION, ct)); + + if (ct - ctshift < ctmin) + ct = ctmin; + } + + return ct; +} + + +// Return the list of words that make up the context preceding the given +// position. The list will only have more than one element if there is a lexer +// set and it defines start strings. If so, then the last element might be +// empty if a start string has just been typed. On return pos is at the start +// of the context. +QStringList QsciScintilla::apiContext(int pos, int &context_start, + int &last_word_start) +{ + enum { + Either, + Separator, + Word + }; + + QStringList words; + int good_pos = pos, expecting = Either; + + last_word_start = -1; + + while (pos > 0) + { + if (getSeparator(pos)) + { + if (expecting == Either) + words.prepend(QString()); + else if (expecting == Word) + break; + + good_pos = pos; + expecting = Word; + } + else + { + QString word = getWord(pos); + + if (word.isEmpty() || expecting == Separator) + break; + + words.prepend(word); + good_pos = pos; + expecting = Separator; + + // Return the position of the start of the last word if required. + if (last_word_start < 0) + last_word_start = pos; + } + + // Strip any preceding spaces (mainly around operators). + char ch; + + while ((ch = getCharacter(pos)) != '\0') + { + // This is the same definition of space that Scintilla uses. + if (ch != ' ' && (ch < 0x09 || ch > 0x0d)) + { + ++pos; + break; + } + } + } + + // A valid sequence always starts with a word and so should be expecting a + // separator. + if (expecting != Separator) + words.clear(); + + context_start = good_pos; + + return words; +} + + +// Try and get a lexer's word separator from the text before the current +// position. Return true if one was found and adjust the position accordingly. +bool QsciScintilla::getSeparator(int &pos) const +{ + int opos = pos; + + // Go through each separator. + for (int i = 0; i < wseps.count(); ++i) + { + const QString &ws = wseps[i]; + + // Work backwards. + uint l; + + for (l = ws.length(); l; --l) + { + char ch = getCharacter(pos); + + if (ch == '\0' || ws.at(l - 1) != ch) + break; + } + + if (!l) + return true; + + // Reset for the next separator. + pos = opos; + } + + return false; +} + + +// Try and get a word from the text before the current position. Return the +// word if one was found and adjust the position accordingly. +QString QsciScintilla::getWord(int &pos) const +{ + QString word; + bool numeric = true; + char ch; + + while ((ch = getCharacter(pos)) != '\0') + { + if (!isWordCharacter(ch)) + { + ++pos; + break; + } + + if (ch < '0' || ch > '9') + numeric = false; + + word.prepend(ch); + } + + // We don't auto-complete numbers. + if (numeric) + word.truncate(0); + + return word; +} + + +// Get the "next" character (ie. the one before the current position) in the +// current line. The character will be '\0' if there are no more. +char QsciScintilla::getCharacter(int &pos) const +{ + if (pos <= 0) + return '\0'; + + char ch = SendScintilla(SCI_GETCHARAT, --pos); + + // Don't go past the end of the previous line. + if (ch == '\n' || ch == '\r') + { + ++pos; + return '\0'; + } + + return ch; +} + + +// See if a character is an auto-completion start character, ie. the last +// character of a word separator. +bool QsciScintilla::isStartChar(char ch) const +{ + QString s = QChar(ch); + + for (int i = 0; i < wseps.count(); ++i) + if (wseps[i].endsWith(s)) + return true; + + return false; +} + + +// Possibly start auto-completion. +void QsciScintilla::startAutoCompletion(AutoCompletionSource acs, + bool checkThresh, bool single) +{ + int start, ignore; + QStringList context = apiContext(SendScintilla(SCI_GETCURRENTPOS), start, + ignore); + + if (context.isEmpty()) + return; + + // Get the last word's raw data and length. + ScintillaString s = convertTextQ2S(context.last()); + const char *last_data = ScintillaStringData(s); + int last_len = ScintillaStringLength(s); + + if (checkThresh && last_len < acThresh) + return; + + // Generate the string representing the valid words to select from. + QStringList wlist; + + if ((acs == AcsAll || acs == AcsAPIs) && !lex.isNull()) + { + QsciAbstractAPIs *apis = lex->apis(); + + if (apis) + apis->updateAutoCompletionList(context, wlist); + } + + if (acs == AcsAll || acs == AcsDocument) + { + int sflags = SCFIND_WORDSTART; + + if (!SendScintilla(SCI_AUTOCGETIGNORECASE)) + sflags |= SCFIND_MATCHCASE; + + SendScintilla(SCI_SETSEARCHFLAGS, sflags); + + int pos = 0; + int dlen = SendScintilla(SCI_GETLENGTH); + int caret = SendScintilla(SCI_GETCURRENTPOS); + int clen = caret - start; + char *orig_context = new char[clen + 1]; + + SendScintilla(SCI_GETTEXTRANGE, start, caret, orig_context); + + for (;;) + { + int fstart; + + SendScintilla(SCI_SETTARGETSTART, pos); + SendScintilla(SCI_SETTARGETEND, dlen); + + if ((fstart = SendScintilla(SCI_SEARCHINTARGET, clen, orig_context)) < 0) + break; + + // Move past the root part. + pos = fstart + clen; + + // Skip if this is the context we are auto-completing. + if (pos == caret) + continue; + + // Get the rest of this word. + QString w = last_data; + + while (pos < dlen) + { + char ch = SendScintilla(SCI_GETCHARAT, pos); + + if (!isWordCharacter(ch)) + break; + + w += ch; + ++pos; + } + + // Add the word if it isn't already there. + if (!w.isEmpty() && !wlist.contains(w)) + wlist.append(w); + } + + delete []orig_context; + } + + if (wlist.isEmpty()) + return; + + wlist.sort(); + + SendScintilla(SCI_AUTOCSETCHOOSESINGLE, single); + SendScintilla(SCI_AUTOCSETSEPARATOR, acSeparator); + + QByteArray chlist = wlist.join(QChar(acSeparator)).toLatin1(); + SendScintilla(SCI_AUTOCSHOW, last_len, chlist.constData()); +} + + +// Maintain the indentation of the previous line. +void QsciScintilla::maintainIndentation(char ch, long pos) +{ + if (ch != '\r' && ch != '\n') + return; + + int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos); + + // Get the indentation of the preceding non-zero length line. + int ind = 0; + + for (int line = curr_line - 1; line >= 0; --line) + { + if (SendScintilla(SCI_GETLINEENDPOSITION, line) > + SendScintilla(SCI_POSITIONFROMLINE, line)) + { + ind = indentation(line); + break; + } + } + + if (ind > 0) + autoIndentLine(pos, curr_line, ind); +} + + +// Implement auto-indentation. +void QsciScintilla::autoIndentation(char ch, long pos) +{ + int curr_line = SendScintilla(SCI_LINEFROMPOSITION, pos); + int ind_width = indentWidth(); + long curr_line_start = SendScintilla(SCI_POSITIONFROMLINE, curr_line); + + const char *block_start = lex->blockStart(); + bool start_single = (block_start && qstrlen(block_start) == 1); + + const char *block_end = lex->blockEnd(); + bool end_single = (block_end && qstrlen(block_end) == 1); + + if (end_single && block_end[0] == ch) + { + if (!(lex->autoIndentStyle() & AiClosing) && rangeIsWhitespace(curr_line_start, pos - 1)) + autoIndentLine(pos, curr_line, blockIndent(curr_line - 1) - ind_width); + } + else if (start_single && block_start[0] == ch) + { + // De-indent if we have already indented because the previous line was + // a start of block keyword. + if (!(lex->autoIndentStyle() & AiOpening) && curr_line > 0 && getIndentState(curr_line - 1) == isKeywordStart && rangeIsWhitespace(curr_line_start, pos - 1)) + autoIndentLine(pos, curr_line, blockIndent(curr_line - 1) - ind_width); + } + else if (ch == '\r' || ch == '\n') + autoIndentLine(pos, curr_line, blockIndent(curr_line - 1)); +} + + +// Set the indentation for a line. +void QsciScintilla::autoIndentLine(long pos, int line, int indent) +{ + if (indent < 0) + return; + + long pos_before = SendScintilla(SCI_GETLINEINDENTPOSITION, line); + SendScintilla(SCI_SETLINEINDENTATION, line, indent); + long pos_after = SendScintilla(SCI_GETLINEINDENTPOSITION, line); + long new_pos = -1; + + if (pos_after > pos_before) + new_pos = pos + (pos_after - pos_before); + else if (pos_after < pos_before && pos >= pos_after) + if (pos >= pos_before) + new_pos = pos + (pos_after - pos_before); + else + new_pos = pos_after; + + if (new_pos >= 0) + SendScintilla(SCI_SETSEL, new_pos, new_pos); +} + + +// Return the indentation of the block defined by the given line (or something +// significant before). +int QsciScintilla::blockIndent(int line) +{ + if (line < 0) + return 0; + + // Handle the trvial case. + if (!lex->blockStartKeyword() && !lex->blockStart() && !lex->blockEnd()) + return indentation(line); + + int line_limit = line - lex->blockLookback(); + + if (line_limit < 0) + line_limit = 0; + + for (int l = line; l >= line_limit; --l) + { + IndentState istate = getIndentState(l); + + if (istate != isNone) + { + int ind_width = indentWidth(); + int ind = indentation(l); + + if (istate == isBlockStart) + { + if (!(lex -> autoIndentStyle() & AiOpening)) + ind += ind_width; + } + else if (istate == isBlockEnd) + { + if (lex -> autoIndentStyle() & AiClosing) + ind -= ind_width; + + if (ind < 0) + ind = 0; + } + else if (line == l) + ind += ind_width; + + return ind; + } + } + + return indentation(line); +} + + +// Return true if all characters starting at spos up to, but not including +// epos, are spaces or tabs. +bool QsciScintilla::rangeIsWhitespace(long spos, long epos) +{ + while (spos < epos) + { + char ch = SendScintilla(SCI_GETCHARAT, spos); + + if (ch != ' ' && ch != '\t') + return false; + + ++spos; + } + + return true; +} + + +// Returns the indentation state of a line. +QsciScintilla::IndentState QsciScintilla::getIndentState(int line) +{ + IndentState istate; + + // Get the styled text. + long spos = SendScintilla(SCI_POSITIONFROMLINE, line); + long epos = SendScintilla(SCI_POSITIONFROMLINE, line + 1); + + char *text = new char[(epos - spos + 1) * 2]; + + SendScintilla(SCI_GETSTYLEDTEXT, spos, epos, text); + + int style, bstart_off, bend_off; + + // Block start/end takes precedence over keywords. + const char *bstart_words = lex->blockStart(&style); + bstart_off = findStyledWord(text, style, bstart_words); + + const char *bend_words = lex->blockEnd(&style); + bend_off = findStyledWord(text, style, bend_words); + + // If there is a block start but no block end characters then ignore it + // unless the block start is the last significant thing on the line, ie. + // assume Python-like blocking. + if (bstart_off >= 0 && !bend_words) + for (int i = bstart_off * 2; text[i] != '\0'; i += 2) + if (!QChar(text[i]).isSpace()) + return isNone; + + if (bstart_off > bend_off) + istate = isBlockStart; + else if (bend_off > bstart_off) + istate = isBlockEnd; + else + { + const char *words = lex->blockStartKeyword(&style); + + istate = (findStyledWord(text,style,words) >= 0) ? isKeywordStart : isNone; + } + + delete[] text; + + return istate; +} + + +// text is a pointer to some styled text (ie. a character byte followed by a +// style byte). style is a style number. words is a space separated list of +// words. Returns the position in the text immediately after the last one of +// the words with the style. The reason we are after the last, and not the +// first, occurance is that we are looking for words that start and end a block +// where the latest one is the most significant. +int QsciScintilla::findStyledWord(const char *text, int style, + const char *words) +{ + if (!words) + return -1; + + // Find the range of text with the style we are looking for. + const char *stext; + + for (stext = text; stext[1] != style; stext += 2) + if (stext[0] == '\0') + return -1; + + // Move to the last character. + const char *etext = stext; + + while (etext[2] != '\0') + etext += 2; + + // Backtrack until we find the style. There will be one. + while (etext[1] != style) + etext -= 2; + + // Look for each word in turn. + while (words[0] != '\0') + { + // Find the end of the word. + const char *eword = words; + + while (eword[1] != ' ' && eword[1] != '\0') + ++eword; + + // Now search the text backwards. + const char *wp = eword; + + for (const char *tp = etext; tp >= stext; tp -= 2) + { + if (tp[0] != wp[0] || tp[1] != style) + { + // Reset the search. + wp = eword; + continue; + } + + // See if all the word has matched. + if (wp-- == words) + return ((tp - text) / 2) + (eword - words) + 1; + } + + // Move to the start of the next word if there is one. + words = eword + 1; + + if (words[0] == ' ') + ++words; + } + + return -1; +} + + +// Return true if the code page is UTF8. +bool QsciScintilla::isUtf8() const +{ + return (SendScintilla(SCI_GETCODEPAGE) == SC_CP_UTF8); +} + + +// Set the code page. +void QsciScintilla::setUtf8(bool cp) +{ + setAttribute(Qt::WA_InputMethodEnabled, cp); + SendScintilla(SCI_SETCODEPAGE, (cp ? SC_CP_UTF8 : 0)); +} + + +// Return the end-of-line mode. +QsciScintilla::EolMode QsciScintilla::eolMode() const +{ + return (EolMode)SendScintilla(SCI_GETEOLMODE); +} + + +// Set the end-of-line mode. +void QsciScintilla::setEolMode(EolMode mode) +{ + SendScintilla(SCI_SETEOLMODE, mode); +} + + +// Convert the end-of-lines to a particular mode. +void QsciScintilla::convertEols(EolMode mode) +{ + SendScintilla(SCI_CONVERTEOLS, mode); +} + + +// Return the edge colour. +QColor QsciScintilla::edgeColor() const +{ + long res = SendScintilla(SCI_GETEDGECOLOUR); + + return QColor((int)res, ((int)(res >> 8)) & 0x00ff, ((int)(res >> 16)) & 0x00ff); +} + + +// Set the edge colour. +void QsciScintilla::setEdgeColor(const QColor &col) +{ + SendScintilla(SCI_SETEDGECOLOUR, col); +} + + +// Return the edge column. +int QsciScintilla::edgeColumn() const +{ + return SendScintilla(SCI_GETEDGECOLUMN); +} + + +// Set the edge column. +void QsciScintilla::setEdgeColumn(int colnr) +{ + SendScintilla(SCI_SETEDGECOLUMN, colnr); +} + + +// Return the edge mode. +QsciScintilla::EdgeMode QsciScintilla::edgeMode() const +{ + return (EdgeMode)SendScintilla(SCI_GETEDGEMODE); +} + + +// Set the edge mode. +void QsciScintilla::setEdgeMode(EdgeMode mode) +{ + SendScintilla(SCI_SETEDGEMODE, mode); +} + + +// Return the end-of-line visibility. +bool QsciScintilla::eolVisibility() const +{ + return SendScintilla(SCI_GETVIEWEOL); +} + + +// Set the end-of-line visibility. +void QsciScintilla::setEolVisibility(bool visible) +{ + SendScintilla(SCI_SETVIEWEOL, visible); +} + + +// Return the whitespace visibility. +QsciScintilla::WhitespaceVisibility QsciScintilla::whitespaceVisibility() const +{ + return (WhitespaceVisibility)SendScintilla(SCI_GETVIEWWS); +} + + +// Set the whitespace visibility. +void QsciScintilla::setWhitespaceVisibility(WhitespaceVisibility mode) +{ + SendScintilla(SCI_SETVIEWWS, mode); +} + + +// Return the line wrap mode. +QsciScintilla::WrapMode QsciScintilla::wrapMode() const +{ + return (WrapMode)SendScintilla(SCI_GETWRAPMODE); +} + + +// Set the line wrap mode. +void QsciScintilla::setWrapMode(WrapMode mode) +{ + SendScintilla(SCI_SETLAYOUTCACHE, + (mode == WrapNone ? SC_CACHE_CARET : SC_CACHE_DOCUMENT)); + SendScintilla(SCI_SETWRAPMODE, mode); +} + + +// Set the line wrap visual flags. +void QsciScintilla::setWrapVisualFlags(WrapVisualFlag eflag, + WrapVisualFlag sflag, int sindent) +{ + int flags = SC_WRAPVISUALFLAG_NONE; + int loc = SC_WRAPVISUALFLAGLOC_DEFAULT; + + if (eflag == WrapFlagByText) + { + flags |= SC_WRAPVISUALFLAG_END; + loc |= SC_WRAPVISUALFLAGLOC_END_BY_TEXT; + } + else if (eflag == WrapFlagByBorder) + flags |= SC_WRAPVISUALFLAG_END; + + if (sflag == WrapFlagByText) + { + flags |= SC_WRAPVISUALFLAG_START; + loc |= SC_WRAPVISUALFLAGLOC_START_BY_TEXT; + } + else if (sflag == WrapFlagByBorder) + flags |= SC_WRAPVISUALFLAG_START; + + SendScintilla(SCI_SETWRAPVISUALFLAGS, flags); + SendScintilla(SCI_SETWRAPVISUALFLAGSLOCATION, loc); + SendScintilla(SCI_SETWRAPSTARTINDENT, sindent); +} + + +// Set the folding style. +void QsciScintilla::setFolding(FoldStyle folding, int margin) +{ + fold = folding; + foldmargin = margin; + + if (folding == NoFoldStyle) + { + SendScintilla(SCI_SETMARGINWIDTHN, margin, 0L); + return; + } + + int mask = SendScintilla(SCI_GETMODEVENTMASK); + SendScintilla(SCI_SETMODEVENTMASK, mask | SC_MOD_CHANGEFOLD); + + SendScintilla(SCI_SETFOLDFLAGS, SC_FOLDFLAG_LINEAFTER_CONTRACTED); + + SendScintilla(SCI_SETMARGINTYPEN, margin, (long)SC_MARGIN_SYMBOL); + SendScintilla(SCI_SETMARGINMASKN, margin, SC_MASK_FOLDERS); + SendScintilla(SCI_SETMARGINSENSITIVEN, margin, 1); + + // Set the marker symbols to use. + switch (folding) + { + case PlainFoldStyle: + setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_MINUS); + setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_PLUS); + setFoldMarker(SC_MARKNUM_FOLDERSUB); + setFoldMarker(SC_MARKNUM_FOLDERTAIL); + setFoldMarker(SC_MARKNUM_FOLDEREND); + setFoldMarker(SC_MARKNUM_FOLDEROPENMID); + setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); + break; + + case CircledFoldStyle: + setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS); + setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS); + setFoldMarker(SC_MARKNUM_FOLDERSUB); + setFoldMarker(SC_MARKNUM_FOLDERTAIL); + setFoldMarker(SC_MARKNUM_FOLDEREND); + setFoldMarker(SC_MARKNUM_FOLDEROPENMID); + setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); + break; + + case BoxedFoldStyle: + setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS); + setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS); + setFoldMarker(SC_MARKNUM_FOLDERSUB); + setFoldMarker(SC_MARKNUM_FOLDERTAIL); + setFoldMarker(SC_MARKNUM_FOLDEREND); + setFoldMarker(SC_MARKNUM_FOLDEROPENMID); + setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL); + break; + + case CircledTreeFoldStyle: + setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS); + setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS); + setFoldMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); + setFoldMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE); + setFoldMarker(SC_MARKNUM_FOLDEREND, SC_MARK_CIRCLEPLUSCONNECTED); + setFoldMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED); + setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE); + break; + + case BoxedTreeFoldStyle: + setFoldMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS); + setFoldMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS); + setFoldMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); + setFoldMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER); + setFoldMarker(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED); + setFoldMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED); + setFoldMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER); + break; + + default: + break; + } + + SendScintilla(SCI_SETMARGINWIDTHN, margin, defaultFoldMarginWidth); +} + + +// Clear all current folds. +void QsciScintilla::clearFolds() +{ + recolor(); + + int maxLine = SendScintilla(SCI_GETLINECOUNT); + + for (int line = 0; line < maxLine; line++) + { + int level = SendScintilla(SCI_GETFOLDLEVEL, line); + + if (level & SC_FOLDLEVELHEADERFLAG) + { + SendScintilla(SCI_SETFOLDEXPANDED, line, 1); + foldExpand(line, true, false, 0, level); + line--; + } + } +} + + +// Set up a folder marker. +void QsciScintilla::setFoldMarker(int marknr, int mark) +{ + SendScintilla(SCI_MARKERDEFINE, marknr, mark); + + if (mark != SC_MARK_EMPTY) + { + SendScintilla(SCI_MARKERSETFORE, marknr, QColor(Qt::white)); + SendScintilla(SCI_MARKERSETBACK, marknr, QColor(Qt::black)); + } +} + + +// Handle a click in the fold margin. This is mostly taken from SciTE. +void QsciScintilla::foldClick(int lineClick, int bstate) +{ + bool shift = bstate & Qt::ShiftModifier; + bool ctrl = bstate & Qt::ControlModifier; + + if (shift && ctrl) + { + foldAll(); + return; + } + + int levelClick = SendScintilla(SCI_GETFOLDLEVEL, lineClick); + + if (levelClick & SC_FOLDLEVELHEADERFLAG) + { + if (shift) + { + // Ensure all children are visible. + SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1); + foldExpand(lineClick, true, true, 100, levelClick); + } + else if (ctrl) + { + if (SendScintilla(SCI_GETFOLDEXPANDED, lineClick)) + { + // Contract this line and all its children. + SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 0L); + foldExpand(lineClick, false, true, 0, levelClick); + } + else + { + // Expand this line and all its children. + SendScintilla(SCI_SETFOLDEXPANDED, lineClick, 1); + foldExpand(lineClick, true, true, 100, levelClick); + } + } + else + { + // Toggle this line. + SendScintilla(SCI_TOGGLEFOLD, lineClick); + } + } +} + + +// Do the hard work of hiding and showing lines. This is mostly taken from +// SciTE. +void QsciScintilla::foldExpand(int &line, bool doExpand, bool force, + int visLevels, int level) +{ + int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, line, + level & SC_FOLDLEVELNUMBERMASK); + + line++; + + while (line <= lineMaxSubord) + { + if (force) + { + if (visLevels > 0) + SendScintilla(SCI_SHOWLINES, line, line); + else + SendScintilla(SCI_HIDELINES, line, line); + } + else if (doExpand) + SendScintilla(SCI_SHOWLINES, line, line); + + int levelLine = level; + + if (levelLine == -1) + levelLine = SendScintilla(SCI_GETFOLDLEVEL, line); + + if (levelLine & SC_FOLDLEVELHEADERFLAG) + { + if (force) + { + if (visLevels > 1) + SendScintilla(SCI_SETFOLDEXPANDED, line, 1); + else + SendScintilla(SCI_SETFOLDEXPANDED, line, 0L); + + foldExpand(line, doExpand, force, visLevels - 1); + } + else if (doExpand) + { + if (!SendScintilla(SCI_GETFOLDEXPANDED, line)) + SendScintilla(SCI_SETFOLDEXPANDED, line, 1); + + foldExpand(line, true, force, visLevels - 1); + } + else + foldExpand(line, false, force, visLevels - 1); + } + else + line++; + } +} + + +// Fully expand (if there is any line currently folded) all text. Otherwise, +// fold all text. This is mostly taken from SciTE. +void QsciScintilla::foldAll(bool children) +{ + recolor(); + + int maxLine = SendScintilla(SCI_GETLINECOUNT); + bool expanding = true; + + for (int lineSeek = 0; lineSeek < maxLine; lineSeek++) + { + if (SendScintilla(SCI_GETFOLDLEVEL,lineSeek) & SC_FOLDLEVELHEADERFLAG) + { + expanding = !SendScintilla(SCI_GETFOLDEXPANDED, lineSeek); + break; + } + } + + for (int line = 0; line < maxLine; line++) + { + int level = SendScintilla(SCI_GETFOLDLEVEL, line); + + if (!(level & SC_FOLDLEVELHEADERFLAG)) + continue; + + if (children || + (SC_FOLDLEVELBASE == (level & SC_FOLDLEVELNUMBERMASK))) + { + if (expanding) + { + SendScintilla(SCI_SETFOLDEXPANDED, line, 1); + foldExpand(line, true, false, 0, level); + line--; + } + else + { + int lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, line, -1); + + SendScintilla(SCI_SETFOLDEXPANDED, line, 0L); + + if (lineMaxSubord > line) + SendScintilla(SCI_HIDELINES, line + 1, lineMaxSubord); + } + } + } +} + + +// Handle a fold change. This is mostly taken from SciTE. +void QsciScintilla::foldChanged(int line,int levelNow,int levelPrev) +{ + if (levelNow & SC_FOLDLEVELHEADERFLAG) + { + if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) + SendScintilla(SCI_SETFOLDEXPANDED, line, 1); + } + else if (levelPrev & SC_FOLDLEVELHEADERFLAG) + { + if (!SendScintilla(SCI_GETFOLDEXPANDED, line)) + { + // Removing the fold from one that has been contracted so should + // expand. Otherwise lines are left invisible with no way to make + // them visible. + foldExpand(line, true, false, 0, levelPrev); + } + } +} + + +// Toggle the fold for a line if it contains a fold marker. +void QsciScintilla::foldLine(int line) +{ + SendScintilla(SCI_TOGGLEFOLD, line); +} + + +// Handle the SCN_MODIFIED notification. +void QsciScintilla::handleModified(int pos, int mtype, const char *text, + int len, int added, int line, int foldNow, int foldPrev, int token, + int annotationLinesAdded) +{ + Q_UNUSED( pos ); + Q_UNUSED( text ); + Q_UNUSED( len ); + Q_UNUSED( token ); + Q_UNUSED(annotationLinesAdded ); + + if (mtype & SC_MOD_CHANGEFOLD) + { + if (fold) + foldChanged(line, foldNow, foldPrev); + } + + if (mtype & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) + { + emit textChanged(); + + if (added != 0) + emit linesChanged(); + } +} + + +// Zoom in a number of points. +void QsciScintilla::zoomIn(int range) +{ + zoomTo(SendScintilla(SCI_GETZOOM) + range); +} + + +// Zoom in a single point. +void QsciScintilla::zoomIn() +{ + SendScintilla(SCI_ZOOMIN); +} + + +// Zoom out a number of points. +void QsciScintilla::zoomOut(int range) +{ + zoomTo(SendScintilla(SCI_GETZOOM) - range); +} + + +// Zoom out a single point. +void QsciScintilla::zoomOut() +{ + SendScintilla(SCI_ZOOMOUT); +} + + +// Set the zoom to a number of points. +void QsciScintilla::zoomTo(int size) +{ + if (size < -10) + size = -10; + else if (size > 20) + size = 20; + + SendScintilla(SCI_SETZOOM, size); +} + + +// Find the first occurrence of a string. +bool QsciScintilla::findFirst(const QString &expr, bool re, bool cs, bool wo, + bool wrap, bool forward, int line, int index, bool show) +{ + findState.inProgress = false; + + if (expr.isEmpty()) + return false; + + findState.expr = expr; + findState.wrap = wrap; + findState.forward = forward; + + findState.flags = + (cs ? SCFIND_MATCHCASE : 0) | + (wo ? SCFIND_WHOLEWORD : 0) | + (re ? SCFIND_REGEXP : 0); + + if (line < 0 || index < 0) + findState.startpos = SendScintilla(SCI_GETCURRENTPOS); + else + findState.startpos = positionFromLineIndex(line, index); + + if (forward) + findState.endpos = SendScintilla(SCI_GETLENGTH); + else + findState.endpos = 0; + + findState.show = show; + + return doFind(); +} + + +// Find the next occurrence of a string. +bool QsciScintilla::findNext() +{ + if (!findState.inProgress) + return false; + + return doFind(); +} + + +// Do the hard work of findFirst() and findNext(). +bool QsciScintilla::doFind() +{ + SendScintilla(SCI_SETSEARCHFLAGS, findState.flags); + + int pos = simpleFind(); + + // See if it was found. If not and wraparound is wanted, try again. + if (pos == -1 && findState.wrap) + { + if (findState.forward) + { + findState.startpos = 0; + findState.endpos = SendScintilla(SCI_GETLENGTH); + } + else + { + findState.startpos = SendScintilla(SCI_GETLENGTH); + findState.endpos = 0; + } + + pos = simpleFind(); + } + + if (pos == -1) + { + findState.inProgress = false; + return false; + } + + // It was found. + long targstart = SendScintilla(SCI_GETTARGETSTART); + long targend = SendScintilla(SCI_GETTARGETEND); + + // Ensure the text found is visible if required. + if (findState.show) + { + int startLine = SendScintilla(SCI_LINEFROMPOSITION, targstart); + int endLine = SendScintilla(SCI_LINEFROMPOSITION, targend); + + for (int i = startLine; i <= endLine; ++i) + SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, i); + } + + // Now set the selection. + SendScintilla(SCI_SETSEL, targstart, targend); + + // Finally adjust the start position so that we don't find the same one + // again. + if (findState.forward) + findState.startpos = targend; + else if ((findState.startpos = targstart - 1) < 0) + findState.startpos = 0; + + findState.inProgress = true; + return true; +} + + +// Do a simple find between the start and end positions. +int QsciScintilla::simpleFind() +{ + if (findState.startpos == findState.endpos) + return -1; + + SendScintilla(SCI_SETTARGETSTART, findState.startpos); + SendScintilla(SCI_SETTARGETEND, findState.endpos); + + ScintillaString s = convertTextQ2S(findState.expr); + + return SendScintilla(SCI_SEARCHINTARGET, ScintillaStringLength(s), + ScintillaStringData(s)); +} + + +// Replace the text found with the previous findFirst() or findNext(). +void QsciScintilla::replace(const QString &replaceStr) +{ + if (!findState.inProgress) + return; + + long start = SendScintilla(SCI_GETSELECTIONSTART); + + SendScintilla(SCI_TARGETFROMSELECTION); + + int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET; + + ScintillaString s = convertTextQ2S(replaceStr); + long len = SendScintilla(cmd, -1, ScintillaStringData(s)); + + // Reset the selection. + SendScintilla(SCI_SETSELECTIONSTART, start); + SendScintilla(SCI_SETSELECTIONEND, start + len); + + if (findState.forward) + findState.startpos = start + len; +} + + +// Query the modified state. +bool QsciScintilla::isModified() const +{ + return doc.isModified(); +} + + +// Set the modified state. +void QsciScintilla::setModified(bool m) +{ + if (!m) + SendScintilla(SCI_SETSAVEPOINT); +} + + +// Handle the SCN_MARGINCLICK notification. +void QsciScintilla::handleMarginClick(int pos, int modifiers, int margin) +{ + int state = 0; + + if (modifiers & SCMOD_SHIFT) + state |= Qt::ShiftModifier; + + if (modifiers & SCMOD_CTRL) + state |= Qt::ControlModifier; + + if (modifiers & SCMOD_ALT) + state |= Qt::AltModifier; + + int line = SendScintilla(SCI_LINEFROMPOSITION, pos); + + if (fold && margin == foldmargin) + foldClick(line, state); + else + emit marginClicked(margin, line, Qt::KeyboardModifiers(state)); +} + + +// Handle the SCN_SAVEPOINTREACHED notification. +void QsciScintilla::handleSavePointReached() +{ + doc.setModified(false); + emit modificationChanged(false); +} + + +// Handle the SCN_SAVEPOINTLEFT notification. +void QsciScintilla::handleSavePointLeft() +{ + doc.setModified(true); + emit modificationChanged(true); +} + + +// Handle the QSCN_SELCHANGED signal. +void QsciScintilla::handleSelectionChanged(bool yes) +{ + selText = yes; + + emit copyAvailable(yes); + emit selectionChanged(); +} + + +// Get the current selection. +void QsciScintilla::getSelection(int *lineFrom, int *indexFrom, int *lineTo, + int *indexTo) const +{ + if (selText) + { + lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONSTART), lineFrom, + indexFrom); + lineIndexFromPosition(SendScintilla(SCI_GETSELECTIONEND), lineTo, + indexTo); + } + else + *lineFrom = *indexFrom = *lineTo = *indexTo = -1; +} + + +// Sets the current selection. +void QsciScintilla::setSelection(int lineFrom, int indexFrom, int lineTo, + int indexTo) +{ + SendScintilla(SCI_SETSEL, positionFromLineIndex(lineFrom, indexFrom), + positionFromLineIndex(lineTo, indexTo)); +} + + +// Set the background colour of selected text. +void QsciScintilla::setSelectionBackgroundColor(const QColor &col) +{ + int alpha = col.alpha(); + + if (alpha == 255) + alpha = SC_ALPHA_NOALPHA; + + SendScintilla(SCI_SETSELBACK, 1, col); + SendScintilla(SCI_SETSELALPHA, alpha); +} + + +// Set the foreground colour of selected text. +void QsciScintilla::setSelectionForegroundColor(const QColor &col) +{ + SendScintilla(SCI_SETSELFORE, 1, col); +} + + +// Reset the background colour of selected text to the default. +void QsciScintilla::resetSelectionBackgroundColor() +{ + SendScintilla(SCI_SETSELALPHA, SC_ALPHA_NOALPHA); + SendScintilla(SCI_SETSELBACK, 0UL); +} + + +// Reset the foreground colour of selected text to the default. +void QsciScintilla::resetSelectionForegroundColor() +{ + SendScintilla(SCI_SETSELFORE, 0UL); +} + + +// Set the fill to the end-of-line for the selection. +void QsciScintilla::setSelectionToEol(bool filled) +{ + SendScintilla(SCI_SETSELEOLFILLED, filled); +} + + +// Return the fill to the end-of-line for the selection. +bool QsciScintilla::selectionToEol() const +{ + return SendScintilla(SCI_GETSELEOLFILLED); +} + + +// Set the width of the caret. +void QsciScintilla::setCaretWidth(int width) +{ + SendScintilla(SCI_SETCARETWIDTH, width); +} + + +// Set the foreground colour of the caret. +void QsciScintilla::setCaretForegroundColor(const QColor &col) +{ + SendScintilla(SCI_SETCARETFORE, col); +} + + +// Set the background colour of the line containing the caret. +void QsciScintilla::setCaretLineBackgroundColor(const QColor &col) +{ + int alpha = col.alpha(); + + if (alpha == 255) + alpha = SC_ALPHA_NOALPHA; + + SendScintilla(SCI_SETCARETLINEBACK, col); + SendScintilla(SCI_SETCARETLINEBACKALPHA, alpha); +} + + +// Set the state of the background colour of the line containing the caret. +void QsciScintilla::setCaretLineVisible(bool enable) +{ + SendScintilla(SCI_SETCARETLINEVISIBLE, enable); +} + + +// Query the read-only state. +bool QsciScintilla::isReadOnly() const +{ + return SendScintilla(SCI_GETREADONLY); +} + + +// Set the read-only state. +void QsciScintilla::setReadOnly(bool ro) +{ + SendScintilla(SCI_SETREADONLY, ro); +} + + +// Append the given text. +void QsciScintilla::append(const QString &text) +{ + bool ro = ensureRW(); + + ScintillaString s = convertTextQ2S(text); + SendScintilla(SCI_APPENDTEXT, ScintillaStringLength(s), + ScintillaStringData(s)); + + SendScintilla(SCI_EMPTYUNDOBUFFER); + + setReadOnly(ro); +} + + +// Insert the given text at the current position. +void QsciScintilla::insert(const QString &text) +{ + insertAtPos(text, -1); +} + + +// Insert the given text at the given line and offset. +void QsciScintilla::insertAt(const QString &text, int line, int index) +{ + insertAtPos(text, positionFromLineIndex(line, index)); +} + + +// Insert the given text at the given position. +void QsciScintilla::insertAtPos(const QString &text, int pos) +{ + bool ro = ensureRW(); + + SendScintilla(SCI_BEGINUNDOACTION); + SendScintilla(SCI_INSERTTEXT, pos, + ScintillaStringData(convertTextQ2S(text))); + SendScintilla(SCI_ENDUNDOACTION); + + setReadOnly(ro); +} + + +// Begin a sequence of undoable actions. +void QsciScintilla::beginUndoAction() +{ + SendScintilla(SCI_BEGINUNDOACTION); +} + + +// End a sequence of undoable actions. +void QsciScintilla::endUndoAction() +{ + SendScintilla(SCI_ENDUNDOACTION); +} + + +// Redo a sequence of actions. +void QsciScintilla::redo() +{ + SendScintilla(SCI_REDO); +} + + +// Undo a sequence of actions. +void QsciScintilla::undo() +{ + SendScintilla(SCI_UNDO); +} + + +// See if there is something to redo. +bool QsciScintilla::isRedoAvailable() const +{ + return SendScintilla(SCI_CANREDO); +} + + +// See if there is something to undo. +bool QsciScintilla::isUndoAvailable() const +{ + return SendScintilla(SCI_CANUNDO); +} + + +// Return the number of lines. +int QsciScintilla::lines() const +{ + return SendScintilla(SCI_GETLINECOUNT); +} + + +// Return the line at a position. +int QsciScintilla::lineAt(const QPoint &pos) const +{ + long chpos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, pos.x(), pos.y()); + + if (chpos < 0) + return -1; + + return SendScintilla(SCI_LINEFROMPOSITION, chpos); +} + + +// Return the length of a line. +int QsciScintilla::lineLength(int line) const +{ + if (line < 0 || line >= SendScintilla(SCI_GETLINECOUNT)) + return -1; + + return SendScintilla(SCI_LINELENGTH, line); +} + + +// Return the length of the current text. +int QsciScintilla::length() const +{ + return SendScintilla(SCI_GETTEXTLENGTH); +} + + +// Remove any selected text. +void QsciScintilla::removeSelectedText() +{ + SendScintilla(SCI_REPLACESEL, ""); +} + + +// Return the current selected text. +QString QsciScintilla::selectedText() const +{ + if (!selText) + return QString(); + + char *buf = new char[SendScintilla(SCI_GETSELECTIONEND) - SendScintilla(SCI_GETSELECTIONSTART) + 1]; + + SendScintilla(SCI_GETSELTEXT, buf); + + QString qs = convertTextS2Q(buf); + delete[] buf; + + return qs; +} + + +// Return the current text. +QString QsciScintilla::text() const +{ + int buflen = length() + 1; + char *buf = new char[buflen]; + + SendScintilla(SCI_GETTEXT, buflen, buf); + + QString qs = convertTextS2Q(buf); + delete[] buf; + + return qs; +} + + +// Return the text of a line. +QString QsciScintilla::text(int line) const +{ + int line_len = lineLength(line); + + if (line_len < 1) + return QString(); + + char *buf = new char[line_len + 1]; + + SendScintilla(SCI_GETLINE, line, buf); + buf[line_len] = '\0'; + + QString qs = convertTextS2Q(buf); + delete[] buf; + + return qs; +} + + +// Set the given text. +void QsciScintilla::setText(const QString &text) +{ + bool ro = ensureRW(); + + SendScintilla(SCI_SETTEXT, ScintillaStringData(convertTextQ2S(text))); + SendScintilla(SCI_EMPTYUNDOBUFFER); + + setReadOnly(ro); +} + + +// Get the cursor position +void QsciScintilla::getCursorPosition(int *line, int *index) const +{ + lineIndexFromPosition(SendScintilla(SCI_GETCURRENTPOS), line, index); +} + + +// Set the cursor position +void QsciScintilla::setCursorPosition(int line, int index) +{ + SendScintilla(SCI_GOTOPOS, positionFromLineIndex(line, index)); +} + + +// Ensure the cursor is visible. +void QsciScintilla::ensureCursorVisible() +{ + SendScintilla(SCI_SCROLLCARET); +} + + +// Ensure a line is visible. +void QsciScintilla::ensureLineVisible(int line) +{ + SendScintilla(SCI_ENSUREVISIBLEENFORCEPOLICY, line); +} + + +// Copy text to the clipboard. +void QsciScintilla::copy() +{ + SendScintilla(SCI_COPY); +} + + +// Cut text to the clipboard. +void QsciScintilla::cut() +{ + SendScintilla(SCI_CUT); +} + + +// Paste text from the clipboard. +void QsciScintilla::paste() +{ + SendScintilla(SCI_PASTE); +} + + +// Select all text, or deselect any selected text. +void QsciScintilla::selectAll(bool select) +{ + if (select) + SendScintilla(SCI_SELECTALL); + else + SendScintilla(SCI_SETANCHOR, SendScintilla(SCI_GETCURRENTPOS)); +} + + +// Delete all text. +void QsciScintilla::clear() +{ + bool ro = ensureRW(); + + SendScintilla(SCI_BEGINUNDOACTION); + SendScintilla(SCI_CLEARALL); + SendScintilla(SCI_ENDUNDOACTION); + + setReadOnly(ro); +} + + +// Return the indentation of a line. +int QsciScintilla::indentation(int line) const +{ + return SendScintilla(SCI_GETLINEINDENTATION, line); +} + + +// Set the indentation of a line. +void QsciScintilla::setIndentation(int line, int indentation) +{ + SendScintilla(SCI_BEGINUNDOACTION); + SendScintilla(SCI_SETLINEINDENTATION, line, indentation); + SendScintilla(SCI_ENDUNDOACTION); +} + + +// Indent a line. +void QsciScintilla::indent(int line) +{ + setIndentation(line, indentation(line) + indentWidth()); +} + + +// Unindent a line. +void QsciScintilla::unindent(int line) +{ + int newIndent = indentation(line) - indentWidth(); + + if (newIndent < 0) + newIndent = 0; + + setIndentation(line, newIndent); +} + + +// Return the indentation of the current line. +int QsciScintilla::currentIndent() const +{ + return indentation(SendScintilla(SCI_LINEFROMPOSITION, + SendScintilla(SCI_GETCURRENTPOS))); +} + + +// Return the current indentation width. +int QsciScintilla::indentWidth() const +{ + int w = indentationWidth(); + + if (w == 0) + w = tabWidth(); + + return w; +} + + +// Return the state of indentation guides. +bool QsciScintilla::indentationGuides() const +{ + return (SendScintilla(SCI_GETINDENTATIONGUIDES) != SC_IV_NONE); +} + + +// Enable and disable indentation guides. +void QsciScintilla::setIndentationGuides(bool enable) +{ + int iv; + + if (!enable) + iv = SC_IV_NONE; + else if (lex.isNull()) + iv = SC_IV_REAL; + else + iv = lex->indentationGuideView(); + + SendScintilla(SCI_SETINDENTATIONGUIDES, iv); +} + + +// Set the background colour of indentation guides. +void QsciScintilla::setIndentationGuidesBackgroundColor(const QColor &col) +{ + SendScintilla(SCI_STYLESETBACK, STYLE_INDENTGUIDE, col); +} + + +// Set the foreground colour of indentation guides. +void QsciScintilla::setIndentationGuidesForegroundColor(const QColor &col) +{ + SendScintilla(SCI_STYLESETFORE, STYLE_INDENTGUIDE, col); +} + + +// Return the indentation width. +int QsciScintilla::indentationWidth() const +{ + return SendScintilla(SCI_GETINDENT); +} + + +// Set the indentation width. +void QsciScintilla::setIndentationWidth(int width) +{ + SendScintilla(SCI_SETINDENT, width); +} + + +// Return the tab width. +int QsciScintilla::tabWidth() const +{ + return SendScintilla(SCI_GETTABWIDTH); +} + + +// Set the tab width. +void QsciScintilla::setTabWidth(int width) +{ + SendScintilla(SCI_SETTABWIDTH, width); +} + + +// Return the effect of the backspace key. +bool QsciScintilla::backspaceUnindents() const +{ + return SendScintilla(SCI_GETBACKSPACEUNINDENTS); +} + + +// Set the effect of the backspace key. +void QsciScintilla::setBackspaceUnindents(bool unindents) +{ + SendScintilla(SCI_SETBACKSPACEUNINDENTS, unindents); +} + + +// Return the effect of the tab key. +bool QsciScintilla::tabIndents() const +{ + return SendScintilla(SCI_GETTABINDENTS); +} + + +// Set the effect of the tab key. +void QsciScintilla::setTabIndents(bool indents) +{ + SendScintilla(SCI_SETTABINDENTS, indents); +} + + +// Return the indentation use of tabs. +bool QsciScintilla::indentationsUseTabs() const +{ + return SendScintilla(SCI_GETUSETABS); +} + + +// Set the indentation use of tabs. +void QsciScintilla::setIndentationsUseTabs(bool tabs) +{ + SendScintilla(SCI_SETUSETABS, tabs); +} + + +// Return the margin type. +QsciScintilla::MarginType QsciScintilla::marginType(int margin) const +{ + return (MarginType)SendScintilla(SCI_GETMARGINTYPEN, margin); +} + + +// Set the margin type. +void QsciScintilla::setMarginType(int margin, QsciScintilla::MarginType type) +{ + SendScintilla(SCI_SETMARGINTYPEN, margin, type); +} + + +// Clear margin text. +void QsciScintilla::clearMarginText(int line) +{ + if (line < 0) + SendScintilla(SCI_MARGINSETTEXT, line, (const char *)0); + else + SendScintilla(SCI_MARGINTEXTCLEARALL); +} + + +// Annotate a line. +void QsciScintilla::setMarginText(int line, const QString &text, int style) +{ + int style_offset = SendScintilla(SCI_MARGINGETSTYLEOFFSET); + + SendScintilla(SCI_MARGINSETTEXT, line, + ScintillaStringData(convertTextQ2S(text))); + + SendScintilla(SCI_MARGINSETSTYLE, line, style - style_offset); +} + + +// Annotate a line. +void QsciScintilla::setMarginText(int line, const QString &text, const QsciStyle &style) +{ + setMarginText(line, text, style.style()); +} + + +// Annotate a line. +void QsciScintilla::setMarginText(int line, const QsciStyledText &text) +{ + setMarginText(line, text.text(), text.style()); +} + + +// Annotate a line. +void QsciScintilla::setMarginText(int line, const QList &text) +{ + char *styles; + ScintillaString styled_text = styleText(text, &styles, + SendScintilla(SCI_MARGINGETSTYLEOFFSET)); + + SendScintilla(SCI_MARGINSETTEXT, line, ScintillaStringData(styled_text)); + SendScintilla(SCI_MARGINSETSTYLES, line, styles); + + delete[] styles; +} + + +// Return the state of line numbers in a margin. +bool QsciScintilla::marginLineNumbers(int margin) const +{ + return SendScintilla(SCI_GETMARGINTYPEN, margin); +} + + +// Enable and disable line numbers in a margin. +void QsciScintilla::setMarginLineNumbers(int margin, bool lnrs) +{ + SendScintilla(SCI_SETMARGINTYPEN, margin, + lnrs ? SC_MARGIN_NUMBER : SC_MARGIN_SYMBOL); +} + + +// Return the marker mask of a margin. +int QsciScintilla::marginMarkerMask(int margin) const +{ + return SendScintilla(SCI_GETMARGINMASKN, margin); +} + + +// Set the marker mask of a margin. +void QsciScintilla::setMarginMarkerMask(int margin,int mask) +{ + SendScintilla(SCI_SETMARGINMASKN, margin, mask); +} + + +// Return the state of a margin's sensitivity. +bool QsciScintilla::marginSensitivity(int margin) const +{ + return SendScintilla(SCI_GETMARGINSENSITIVEN, margin); +} + + +// Enable and disable a margin's sensitivity. +void QsciScintilla::setMarginSensitivity(int margin,bool sens) +{ + SendScintilla(SCI_SETMARGINSENSITIVEN, margin, sens); +} + + +// Return the width of a margin. +int QsciScintilla::marginWidth(int margin) const +{ + return SendScintilla(SCI_GETMARGINWIDTHN, margin); +} + + +// Set the width of a margin. +void QsciScintilla::setMarginWidth(int margin, int width) +{ + SendScintilla(SCI_SETMARGINWIDTHN, margin, width); +} + + +// Set the width of a margin to the width of some text. +void QsciScintilla::setMarginWidth(int margin, const QString &s) +{ + int width = SendScintilla(SCI_TEXTWIDTH, STYLE_LINENUMBER, + ScintillaStringData(convertTextQ2S(s))); + + setMarginWidth(margin, width); +} + + +// Set the background colour of all margins. +void QsciScintilla::setMarginsBackgroundColor(const QColor &col) +{ + handleStylePaperChange(col, STYLE_LINENUMBER); +} + + +// Set the foreground colour of all margins. +void QsciScintilla::setMarginsForegroundColor(const QColor &col) +{ + handleStyleColorChange(col, STYLE_LINENUMBER); +} + + +// Set the font of all margins. +void QsciScintilla::setMarginsFont(const QFont &f) +{ + setStylesFont(f, STYLE_LINENUMBER); +} + + +// Define a marker based on a symbol. +int QsciScintilla::markerDefine(MarkerSymbol sym, int mnr) +{ + checkMarker(mnr); + + if (mnr >= 0) + SendScintilla(SCI_MARKERDEFINE, mnr, static_cast(sym)); + + return mnr; +} + + +// Define a marker based on a character. +int QsciScintilla::markerDefine(char ch, int mnr) +{ + checkMarker(mnr); + + if (mnr >= 0) + SendScintilla(SCI_MARKERDEFINE, mnr, + static_cast(SC_MARK_CHARACTER) + ch); + + return mnr; +} + + +// Define a marker based on a QPixmap. +int QsciScintilla::markerDefine(const QPixmap &pm, int mnr) +{ + checkMarker(mnr); + + if (mnr >= 0) + SendScintilla(SCI_MARKERDEFINEPIXMAP, mnr, pm); + + return mnr; +} + + +// Add a marker to a line. +int QsciScintilla::markerAdd(int linenr, int mnr) +{ + if (mnr < 0 || mnr > MARKER_MAX || (allocatedMarkers & (1 << mnr)) == 0) + return -1; + + return SendScintilla(SCI_MARKERADD, linenr, mnr); +} + + +// Get the marker mask for a line. +unsigned QsciScintilla::markersAtLine(int linenr) const +{ + return SendScintilla(SCI_MARKERGET, linenr); +} + + +// Delete a marker from a line. +void QsciScintilla::markerDelete(int linenr, int mnr) +{ + if (mnr <= MARKER_MAX) + { + if (mnr < 0) + { + unsigned am = allocatedMarkers; + + for (int m = 0; m <= MARKER_MAX; ++m) + { + if (am & 1) + SendScintilla(SCI_MARKERDELETE, linenr, m); + + am >>= 1; + } + } + else if (allocatedMarkers & (1 << mnr)) + SendScintilla(SCI_MARKERDELETE, linenr, mnr); + } +} + + +// Delete a marker from the text. +void QsciScintilla::markerDeleteAll(int mnr) +{ + if (mnr <= MARKER_MAX) + { + if (mnr < 0) + SendScintilla(SCI_MARKERDELETEALL, -1); + else if (allocatedMarkers & (1 << mnr)) + SendScintilla(SCI_MARKERDELETEALL, mnr); + } +} + + +// Delete a marker handle from the text. +void QsciScintilla::markerDeleteHandle(int mhandle) +{ + SendScintilla(SCI_MARKERDELETEHANDLE, mhandle); +} + + +// Return the line containing a marker instance. +int QsciScintilla::markerLine(int mhandle) const +{ + return SendScintilla(SCI_MARKERLINEFROMHANDLE, mhandle); +} + + +// Search forwards for a marker. +int QsciScintilla::markerFindNext(int linenr, unsigned mask) const +{ + return SendScintilla(SCI_MARKERNEXT, linenr, mask); +} + + +// Search backwards for a marker. +int QsciScintilla::markerFindPrevious(int linenr, unsigned mask) const +{ + return SendScintilla(SCI_MARKERPREVIOUS, linenr, mask); +} + + +// Set the marker background colour. +void QsciScintilla::setMarkerBackgroundColor(const QColor &col, int mnr) +{ + if (mnr <= MARKER_MAX) + { + int alpha = col.alpha(); + + // An opaque background would make the text invisible. + if (alpha == 255) + alpha = SC_ALPHA_NOALPHA; + + if (mnr < 0) + { + unsigned am = allocatedMarkers; + + for (int m = 0; m <= MARKER_MAX; ++m) + { + if (am & 1) + { + SendScintilla(SCI_MARKERSETBACK, m, col); + SendScintilla(SCI_MARKERSETALPHA, m, alpha); + } + + am >>= 1; + } + } + else if (allocatedMarkers & (1 << mnr)) + { + SendScintilla(SCI_MARKERSETBACK, mnr, col); + SendScintilla(SCI_MARKERSETALPHA, mnr, alpha); + } + } +} + + +// Set the marker foreground colour. +void QsciScintilla::setMarkerForegroundColor(const QColor &col, int mnr) +{ + if (mnr <= MARKER_MAX) + { + if (mnr < 0) + { + unsigned am = allocatedMarkers; + + for (int m = 0; m <= MARKER_MAX; ++m) + { + if (am & 1) + SendScintilla(SCI_MARKERSETFORE, m, col); + + am >>= 1; + } + } + else if (allocatedMarkers & (1 << mnr)) + { + SendScintilla(SCI_MARKERSETFORE, mnr, col); + } + } +} + + +// Check a marker, allocating a marker number if necessary. +void QsciScintilla::checkMarker(int &mnr) +{ + if (mnr >= 0) + { + // Note that we allow existing markers to be explicitly redefined. + if (mnr > MARKER_MAX) + mnr = -1; + } + else + { + unsigned am = allocatedMarkers; + + // Find the smallest unallocated marker number. + for (mnr = 0; mnr <= MARKER_MAX; ++mnr) + { + if ((am & 1) == 0) + break; + + am >>= 1; + } + } + + // Define the marker if it is valid. + if (mnr >= 0) + allocatedMarkers |= (1 << mnr); +} + + +// Reset the fold margin colours. +void QsciScintilla::resetFoldMarginColors() +{ + SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 0, 0L); + SendScintilla(SCI_SETFOLDMARGINCOLOUR, 0, 0L); +} + + +// Set the fold margin colours. +void QsciScintilla::setFoldMarginColors(const QColor &fore, const QColor &back) +{ + SendScintilla(SCI_SETFOLDMARGINHICOLOUR, 1, fore); + SendScintilla(SCI_SETFOLDMARGINCOLOUR, 1, back); +} + + +// Set the call tips background colour. +void QsciScintilla::setCallTipsBackgroundColor(const QColor &col) +{ + SendScintilla(SCI_CALLTIPSETBACK, col); +} + + +// Set the call tips foreground colour. +void QsciScintilla::setCallTipsForegroundColor(const QColor &col) +{ + SendScintilla(SCI_CALLTIPSETFORE, col); +} + + +// Set the call tips highlight colour. +void QsciScintilla::setCallTipsHighlightColor(const QColor &col) +{ + SendScintilla(SCI_CALLTIPSETFOREHLT, col); +} + + +// Set the matched brace background colour. +void QsciScintilla::setMatchedBraceBackgroundColor(const QColor &col) +{ + SendScintilla(SCI_STYLESETBACK, STYLE_BRACELIGHT, col); +} + + +// Set the matched brace foreground colour. +void QsciScintilla::setMatchedBraceForegroundColor(const QColor &col) +{ + SendScintilla(SCI_STYLESETFORE, STYLE_BRACELIGHT, col); +} + + +// Set the unmatched brace background colour. +void QsciScintilla::setUnmatchedBraceBackgroundColor(const QColor &col) +{ + SendScintilla(SCI_STYLESETBACK, STYLE_BRACEBAD, col); +} + + +// Set the unmatched brace foreground colour. +void QsciScintilla::setUnmatchedBraceForegroundColor(const QColor &col) +{ + SendScintilla(SCI_STYLESETFORE, STYLE_BRACEBAD, col); +} + + +// Detach any lexer. +void QsciScintilla::detachLexer() +{ + if (!lex.isNull()) + { + lex->setEditor(0); + lex->disconnect(this); + + SendScintilla(SCI_STYLERESETDEFAULT); + SendScintilla(SCI_STYLECLEARALL); + SendScintilla(SCI_CLEARDOCUMENTSTYLE); + } +} + + +// Set the lexer. +void QsciScintilla::setLexer(QsciLexer *lexer) +{ + // Detach any current lexer. + detachLexer(); + + // Connect up the new lexer. + lex = lexer; + + if (lex) + { + if (lex->lexer()) + SendScintilla(SCI_SETLEXERLANGUAGE, lex->lexer()); + else + SendScintilla(SCI_SETLEXER, lex->lexerId()); + + lex->setEditor(this); + + connect(lex,SIGNAL(colorChanged(const QColor &, int)), + SLOT(handleStyleColorChange(const QColor &, int))); + connect(lex,SIGNAL(eolFillChanged(bool, int)), + SLOT(handleStyleEolFillChange(bool, int))); + connect(lex,SIGNAL(fontChanged(const QFont &, int)), + SLOT(handleStyleFontChange(const QFont &, int))); + connect(lex,SIGNAL(paperChanged(const QColor &, int)), + SLOT(handleStylePaperChange(const QColor &, int))); + connect(lex,SIGNAL(propertyChanged(const char *, const char *)), + SLOT(handlePropertyChange(const char *, const char *))); + + // Set the keywords. Scintilla allows for sets numbered 0 to + // KEYWORDSET_MAX (although the lexers only seem to exploit 0 to + // KEYWORDSET_MAX - 1). We number from 1 in line with SciTE's property + // files. + for (int k = 0; k <= KEYWORDSET_MAX; ++k) + { + const char *kw = lex -> keywords(k + 1); + + if (!kw) + kw = ""; + + SendScintilla(SCI_SETKEYWORDS, k, kw); + } + + // Initialise each style. Do the default first so its (possibly + // incorrect) font setting gets reset when style 0 is set. + setLexerStyle(STYLE_DEFAULT); + + int nrStyles = 1 << SendScintilla(SCI_GETSTYLEBITS); + + for (int s = 0; s < nrStyles; ++s) + if (!lex->description(s).isNull()) + setLexerStyle(s); + + // Initialise the properties. + lex->refreshProperties(); + + // Set the auto-completion fillups and word separators. + setAutoCompletionFillupsEnabled(fillups_enabled); + wseps = lex->autoCompletionWordSeparators(); + + wchars = lex->wordCharacters(); + + if (!wchars) + wchars = defaultWordChars; + + SendScintilla(SCI_AUTOCSETIGNORECASE, !lex->caseSensitive()); + + recolor(); + } + else + { + SendScintilla(SCI_SETLEXER, SCLEX_CONTAINER); + + setColor(nl_text_colour); + setPaper(nl_paper_colour); + + SendScintilla(SCI_AUTOCSETFILLUPS, ""); + SendScintilla(SCI_AUTOCSETIGNORECASE, false); + wseps.clear(); + wchars = defaultWordChars; + } +} + + +// Set a particular style of the current lexer. +void QsciScintilla::setLexerStyle(int style) +{ + handleStyleColorChange(lex->color(style), style); + handleStyleEolFillChange(lex->eolFill(style), style); + handleStyleFontChange(lex->font(style), style); + handleStylePaperChange(lex->paper(style), style); +} + + +// Get the current lexer. +QsciLexer *QsciScintilla::lexer() const +{ + return lex; +} + + +// Handle a change in lexer style foreground colour. +void QsciScintilla::handleStyleColorChange(const QColor &c, int style) +{ + SendScintilla(SCI_STYLESETFORE, style, c); +} + + +// Handle a change in lexer style end-of-line fill. +void QsciScintilla::handleStyleEolFillChange(bool eolfill, int style) +{ + SendScintilla(SCI_STYLESETEOLFILLED, style, eolfill); +} + + +// Handle a change in lexer style font. +void QsciScintilla::handleStyleFontChange(const QFont &f, int style) +{ + setStylesFont(f, style); + + if (style == lex->braceStyle()) + { + setStylesFont(f, STYLE_BRACELIGHT); + setStylesFont(f, STYLE_BRACEBAD); + } +} + + +// Set the font for a style. +void QsciScintilla::setStylesFont(const QFont &f, int style) +{ + SendScintilla(SCI_STYLESETFONT, style, f.family().toAscii().data()); + SendScintilla(SCI_STYLESETSIZE, style, f.pointSize()); + SendScintilla(SCI_STYLESETBOLD, style, f.bold()); + SendScintilla(SCI_STYLESETITALIC, style, f.italic()); + SendScintilla(SCI_STYLESETUNDERLINE, style, f.underline()); + + // Tie the font settings of the default style to that of style 0 (the style + // conventionally used for whitespace by lexers). This is needed so that + // fold marks, indentations, edge columns etc are set properly. + if (style == 0) + setStylesFont(f, STYLE_DEFAULT); +} + + +// Handle a change in lexer style background colour. +void QsciScintilla::handleStylePaperChange(const QColor &c, int style) +{ + SendScintilla(SCI_STYLESETBACK, style, c); +} + + +// Handle a change in lexer property. +void QsciScintilla::handlePropertyChange(const char *prop, const char *val) +{ + SendScintilla(SCI_SETPROPERTY, prop, val); +} + + +// Handle a change to the user visible user interface. +void QsciScintilla::handleUpdateUI() +{ + int newPos = SendScintilla(SCI_GETCURRENTPOS); + + if (newPos != oldPos) + { + oldPos = newPos; + + int line = SendScintilla(SCI_LINEFROMPOSITION, newPos); + int col = SendScintilla(SCI_GETCOLUMN, newPos); + + emit cursorPositionChanged(line, col); + } + + if (braceMode != NoBraceMatch) + braceMatch(); +} + + +// Handle brace matching. +void QsciScintilla::braceMatch() +{ + long braceAtCaret, braceOpposite; + + findMatchingBrace(braceAtCaret, braceOpposite, braceMode); + + if (braceAtCaret >= 0 && braceOpposite < 0) + { + SendScintilla(SCI_BRACEBADLIGHT, braceAtCaret); + SendScintilla(SCI_SETHIGHLIGHTGUIDE, 0UL); + } + else + { + char chBrace = SendScintilla(SCI_GETCHARAT, braceAtCaret); + + SendScintilla(SCI_BRACEHIGHLIGHT, braceAtCaret, braceOpposite); + + long columnAtCaret = SendScintilla(SCI_GETCOLUMN, braceAtCaret); + long columnOpposite = SendScintilla(SCI_GETCOLUMN, braceOpposite); + + if (chBrace == ':') + { + long lineStart = SendScintilla(SCI_LINEFROMPOSITION, braceAtCaret); + long indentPos = SendScintilla(SCI_GETLINEINDENTPOSITION, + lineStart); + long indentPosNext = SendScintilla(SCI_GETLINEINDENTPOSITION, + lineStart + 1); + + columnAtCaret = SendScintilla(SCI_GETCOLUMN, indentPos); + + long columnAtCaretNext = SendScintilla(SCI_GETCOLUMN, + indentPosNext); + long indentSize = SendScintilla(SCI_GETINDENT); + + if (columnAtCaretNext - indentSize > 1) + columnAtCaret = columnAtCaretNext - indentSize; + + if (columnOpposite == 0) + columnOpposite = columnAtCaret; + } + + long column = columnAtCaret; + + if (column > columnOpposite) + column = columnOpposite; + + SendScintilla(SCI_SETHIGHLIGHTGUIDE, column); + } +} + + +// Check if the character at a position is a brace. +long QsciScintilla::checkBrace(long pos, int brace_style, bool &colonMode) +{ + long brace_pos = -1; + char ch = SendScintilla(SCI_GETCHARAT, pos); + + if (ch == ':') + { + // A bit of a hack, we should really use a virtual. + if (!lex.isNull() && qstrcmp(lex->lexer(), "python") == 0) + { + brace_pos = pos; + colonMode = true; + } + } + else if (ch && strchr("[](){}<>", ch)) + { + if (brace_style < 0) + brace_pos = pos; + else + { + int style = SendScintilla(SCI_GETSTYLEAT, pos) & 0x1f; + + if (style == brace_style) + brace_pos = pos; + } + } + + return brace_pos; +} + + +// Find a brace and it's match. Return true if the current position is inside +// a pair of braces. +bool QsciScintilla::findMatchingBrace(long &brace, long &other,BraceMatch mode) +{ + bool colonMode = false; + int brace_style = (lex.isNull() ? -1 : lex->braceStyle()); + + brace = -1; + other = -1; + + long caretPos = SendScintilla(SCI_GETCURRENTPOS); + + if (caretPos > 0) + brace = checkBrace(caretPos - 1, brace_style, colonMode); + + bool isInside = false; + + if (brace < 0 && mode == SloppyBraceMatch) + { + brace = checkBrace(caretPos, brace_style, colonMode); + + if (brace >= 0 && !colonMode) + isInside = true; + } + + if (brace >= 0) + { + if (colonMode) + { + // Find the end of the Python indented block. + long lineStart = SendScintilla(SCI_LINEFROMPOSITION, brace); + long lineMaxSubord = SendScintilla(SCI_GETLASTCHILD, lineStart, -1); + + other = SendScintilla(SCI_GETLINEENDPOSITION, lineMaxSubord); + } + else + other = SendScintilla(SCI_BRACEMATCH, brace); + + if (other > brace) + isInside = !isInside; + } + + return isInside; +} + + +// Move to the matching brace. +void QsciScintilla::moveToMatchingBrace() +{ + gotoMatchingBrace(false); +} + + +// Select to the matching brace. +void QsciScintilla::selectToMatchingBrace() +{ + gotoMatchingBrace(true); +} + + +// Move to the matching brace and optionally select the text. +void QsciScintilla::gotoMatchingBrace(bool select) +{ + long braceAtCaret; + long braceOpposite; + + bool isInside = findMatchingBrace(braceAtCaret, braceOpposite, + SloppyBraceMatch); + + if (braceOpposite >= 0) + { + // Convert the character positions into caret positions based on + // whether the caret position was inside or outside the braces. + if (isInside) + { + if (braceOpposite > braceAtCaret) + braceAtCaret++; + else + braceOpposite++; + } + else + { + if (braceOpposite > braceAtCaret) + braceOpposite++; + else + braceAtCaret++; + } + + ensureLineVisible(SendScintilla(SCI_LINEFROMPOSITION, braceOpposite)); + + if (select) + SendScintilla(SCI_SETSEL, braceAtCaret, braceOpposite); + else + SendScintilla(SCI_SETSEL, braceOpposite, braceOpposite); + } +} + + +// Return a position from a line number and an index within the line. +int QsciScintilla::positionFromLineIndex(int line, int index) const +{ + int pos = SendScintilla(SCI_POSITIONFROMLINE, line); + + // Allow for multi-byte characters. + for(int i = 0; i < index; i++) + pos = SendScintilla(SCI_POSITIONAFTER, pos); + + return pos; +} + + +// Return a line number and an index within the line from a position. +void QsciScintilla::lineIndexFromPosition(int position, int *line, int *index) const +{ + int lin = SendScintilla(SCI_LINEFROMPOSITION, position); + int linpos = SendScintilla(SCI_POSITIONFROMLINE, lin); + int indx = 0; + + // Allow for multi-byte characters. + while (linpos < position) + { + int new_linpos = SendScintilla(SCI_POSITIONAFTER, linpos); + + // If the position hasn't moved then we must be at the end of the text + // (which implies that the position passed was beyond the end of the + // text). + if (new_linpos == linpos) + break; + + linpos = new_linpos; + ++indx; + } + + *line = lin; + *index = indx; +} + + +// Convert a Scintilla string to a Qt Unicode string. +QString QsciScintilla::convertTextS2Q(const char *s) const +{ + if (isUtf8()) + return QString::fromUtf8(s); + + return QString::fromLatin1(s); +} + + +// Convert a Qt Unicode string to a Scintilla string. +QsciScintilla::ScintillaString QsciScintilla::convertTextQ2S(const QString &q) const +{ + if (isUtf8()) + return q.toUtf8(); + + return q.toLatin1(); +} + + +// Set the source of the automatic auto-completion list. +void QsciScintilla::setAutoCompletionSource(AutoCompletionSource source) +{ + acSource = source; +} + + +// Set the threshold for automatic auto-completion. +void QsciScintilla::setAutoCompletionThreshold(int thresh) +{ + acThresh = thresh; +} + + +// Set the auto-completion word separators if there is no current lexer. +void QsciScintilla::setAutoCompletionWordSeparators(const QStringList &separators) +{ + if (lex.isNull()) + wseps = separators; +} + + +// Explicitly auto-complete from all sources. +void QsciScintilla::autoCompleteFromAll() +{ + startAutoCompletion(AcsAll, false, showSingle); +} + + +// Explicitly auto-complete from the APIs. +void QsciScintilla::autoCompleteFromAPIs() +{ + startAutoCompletion(AcsAPIs, false, showSingle); +} + + +// Explicitly auto-complete from the document. +void QsciScintilla::autoCompleteFromDocument() +{ + startAutoCompletion(AcsDocument, false, showSingle); +} + + +// Check if a character can be in a word. +bool QsciScintilla::isWordCharacter(char ch) const +{ + return (strchr(wchars, ch) != NULL); +} + + +// Return the set of valid word characters. +const char *QsciScintilla::wordCharacters() const +{ + return wchars; +} + + +// Recolour the document. +void QsciScintilla::recolor(int start, int end) +{ + SendScintilla(SCI_COLOURISE, start, end); +} + + +// Registered an image. +void QsciScintilla::registerImage(int id, const QPixmap &pm) +{ + SendScintilla(SCI_REGISTERIMAGE, id, pm); +} + + +// Clear all registered images. +void QsciScintilla::clearRegisteredImages() +{ + SendScintilla(SCI_CLEARREGISTEREDIMAGES); +} + + +// Enable auto-completion fill-ups. +void QsciScintilla::setAutoCompletionFillupsEnabled(bool enable) +{ + const char *fillups; + + if (!enable) + fillups = ""; + else if (!lex.isNull()) + fillups = lex->autoCompletionFillups(); + else + fillups = explicit_fillups.data(); + + SendScintilla(SCI_AUTOCSETFILLUPS, fillups); + + fillups_enabled = enable; +} + + +// See if auto-completion fill-ups are enabled. +bool QsciScintilla::autoCompletionFillupsEnabled() const +{ + return fillups_enabled; +} + + +// Set the fill-up characters for auto-completion if there is no current lexer. +void QsciScintilla::setAutoCompletionFillups(const char *fillups) +{ + explicit_fillups = fillups; + setAutoCompletionFillupsEnabled(fillups_enabled); +} + + +// Set the case sensitivity for auto-completion if there is no current lexer. +void QsciScintilla::setAutoCompletionCaseSensitivity(bool cs) +{ + if (lex.isNull()) + SendScintilla(SCI_AUTOCSETIGNORECASE, !cs); +} + + +// Return the case sensitivity for auto-completion. +bool QsciScintilla::autoCompletionCaseSensitivity() const +{ + return !SendScintilla(SCI_AUTOCGETIGNORECASE); +} + + +// Set the replace word mode for auto-completion. +void QsciScintilla::setAutoCompletionReplaceWord(bool replace) +{ + SendScintilla(SCI_AUTOCSETDROPRESTOFWORD, replace); +} + + +// Return the replace word mode for auto-completion. +bool QsciScintilla::autoCompletionReplaceWord() const +{ + return SendScintilla(SCI_AUTOCGETDROPRESTOFWORD); +} + + +// Set the single item mode for auto-completion. +void QsciScintilla::setAutoCompletionShowSingle(bool single) +{ + showSingle = single; +} + + +// Return the single item mode for auto-completion. +bool QsciScintilla::autoCompletionShowSingle() const +{ + return showSingle; +} + + +// Set current call tip style. +void QsciScintilla::setCallTipsStyle(CallTipsStyle style) +{ + call_tips_style = style; +} + + +// Set maximum number of call tips displayed. +void QsciScintilla::setCallTipsVisible(int nr) +{ + maxCallTips = nr; +} + + +// Set the document to display. +void QsciScintilla::setDocument(const QsciDocument &document) +{ + if (doc.pdoc != document.pdoc) + { + doc.undisplay(this); + doc.attach(document); + doc.display(this,&document); + } +} + + +// Ensure the document is read-write and return true if was was read-only. +bool QsciScintilla::ensureRW() +{ + bool ro = isReadOnly(); + + if (ro) + setReadOnly(false); + + return ro; +} + + +// Return the number of the first visible line. +int QsciScintilla::firstVisibleLine() const +{ + return SendScintilla(SCI_GETFIRSTVISIBLELINE); +} + + +// Return the height in pixels of the text in a particular line. +int QsciScintilla::textHeight(int linenr) const +{ + return SendScintilla(SCI_TEXTHEIGHT, linenr); +} + + +// See if auto-completion or user list is active. +bool QsciScintilla::isListActive() const +{ + return SendScintilla(SCI_AUTOCACTIVE); +} + + +// Cancel any current auto-completion or user list. +void QsciScintilla::cancelList() +{ + SendScintilla(SCI_AUTOCCANCEL); +} + + +// Handle a selection from the auto-completion list. +void QsciScintilla::handleAutoCompletionSelection() +{ + if (!lex.isNull()) + { + QsciAbstractAPIs *apis = lex->apis(); + + if (apis) + apis->autoCompletionSelected(acSelection); + } +} + + +// Display a user list. +void QsciScintilla::showUserList(int id, const QStringList &list) +{ + // Sanity check to make sure auto-completion doesn't get confused. + if (id <= 0) + return; + + SendScintilla(SCI_AUTOCSETSEPARATOR, userSeparator); + SendScintilla(SCI_USERLISTSHOW, id, + list.join(QChar(userSeparator)).toLatin1().data()); +} + + +// Translate the SCN_USERLISTSELECTION notification into something more useful. +void QsciScintilla::handleUserListSelection(const char *text, int id) +{ + emit userListActivated(id, QString(text)); +} + + +// Return the case sensitivity of any lexer. +bool QsciScintilla::caseSensitive() const +{ + return lex.isNull() ? true : lex->caseSensitive(); +} + + +// Return true if the current list is an auto-completion list rather than a +// user list. +bool QsciScintilla::isAutoCompletionList() const +{ + return (SendScintilla(SCI_AUTOCGETSEPARATOR) == acSeparator); +} + + +// Read the text from a QIODevice. +bool QsciScintilla::read(QIODevice *io) +{ + const int min_size = 1024 * 8; + + int buf_size = min_size; + char *buf = new char[buf_size]; + + int data_len = 0; + bool ok = true; + + qint64 part; + + // Read the whole lot in so we don't have to worry about character + // boundaries. + do + { + // Make sure there is a minimum amount of room. + if (buf_size - data_len < min_size) + { + buf_size *= 2; + char *new_buf = new char[buf_size * 2]; + + memcpy(new_buf, buf, data_len); + delete[] buf; + buf = new_buf; + } + + part = io->read(buf + data_len, buf_size - data_len - 1); + + data_len += part; + } + while (part > 0); + + if (part < 0) + ok = false; + else + { + buf[data_len] = '\0'; + + bool ro = ensureRW(); + + SendScintilla(SCI_SETTEXT, buf); + SendScintilla(SCI_EMPTYUNDOBUFFER); + + setReadOnly(ro); + } + + delete[] buf; + + return ok; +} + + +// Write the text to a QIODevice. +bool QsciScintilla::write(QIODevice *io) const +{ + const char *buf = reinterpret_cast(SendScintillaPtrResult(SCI_GETCHARACTERPOINTER)); + + const char *bp = buf; + uint buflen = qstrlen(buf); + + while (buflen > 0) + { + qint64 part = io->write(bp, buflen); + + if (part < 0) + return false; + + bp += part; + buflen -= part; + } + + return true; +} + + +// Return the word at the given cooridinates. +QString QsciScintilla::wordAtPoint(const QPoint &point) const +{ + long close_pos = SendScintilla(SCI_POSITIONFROMPOINTCLOSE, point.x(), + point.y()); + + if (close_pos < 0) + return QString(); + + long start_pos = SendScintilla(SCI_WORDSTARTPOSITION, close_pos, true); + long end_pos = SendScintilla(SCI_WORDENDPOSITION, close_pos, true); + int word_len = end_pos - start_pos; + + if (word_len <= 0) + return QString(); + + char *buf = new char[word_len + 1]; + SendScintilla(SCI_GETTEXTRANGE, start_pos, end_pos, buf); + QString word = convertTextS2Q(buf); + delete[] buf; + + return word; +} + + +// Return the display style for annotations. +QsciScintilla::AnnotationDisplay QsciScintilla::annotationDisplay() const +{ + return (AnnotationDisplay)SendScintilla(SCI_ANNOTATIONGETVISIBLE); +} + + +// Set the display style for annotations. +void QsciScintilla::setAnnotationDisplay(QsciScintilla::AnnotationDisplay display) +{ + SendScintilla(SCI_ANNOTATIONSETVISIBLE, display); +} + + +// Clear annotations. +void QsciScintilla::clearAnnotations(int line) +{ + if (line < 0) + SendScintilla(SCI_ANNOTATIONSETTEXT, line, (const char *)0); + else + SendScintilla(SCI_ANNOTATIONCLEARALL); +} + + +// Annotate a line. +void QsciScintilla::annotate(int line, const QString &text, int style) +{ + int style_offset = SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET); + + ScintillaString s = convertTextQ2S(text); + + SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaStringData(s)); + + // SCI_ANNOTATIONSETSTYLE is broken in Scintilla v1.78 when the text + // contains newlines. +#if 0 + SendScintilla(SCI_ANNOTATIONSETSTYLE, line, style - style_offset); +#else + int nr_bytes = ScintillaStringLength(s); + char *styles = new char[nr_bytes]; + + memset(styles, style - style_offset, nr_bytes); + SendScintilla(SCI_ANNOTATIONSETSTYLES, line, styles); + + delete[] styles; +#endif +} + + +// Annotate a line. +void QsciScintilla::annotate(int line, const QString &text, const QsciStyle &style) +{ + annotate(line, text, style.style()); +} + + +// Annotate a line. +void QsciScintilla::annotate(int line, const QsciStyledText &text) +{ + annotate(line, text.text(), text.style()); +} + + +// Annotate a line. +void QsciScintilla::annotate(int line, const QList &text) +{ + char *styles; + ScintillaString styled_text = styleText(text, &styles, + SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET)); + + SendScintilla(SCI_ANNOTATIONSETTEXT, line, + ScintillaStringData(styled_text)); + SendScintilla(SCI_ANNOTATIONSETSTYLES, line, styles); + + delete[] styles; +} + + +// Get the annotation for a line, if any. +QString QsciScintilla::annotation(int line) const +{ + char *buf = new char[SendScintilla(SCI_ANNOTATIONGETTEXT, line, (const char *)0) + 1]; + + buf[SendScintilla(SCI_ANNOTATIONGETTEXT, line, buf)] = '\0'; + + QString qs = convertTextS2Q(buf); + delete[] buf; + + return qs; +} + + +// Convert a list of styled text to the low-level arrays. +QsciScintilla::ScintillaString QsciScintilla::styleText(const QList &styled_text, char **styles, int style_offset) +{ + QString text; + int i; + + // Build the full text. + for (i = 0; i < styled_text.count(); ++i) + { + const QsciStyledText &st = styled_text[i]; + + text.append(st.text()); + } + + ScintillaString s = convertTextQ2S(text); + + // There is a style byte for every byte. + char *sp = *styles = new char[ScintillaStringLength(s)]; + + for (i = 0; i < styled_text.count(); ++i) + { + const QsciStyledText &st = styled_text[i]; + ScintillaString part = convertTextQ2S(st.text()); + int part_length = ScintillaStringLength(part); + + for (int c = 0; c < part_length; ++c) + *sp++ = (char)(st.style() - style_offset); + } + + return s; +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciscintilla.h b/harbour/contrib/hbide/qscintilla/qt/qsciscintilla.h new file mode 100644 index 0000000000..0f54ae422a --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciscintilla.h @@ -0,0 +1,1681 @@ +// This module defines the "official" high-level API of the Qt port of +// Scintilla. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCISCINTILLA_H +#define QSCISCINTILLA_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +class QIODevice; +class QPoint; + +class QsciCommandSet; +class QsciLexer; +class QsciStyle; +class QsciStyledText; +class ListBoxQt; + + +//! \brief The QsciScintilla class implements a higher level, more Qt-like, +//! API to the Scintilla editor widget. +//! +//! QsciScintilla implements methods, signals and slots similar to those found +//! in other Qt editor classes. It also provides a higher level interface to +//! features specific to Scintilla such as syntax styling, call tips, +//! auto-indenting and auto-completion than that provided by QsciScintillaBase. +class QSCINTILLA_EXPORT QsciScintilla : public QsciScintillaBase +{ + Q_OBJECT + +public: + //! This enum defines the different auto-indentation styles. + enum { + //! A line is automatically indented to match the previous line. + AiMaintain = 0x01, + + //! If the language supported by the current lexer has a specific start + //! of block character (e.g. { in C++), then a line that begins with + //! that character is indented as well as the lines that make up the + //! block. It may be logically ored with AiClosing. + AiOpening = 0x02, + + //! If the language supported by the current lexer has a specific end + //! of block character (e.g. } in C++), then a line that begins with + //! that character is indented as well as the lines that make up the + //! block. It may be logically ored with AiOpening. + AiClosing = 0x04 + }; + + //! This enum defines the different annotation display styles. + enum AnnotationDisplay { + //! Annotations are not displayed. + AnnotationHidden = ANNOTATION_HIDDEN, + + //! Annotations are drawn left justified with no adornment. + AnnotationStandard = ANNOTATION_STANDARD, + + //! Annotations are surrounded by a box. + AnnotationBoxed = ANNOTATION_BOXED + }; + + //! This enum defines the different sources for auto-completion lists. + enum AutoCompletionSource { + //! No sources are used, ie. automatic auto-completion is disabled. + AcsNone, + + //! The source is all available sources. + AcsAll, + + //! The source is the current document. + AcsDocument, + + //! The source is any installed APIs. + AcsAPIs + }; + + //! This enum defines the different brace matching modes. The character + //! pairs {}, [] and () are treated as braces. The Python lexer will also + //! match a : with the end of the corresponding indented block. + enum BraceMatch { + //! Brace matching is disabled. + NoBraceMatch, + + //! Brace matching is enabled for a brace immediately before the + //! current position. + StrictBraceMatch, + + //! Brace matching is enabled for a brace immediately before or after + //! the current position. + SloppyBraceMatch + }; + + //! This enum defines the different call tip styles. + enum CallTipsStyle { + //! Call tips are disabled. + CallTipsNone, + + //! Call tips are displayed without a context. A context is any scope + //! (e.g. a C++ namespace or a Python module) prior to the function + //! name. + CallTipsNoContext, + + //! Call tips are displayed with a context only if the user hasn't + //! already implicitly identified the context using autocompletion. + //! Note that this style may not always be able to align the call tip + //! with the text being entered. + CallTipsNoAutoCompletionContext, + + //! Call tips are displayed with a context. Note that this style + //! may not always be able to align the call tip with the text being + //! entered. + CallTipsContext + }; + + //! This enum defines the different edge modes for long lines. + enum EdgeMode { + //! Long lines are not marked. + EdgeNone = EDGE_NONE, + + //! A vertical line is drawn at the column set by setEdgeColumn(). + //! This is recommended for monospace fonts. + EdgeLine = EDGE_LINE, + + //! The background color of characters after the column limit is + //! changed to the color set by setEdgeColor(). This is recommended + //! for proportional fonts. + EdgeBackground = EDGE_BACKGROUND + }; + + //! This enum defines the different end-of-line modes. + enum EolMode { + //! A carriage return/line feed as used on Windows systems. + EolWindows = SC_EOL_CRLF, + + //! A line feed as used on Unix systems. + EolUnix = SC_EOL_LF, + + //! A carriage return as used on Mac systems. + EolMac = SC_EOL_CR + }; + + //! This enum defines the different styles for the folding margin. + enum FoldStyle { + //! Folding is disabled. + NoFoldStyle, + + //! Plain folding style using plus and minus symbols. + PlainFoldStyle, + + //! Circled folding style using circled plus and minus symbols. + CircledFoldStyle, + + //! Boxed folding style using boxed plus and minus symbols. + BoxedFoldStyle, + + //! Circled tree style using a flattened tree with circled plus and + //! minus symbols and rounded corners. + CircledTreeFoldStyle, + + //! Boxed tree style using a flattened tree with boxed plus and minus + //! symbols and right-angled corners. + BoxedTreeFoldStyle + }; + + //! This enum defined the different margin types. + enum MarginType { + //! The margin contains symbols, including those used for folding. + SymbolMargin = SC_MARGIN_SYMBOL, + + //! The margin contains symbols and uses the default foreground color + //! as its background color. + SymbolMarginDefaultForegroundColor = SC_MARGIN_FORE, + + //! The margin contains symbols and uses the default background color + //! as its background color. + SymbolMarginDefaultBackgroundColor = SC_MARGIN_BACK, + + //! The margin contains line numbers. + NumberMargin = SC_MARGIN_NUMBER, + + //! The margin contains styled text. + TextMargin = SC_MARGIN_TEXT, + + //! The margin contains right justified styled text. + TextMarginRightJustified = SC_MARGIN_RTEXT + }; + + //! This enum defines the different pre-defined marker symbols. + enum MarkerSymbol { + //! A circle. + Circle = SC_MARK_CIRCLE, + + //! A rectangle. + Rectangle = SC_MARK_ROUNDRECT, + + //! A triangle pointing to the right. + RightTriangle = SC_MARK_ARROW, + + //! A smaller rectangle. + SmallRectangle = SC_MARK_SMALLRECT, + + //! An arrow pointing to the right. + RightArrow = SC_MARK_SHORTARROW, + + //! An invisible marker that allows code to track the movement + //! of lines. + Invisible = SC_MARK_EMPTY, + + //! A triangle pointing down. + DownTriangle = SC_MARK_ARROWDOWN, + + //! A drawn minus sign. + Minus = SC_MARK_MINUS, + + //! A drawn plus sign. + Plus = SC_MARK_PLUS, + + //! A vertical line drawn in the background colour. + VerticalLine = SC_MARK_VLINE, + + //! A bottom left corner drawn in the background colour. + BottomLeftCorner = SC_MARK_LCORNER, + + //! A vertical line with a centre right horizontal line drawn + //! in the background colour. + LeftSideSplitter = SC_MARK_TCORNER, + + //! A drawn plus sign in a box. + BoxedPlus = SC_MARK_BOXPLUS, + + //! A drawn plus sign in a connected box. + BoxedPlusConnected = SC_MARK_BOXPLUSCONNECTED, + + //! A drawn minus sign in a box. + BoxedMinus = SC_MARK_BOXMINUS, + + //! A drawn minus sign in a connected box. + BoxedMinusConnected = SC_MARK_BOXMINUSCONNECTED, + + //! A rounded bottom left corner drawn in the background + //! colour. + RoundedBottomLeftCorner = SC_MARK_LCORNERCURVE, + + //! A vertical line with a centre right curved line drawn in the + //! background colour. + LeftSideRoundedSplitter = SC_MARK_TCORNERCURVE, + + //! A drawn plus sign in a circle. + CircledPlus = SC_MARK_CIRCLEPLUS, + + //! A drawn plus sign in a connected box. + CircledPlusConnected = SC_MARK_CIRCLEPLUSCONNECTED, + + //! A drawn minus sign in a circle. + CircledMinus = SC_MARK_CIRCLEMINUS, + + //! A drawn minus sign in a connected circle. + CircledMinusConnected = SC_MARK_CIRCLEMINUSCONNECTED, + + //! No symbol is drawn but the line of text is drawn with the same + //! background colour. + Background = SC_MARK_BACKGROUND, + + //! Three drawn dots. + ThreeDots = SC_MARK_DOTDOTDOT, + + //! Three drawn arrows pointing right. + ThreeRightArrows = SC_MARK_ARROWS + }; + + //! This enum defines the different whitespace visibility modes. When + //! whitespace is visible spaces are displayed as small centred dots and + //! tabs are displayed as light arrows pointing to the right. + enum WhitespaceVisibility { + //! Whitespace is invisible. + WsInvisible = SCWS_INVISIBLE, + + //! Whitespace is always visible. + WsVisible = SCWS_VISIBLEALWAYS, + + //! Whitespace is visible after the whitespace used for indentation. + WsVisibleAfterIndent = SCWS_VISIBLEAFTERINDENT + }; + + //! This enum defines the different line wrap modes. + enum WrapMode { + //! Lines are not wrapped. + WrapNone = SC_WRAP_NONE, + + //! Lines are wrapped at word boundaries. + WrapWord = SC_WRAP_WORD, + + //! Lines are wrapped at character boundaries. + WrapCharacter = SC_WRAP_CHAR + }; + + //! This enum defines the different line wrap visual flags. + enum WrapVisualFlag { + //! No wrap flag is displayed. + WrapFlagNone, + + //! A wrap flag is displayed by the text. + WrapFlagByText, + + //! A wrap flag is displayed by the border. + WrapFlagByBorder + }; + + //! Construct an empty QsciScintilla with parent \a parent. + QsciScintilla(QWidget *parent = 0); + + //! Destroys the QsciScintilla instance. + virtual ~QsciScintilla(); + + //! Returns the API context, which is a list of words, before the position + //! \a pos in the document. The context can be used by auto-completion and + //! call tips to help to identify which API call the user is referring to. + //! In the default implementation the current lexer determines what + //! characters make up a word, and what characters determine the boundaries + //! of words (ie. the start characters). If there is no current lexer then + //! the context will consist of a single word. On return \a context_start + //! will contain the position in the document of the start of the context + //! and \a last_word_start will contain the position in the document of the + //! start of the last word of the context. + virtual QStringList apiContext(int pos, int &context_start, + int &last_word_start); + + //! Annotate the line \a line with the text \a text using the style number + //! \a style. + void annotate(int line, const QString &text, int style); + + //! Annotate the line \a line with the text \a text using the style \a + //! style. + void annotate(int line, const QString &text, const QsciStyle &style); + + //! Annotate the line \a line with the styled text \a text. + void annotate(int line, const QsciStyledText &text); + + //! Annotate the line \a line with the list of styled text \a text. + void annotate(int line, const QList &text); + + //! Returns the annotation on line \a line, if any. + QString annotation(int line) const; + + //! Returns the display style for annotations. + //! + //! \sa setAnnotationDisplay() + AnnotationDisplay annotationDisplay() const; + + //! The annotations on line \a line are removed. If \a line is negative + //! then all annotations are removed. + void clearAnnotations(int line = -1); + + //! Returns true if auto-completion lists are case sensitive. + //! + //! \sa setAutoCompletionCaseSensitivity() + bool autoCompletionCaseSensitivity() const; + + //! Returns true if auto-completion fill-up characters are enabled. + //! + //! \sa setAutoCompletionFillups(), setAutoCompletionFillupsEnabled() + bool autoCompletionFillupsEnabled() const; + + //! Returns true if the rest of the word to the right of the current cursor + //! is removed when an item from an auto-completion list is selected. + //! + //! \sa setAutoCompletionReplaceWord() + bool autoCompletionReplaceWord() const; + + //! Returns true if the only item in an auto-completion list with a single + //! entry is automatically used and the list not displayed. + //! + //! \sa setAutoCompletionShowSingle() + bool autoCompletionShowSingle() const; + + //! Returns the current source for the auto-completion list when it is + //! being displayed automatically as the user types. + //! + //! \sa setAutoCompletionSource() + AutoCompletionSource autoCompletionSource() const {return acSource;} + + //! Returns the current threshold for the automatic display of the + //! auto-completion list as the user types. + //! + //! \sa setAutoCompletionThreshold() + int autoCompletionThreshold() const {return acThresh;} + + //! Returns true if auto-indentation is enabled. + //! + //! \sa setAutoIndent() + bool autoIndent() const {return autoInd;} + + //! Returns true if the backspace key unindents a line instead of deleting + //! a character. The default is false. + //! + //! \sa setBackspaceUnindents(), tabIndents(), setTabIndents() + bool backspaceUnindents() const; + + //! Mark the beginning of a sequence of actions that can be undone by a + //! single call to undo(). + //! + //! \sa endUndoAction(), undo() + void beginUndoAction(); + + //! Returns the brace matching mode. + //! + //! \sa setBraceMatching() + BraceMatch braceMatching() const {return braceMode;} + + //! Returns the current call tip style. + //! + //! \sa setCallTipsStyle() + CallTipsStyle callTipsStyle() const {return call_tips_style;} + + //! Returns the maximum number of call tips that are displayed. + //! + //! \sa setCallTipsVisible() + int callTipsVisible() const {return maxCallTips;} + + //! Cancel any current auto-completion or user defined list. + void cancelList(); + + //! Returns true if the current language lexer is case sensitive. If there + //! is no current lexer then true is returned. + bool caseSensitive() const; + + //! Clear all current folds, i.e. ensure that all lines are displayed + //! unfolded. + //! + //! \sa setFolding() + void clearFolds(); + + //! Clear all registered images. + //! + //! \sa registerImage() + void clearRegisteredImages(); + + //! Returns the widget's text (ie. foreground) colour. + //! + //! \sa setColor() + QColor color() const; + + //! All the lines of the text have their end-of-lines converted to mode + //! \a mode. + //! + //! \sa eolMode(), setEolMode() + void convertEols(EolMode mode); + + //! Returns the attached document. + //! + //! \sa setDocument() + QsciDocument document() const {return doc;} + + //! Mark the end of a sequence of actions that can be undone by a single + //! call to undo(). + //! + //! \sa beginUndoAction(), undo() + void endUndoAction(); + + //! Returns the color of the marker used to show that a line has exceeded + //! the length set by setEdgeColumn(). + //! + //! \sa setEdgeColor(), \sa setEdgeColumn + QColor edgeColor() const; + + //! Returns the number of the column after which lines are considered to be + //! long. + //! + //! \sa setEdgeColumn() + int edgeColumn() const; + + //! Returns the edge mode which determines how long lines are marked. + //! + //! \sa setEdgeMode() + EdgeMode edgeMode() const; + + //! Set the default font. This has no effect if a language lexer has been + //! set. + void setFont(const QFont &f); + + //! Returns the end-of-line mode. + //! + //! \sa setEolMode() + EolMode eolMode() const; + + //! Returns the visibility of end-of-lines. + //! + //! \sa setEolVisibility() + bool eolVisibility() const; + + //! Find the next occurrence of the string \a expr and return true if + //! \a expr was found, otherwise returns false. If \a expr is found it + //! becomes the current selection. + //! + //! If \a re is true then \a expr is interpreted as a regular expression + //! rather than a simple string. + //! + //! If \a cs is true then the search is case sensitive. + //! + //! If \a wo is true then the search looks for whole word matches only, + //! otherwise it searches for any matching text. + //! + //! If \a wrap is true then the search wraps around the end of the text. + //! + //! If \a forward is true (the default) then the search is forward from the + //! starting position to the end of the text, otherwise it is backwards to + //! the beginning of the text. + //! + //! If either \a line or \a index are negative (the default) then the + //! search begins from the current cursor position. Otherwise the search + //! begins at position \a index of line \a line. + //! + //! If \a show is true (the default) then any text found is made visible + //! (ie. it is unfolded). + //! + //! \sa findNext(), replace() + virtual bool findFirst(const QString &expr, bool re, bool cs, bool wo, + bool wrap, bool forward = true, int line = -1, int index = -1, + bool show = true); + + //! Find the next occurence of the string found using findFirst(). + //! + //! \sa findFirst(), replace() + virtual bool findNext(); + + //! Returns the number of the first visible line. + int firstVisibleLine() const; + + //! Returns the current folding style. + //! + //! \sa setFolding() + FoldStyle folding() const {return fold;} + + //! Sets \a *line and \a *index to the line and index of the cursor. + //! + //! \sa setCursorPosition() + void getCursorPosition(int *line, int *index) const; + + //! If there is a selection, \a *lineFrom is set to the line number in + //! which the selection begins and \a *lineTo is set to the line number in + //! which the selection ends. (They could be the same.) \a *indexFrom is + //! set to the index at which the selection begins within \a *lineFrom, and + //! \a *indexTo is set to the index at which the selection ends within + //! \a *lineTo. If there is no selection, \a *lineFrom, \a *indexFrom, + //! \a *lineTo and \a *indexTo are all set to -1. + //! + //! \sa setSelection() + void getSelection(int *lineFrom, int *indexFrom, int *lineTo, + int *indexTo) const; + + //! Returns true if some text is selected. + //! + //! \sa selectedText() + bool hasSelectedText() const {return selText;} + + //! Returns the number of characters that line \a line is indented by. + //! + //! \sa setIndentation() + int indentation(int line) const; + + //! Returns true if the display of indentation guides is enabled. + //! + //! \sa setIndentationGuides() + bool indentationGuides() const; + + //! Returns true if indentations are created using tabs and spaces, rather + //! than just spaces. The default is true. + //! + //! \sa setIndentationsUseTabs() + bool indentationsUseTabs() const; + + //! Returns the indentation width in characters. The default is 0 which + //! means that the value returned by tabWidth() is actually used. + //! + //! \sa setIndentationWidth(), tabWidth() + int indentationWidth() const; + + //! Returns true if a call tip is currently active. + bool isCallTipActive() const; + + //! Returns true if an auto-completion or user defined list is currently + //! active. + bool isListActive() const; + + //! Returns true if the text has been modified. + //! + //! \sa setModified(), modificationChanged() + bool isModified() const; + + //! Returns true if the text edit is read-only. + //! + //! \sa setReadOnly() + bool isReadOnly() const; + + //! Returns true if there is something that can be redone. + //! + //! \sa redo() + bool isRedoAvailable() const; + + //! Returns true if there is something that can be undone. + //! + //! \sa undo() + bool isUndoAvailable() const; + + //! Returns true if text is interpreted as being UTF8 encoded. The default + //! is to interpret the text as Latin1 encoded. + //! + //! \sa setUtf8() + bool isUtf8() const; + + //! Returns true if character \a ch is a valid word character. + //! + //! \sa wordCharacters() + bool isWordCharacter(char ch) const; + + //! Returns the line which is at position \a pos or -1 if there is no line + //! at that position. + int lineAt(const QPoint &pos) const; + + //! QScintilla uses the combination of a line number and a character index + //! from the start of that line to specify the position of a character + //! within the text. The underlying Scintilla instead uses a byte index + //! from the start of the text. This will convert the \a position byte + //! index to the \a *line line number and \a *index character index. + //! + //! \sa positionFromLineIndex() + void lineIndexFromPosition(int position, int *line, int *index) const; + + //! Returns the length of line \a line int bytes or -1 if there is no such + //! line. In order to get the length in characters use text(line).length(). + int lineLength(int line) const; + + //! Returns the number of lines of text. + int lines() const; + + //! Returns the length of the text edit's text in bytes. In order to get + //! the length in characters use text().length(). + int length() const; + + //! Returns the current language lexer used to style text. If it is 0 then + //! syntax styling is disabled. + //! + //! \sa setLexer() + QsciLexer *lexer() const; + + //! Returns true if line numbers are enabled for margin \a margin. + //! + //! \sa setMarginLineNumbers(), marginType(), SCI_GETMARGINTYPEN + bool marginLineNumbers(int margin) const; + + //! Returns the marker mask of margin \a margin. + //! + //! \sa setMarginMask(), QsciMarker, SCI_GETMARGINMASKN + int marginMarkerMask(int margin) const; + + //! Returns true if margin \a margin is sensitive to mouse clicks. + //! + //! \sa setMarginSensitivity(), marginClicked(), SCI_GETMARGINTYPEN + bool marginSensitivity(int margin) const; + + //! Returns the type of margin \a margin. + //! + //! \sa setMarginType(), SCI_GETMARGINTYPEN + MarginType marginType(int margin) const; + + //! Returns the width in pixels of margin \a margin. + //! + //! \sa setMarginWidth(), SCI_GETMARGINWIDTHN + int marginWidth(int margin) const; + + //! Define a type of marker using the symbol \a sym with the marker number + //! \a mnr. If \a mnr is -1 then the marker number is automatically + //! allocated. The marker number is returned or -1 if too many types of + //! marker have been defined. + //! + //! Markers are small geometric symbols and characters used, for example, + //! to indicate the current line or, in debuggers, to indicate breakpoints. + //! If a margin has a width of 0 then its markers are not drawn, but their + //! background colours affect the background colour of the corresponding + //! line of text. + //! + //! There may be up to 32 types of marker defined at a time and each line + //! of text has a set of marker instances associated with it. Markers are + //! drawn according to their numerical identifier. Markers try to move + //! with their text by tracking where the start of their line moves to. + //! For example, when a line is deleted its markers are added to previous + //! line's markers. + //! + //! Each marker type is identified by a marker number. Each instance of a + //! marker is identified by a marker handle. + int markerDefine(MarkerSymbol sym, int mnr = -1); + + //! Define a marker using the character \a ch with the marker number + //! \a mnr. If \a mnr is -1 then the marker number is automatically + //! allocated. The marker number is returned or -1 if too many markers + //! have been defined. + int markerDefine(char ch, int mnr = -1); + + //! Define a marker using a copy of the pixmap \a pm with the marker number + //! \a mnr. If \a mnr is -1 then the marker number is automatically + //! allocated. The marker number is returned or -1 if too many markers + //! have been defined. + int markerDefine(const QPixmap &pm, int mnr = -1); + + //! Add an instance of marker number \a mnr to line number \a linenr. A + //! handle for the marker is returned which can be used to track the + //! marker's position, or -1 if the \a mnr was invalid. + //! + //! \sa markerDelete(), markerDeleteAll(), markerDeleteHandle() + int markerAdd(int linenr, int mnr); + + //! Returns the 32 bit mask of marker numbers at line number \a linenr. + //! + //! \sa markerAdd() + unsigned markersAtLine(int linenr) const; + + //! Delete all markers with the marker number \a mnr in the line \a linenr. + //! If \a mnr is -1 then delete all markers from line \a linenr. + //! + //! \sa markerAdd(), markerDeleteAll(), markerDeleteHandle() + void markerDelete(int linenr, int mnr = -1); + + //! Delete the all markers with the marker number \a mnr. If \a mnr is -1 + //! then delete all markers. + //! + //! \sa markerAdd(), markerDelete(), markerDeleteHandle() + void markerDeleteAll(int mnr = -1); + + //! Delete the the marker instance with the marker handle \a mhandle. + //! + //! \sa markerAdd(), markerDelete(), markerDeleteAll() + void markerDeleteHandle(int mhandle); + + //! Return the line number that contains the marker instance with the + //! marker handle \a mhandle. + int markerLine(int mhandle) const; + + //! Return the number of the next line to contain at least one marker from + //! a 32 bit mask of markers. \a linenr is the line number to start the + //! search from. \a mask is the mask of markers to search for. + //! + //! \sa markerFindPrevious() + int markerFindNext(int linenr, unsigned mask) const; + + //! Return the number of the previous line to contain at least one marker + //! from a 32 bit mask of markers. \a linenr is the line number to start + //! the search from. \a mask is the mask of markers to search for. + //! + //! \sa markerFindNext() + int markerFindPrevious(int linenr, unsigned mask) const; + + //! Returns the widget's paper (ie. background) colour. + //! + //! \sa setPaper() + QColor paper() const; + + //! QScintilla uses the combination of a line number and a character index + //! from the start of that line to specify the position of a character + //! within the text. The underlying Scintilla instead uses a byte index + //! from the start of the text. This will return the byte index + //! corresponding to the \a line line number and \a index character index. + //! + //! \sa lineIndexFromPosition() + int positionFromLineIndex(int line, int index) const; + + //! Reads the current document from the \a io device and returns true if + //! there was no error. + //! + //! \sa write() + bool read(QIODevice *io); + + //! Recolours the document between the \a start and \a end positions. + //! \a start defaults to the start of the document and \a end defaults to + //! the end of the document. + virtual void recolor(int start = 0, int end = -1); + + //! Register an image \a pm with ID \a id. Registered images can be + //! displayed in auto-completion lists. + //! + //! \sa clearRegisteredImages(), QsciLexer::apiLoad() + void registerImage(int id, const QPixmap &pm); + + //! Replace the current selection, set by a previous call to findFirst() or + //! findNext(), with \a replaceStr. + //! + //! \sa findFirst(), findNext() + virtual void replace(const QString &replaceStr); + + //! Reset the fold margin colours to their defaults. + //! + //! \sa setFoldMarginColors() + void resetFoldMarginColors(); + + //! The fold margin may be drawn as a one pixel sized checkerboard pattern + //! of two colours, \a fore and \a back. + //! + //! \sa resetFoldMarginColors() + void setFoldMarginColors(const QColor &fore, const QColor &back); + + //! Set the display style for annotations. The default is + //! AnnotationStandard. + //! + //! \sa annotationDisplay() + void setAnnotationDisplay(AnnotationDisplay display); + + //! Enable the use of fill-up characters, either those explicitly set or + //! those set by a lexer. By default, fill-up characters are disabled. + //! + //! \sa autoCompletionFillupsEnabled(), setAutoCompletionFillups() + void setAutoCompletionFillupsEnabled(bool enabled); + + //! A fill-up character is one that, when entered while an auto-completion + //! list is being displayed, causes the currently selected item from the + //! list to be added to the text followed by the fill-up character. + //! \a fillups is the set of fill-up characters. If a language lexer has + //! been set then this is ignored and the lexer defines the fill-up + //! characters. The default is that no fill-up characters are set. + //! + //! \sa autoCompletionFillupsEnabled(), setAutoCompletionFillupsEnabled() + void setAutoCompletionFillups(const char *fillups); + + //! A word separator is a sequence of characters that, when entered, causes + //! the auto-completion list to be displayed. If a language lexer has been + //! set then this is ignored and the lexer defines the word separators. + //! The default is that no word separators are set. + //! + //! \sa setAutoCompletionThreshold() + void setAutoCompletionWordSeparators(const QStringList &separators); + + //! Set the background colour of call tips to \a col. The default is + //! white. + void setCallTipsBackgroundColor(const QColor &col); + + //! Set the foreground colour of call tips to \a col. The default is + //! mid-gray. + void setCallTipsForegroundColor(const QColor &col); + + //! Set the highlighted colour of call tip text to \a col. The default is + //! dark blue. + void setCallTipsHighlightColor(const QColor &col); + + //! Set the current call tip style. The default is CallTipsNoContext. + //! + //! \sa callTipsStyle() + void setCallTipsStyle(CallTipsStyle style); + + //! Set the maximum number of call tips that are displayed to \a nr. If + //! the maximum number is 0 then all applicable call tips are displayed. + //! If the maximum number is -1 then one call tip will be displayed with up + //! and down arrows that allow the use to scroll through the full list. + //! The default is -1. + //! + //! \sa callTipsVisible() + void setCallTipsVisible(int nr); + + //! Attach the document \a document, replacing the currently attached + //! document. + //! + //! \sa document() + void setDocument(const QsciDocument &document); + + //! Set the color of the marker used to show that a line has exceeded the + //! length set by setEdgeColumn(). + //! + //! \sa edgeColor(), \sa setEdgeColumn + void setEdgeColor(const QColor &col); + + //! Set the number of the column after which lines are considered to be + //! long. + //! + //! \sa edgeColumn() + void setEdgeColumn(int colnr); + + //! Set the edge mode which determines how long lines are marked. + //! + //! \sa edgeMode() + void setEdgeMode(EdgeMode mode); + + //! Set the margin text of line \a line with the text \a text using the + //! style number \a style. + void setMarginText(int line, const QString &text, int style); + + //! Set the margin text of line \a line with the text \a text using the + //! style \a style. + void setMarginText(int line, const QString &text, const QsciStyle &style); + + //! Set the margin text of line \a line with the styled text \a text. + void setMarginText(int line, const QsciStyledText &text); + + //! Set the margin text of line \a line with the list of styled text \a + //! text. + void setMarginText(int line, const QList &text); + + //! Set the type of margin \a margin to type \a type. + //! + //! \sa marginType(), SCI_SETMARGINTYPEN + void setMarginType(int margin, MarginType type); + + //! The margin text on line \a line is removed. If \a line is negative + //! then all margin text is removed. + void clearMarginText(int line = -1); + + //! Set the background colour, including the alpha component, of marker + //! \a mnr to \a col. If \a mnr is -1 then the colour of all markers is + //! set. The default is white. + //! + //! \sa setMarkerForegroundColor() + void setMarkerBackgroundColor(const QColor &col, int mnr = -1); + + //! Set the foreground colour of marker \a mnr to \a col. If \a mnr is -1 + //! then the colour of all markers is set. The default is black. + //! + //! \sa setMarkerBackgroundColor() + void setMarkerForegroundColor(const QColor &col, int mnr = -1); + + //! Set the background colour used to display matched braces to \a col. + //! The default is white. + //! + //! \sa setMatchedBraceForegroundColor() + void setMatchedBraceBackgroundColor(const QColor &col); + + //! Set the foreground colour used to display matched braces to \a col. + //! The default is red. + //! + //! \sa setMatchedBraceBackgroundColor() + void setMatchedBraceForegroundColor(const QColor &col); + + //! Set the background colour used to display unmatched braces to \a col. + //! The default is white. + //! + //! \sa setUnmatchedBraceForegroundColor() + void setUnmatchedBraceBackgroundColor(const QColor &col); + + //! Set the foreground colour used to display unmatched braces to \a col. + //! The default is blue. + //! + //! \sa setUnmatchedBraceBackgroundColor() + void setUnmatchedBraceForegroundColor(const QColor &col); + + //! Set the visual flags displayed when a line is wrapped. \a eflag + //! determines if and where the flag at the end of a line is displayed. + //! \a sflag determines if and where the flag at the start of a line is + //! displayed. \a sindent is the number of characters a wrapped line is + //! indented by. By default no visual flags are displayed. + void setWrapVisualFlags(WrapVisualFlag eflag, + WrapVisualFlag sflag = WrapFlagNone, int sindent = 0); + + //! Returns the selected text or an empty string if there is no currently + //! selected text. + //! + //! \sa hasSelectedText() + QString selectedText() const; + + //! Returns whether or not the selection is drawn up to the right hand + //! border. + //! + //! \sa setSelectionToEol() + bool selectionToEol() const; + + //! Sets whether or not the selection is drawn up to the right hand border. + //! \a filled is set if the selection is drawn to the border. + //! + //! \sa selectionToEol() + void setSelectionToEol(bool filled); + + //! Displays a user defined list which can be interacted with like an + //! auto-completion list. \a id is an identifier for the list which is + //! passed as an argument to the userListActivated() signal and must be at + //! least 1. \a list is the text with which the list is populated. + //! + //! \sa cancelList(), isListActive(), userListActivated() + void showUserList(int id, const QStringList &list); + + //! The standard command set is returned. + QsciCommandSet *standardCommands() const {return stdCmds;} + + //! Returns true if the tab key indents a line instead of inserting a tab + //! character. The default is true. + //! + //! \sa setTabIndents(), backspaceUnindents(), setBackspaceUnindents() + bool tabIndents() const; + + //! Returns the tab width in characters. The default is 8. + //! + //! \sa setTabWidth() + int tabWidth() const; + + //! Returns the text of the current document. + //! + //! \sa setText() + QString text() const; + + //! \overload + //! + //! Returns the text of line \a line. + //! + //! \sa setText() + QString text(int line) const; + + //! Returns the height in pixels of the text in line number \a linenr. + int textHeight(int linenr) const; + + //! Returns the visibility of whitespace. + //! + //! \sa setWhitespaceVisibility() + WhitespaceVisibility whitespaceVisibility() const; + + //! Returns the word at the \a point screen coordinates. + QString wordAtPoint(const QPoint &point) const; + + //! Returns the set of valid word character as defined by the current + //! language lexer. If there is no current lexer then the set contains an + //! an underscore, numbers and all upper and lower case alphabetic + //! characters. + //! + //! \sa isWordCharacter() + const char *wordCharacters() const; + + //! Returns the line wrap mode. + //! + //! \sa setWrapMode() + WrapMode wrapMode() const; + + //! Writes the current document to the \a io device and returns true if + //! there was no error. + //! + //! \sa read() + bool write(QIODevice *io) const; + +public slots: + //! Appends the text \a text to the end of the text edit. Note that the + //! undo/redo history is cleared by this function. + virtual void append(const QString &text); + + //! Display an auto-completion list based on any installed APIs, the + //! current contents of the document and the characters immediately to the + //! left of the cursor. + //! + //! \sa autoCompleteFromAPIs(), autoCompleteFromDocument() + virtual void autoCompleteFromAll(); + + //! Display an auto-completion list based on any installed APIs and the + //! characters immediately to the left of the cursor. + //! + //! \sa autoCompleteFromAll(), autoCompleteFromDocument(), + //! setAutoCompletionAPIs() + virtual void autoCompleteFromAPIs(); + + //! Display an auto-completion list based on the current contents of the + //! document and the characters immediately to the left of the cursor. + //! + //! \sa autoCompleteFromAll(), autoCompleteFromAPIs() + virtual void autoCompleteFromDocument(); + + //! Display a call tip based on the the characters immediately to the left + //! of the cursor. + virtual void callTip(); + + //! Deletes all the text in the text edit. + virtual void clear(); + + //! Copies any selected text to the clipboard. + //! + //! \sa copyAvailable(), cut(), paste() + virtual void copy(); + + //! Copies any selected text to the clipboard and then deletes the text. + //! + //! \sa copy(), paste() + virtual void cut(); + + //! Ensures that the cursor is visible. + virtual void ensureCursorVisible(); + + //! Ensures that the line number \a line is visible. + virtual void ensureLineVisible(int line); + + //! If any lines are currently folded then they are all unfolded. + //! Otherwise all lines are folded. This has the same effect as clicking + //! in the fold margin with the shift and control keys pressed. If + //! \a children is not set (the default) then only the top level fold + //! points are affected, otherwise the state of all fold points are + //! changed. + virtual void foldAll(bool children = false); + + //! If the line \a line is folded then it is unfolded. Otherwise it is + //! folded. This has the same effect as clicking in the fold margin. + virtual void foldLine(int line); + + //! Increases the indentation of line \a line by an indentation width. + //! + //! \sa unindent() + virtual void indent(int line); + + //! Insert the text \a text at the current position. + virtual void insert(const QString &text); + + //! Insert the text \a text in the line \a line at the position + //! \a index. + virtual void insertAt(const QString &text, int line, int index); + + //! If the cursor is either side of a brace character then move it to the + //! position of the corresponding brace. + virtual void moveToMatchingBrace(); + + //! Pastes any text from the clipboard into the text edit at the current + //! cursor position. + //! + //! \sa copy(), cut() + virtual void paste(); + + //! Redo the last change or sequence of changes. + //! + //! \sa isRedoAvailable() + virtual void redo(); + + //! Removes any selected text. + virtual void removeSelectedText(); + + //! Resets the background colour of selected text to the default. + //! + //! \sa setSelectionBackgroundColor(), resetSelectionForegroundColor() + virtual void resetSelectionBackgroundColor(); + + //! Resets the foreground colour of selected text to the default. + //! + //! \sa setSelectionForegroundColor(), resetSelectionBackgroundColor() + virtual void resetSelectionForegroundColor(); + + //! If \a select is true (the default) then all the text is selected. If + //! \a select is false then any currently selected text is deselected. + virtual void selectAll(bool select = true); + + //! If the cursor is either side of a brace character then move it to the + //! position of the corresponding brace and select the text between the + //! braces. + virtual void selectToMatchingBrace(); + + //! If \a cs is true then auto-completion lists are case sensitive. The + //! default is true. This is ignored when the auto-completion source is an + //! installed API as the corresponding language determines the case + //! sensitivity. + //! + //! \sa autoCompletionCaseSensitivity() + virtual void setAutoCompletionCaseSensitivity(bool cs); + + //! If \a replace is true then when an item from an auto-completion list is + //! selected, the rest of the word to the right of the current cursor is + //! removed. The default is false. + //! + //! \sa autoCompletionReplaceWord() + virtual void setAutoCompletionReplaceWord(bool replace); + + //! If \a single is true then when there is only a single entry in an + //! auto-completion list it is automatically used and the list is not + //! displayed. This only has an effect when auto-completion is explicitly + //! requested (using autoCompleteFromAPIs() and autoCompleteFromDocument()) + //! and has no effect when auto-completion is triggered as the user types. + //! The default is false. + //! + //! \sa autoCompletionShowSingle() + virtual void setAutoCompletionShowSingle(bool single); + + //! Sets the source for the auto-completion list when it is being displayed + //! automatically as the user types to \a source. The default is AcsNone, + //! ie. it is disabled. + //! + //! \sa autoCompletionSource() + virtual void setAutoCompletionSource(AutoCompletionSource source); + + //! Sets the threshold for the automatic display of the auto-completion + //! list as the user types to \a thresh. The threshold is the number of + //! characters that the user must type before the list is displayed. If + //! the threshold is less than or equal to 0 then the list is disabled. + //! The default is -1. + //! + //! \sa autoCompletionThreshold(), setAutoCompletionWordSeparators() + virtual void setAutoCompletionThreshold(int thresh); + + //! If \a autoindent is true then auto-indentation is enabled. The default + //! is false. + //! + //! \sa autoIndent() + virtual void setAutoIndent(bool autoindent); + + //! Sets the brace matching mode to \a bm. The default is NoBraceMatching. + //! + //! \sa braceMatching() + virtual void setBraceMatching(BraceMatch bm); + + //! If \a deindent is true then the backspace key will unindent a line + //! rather then delete a character. + //! + //! \sa backspaceUnindents(), tabIndents(), setTabIndents() + virtual void setBackspaceUnindents(bool unindent); + + //! Sets the foreground colour of the caret to \a col. + virtual void setCaretForegroundColor(const QColor &col); + + //! Sets the background colour, including the alpha component, of the line + //! containing the caret to \a col. + //! + //! \sa setCaretLineVisible() + virtual void setCaretLineBackgroundColor(const QColor &col); + + //! Enables or disables, according to \a enable, the background color of + //! the line containing the caret. + //! + //! \sa setCaretLineBackgroundColor() + virtual void setCaretLineVisible(bool enable); + + //! Sets the width of the caret to \a width pixels. A \a width of 0 makes + //! the caret invisible. + virtual void setCaretWidth(int width); + + //! The widget's text (ie. foreground) colour is set to \a c. This has no + //! effect if a language lexer has been set. + //! + //! \sa color() + virtual void setColor(const QColor &c); + + //! Sets the cursor to the line \a line at the position \a index. + //! + //! \sa getCursorPosition() + virtual void setCursorPosition(int line, int index); + + //! Sets the end-of-line mode to \a mode. The default is the platform's + //! natural mode. + //! + //! \sa eolMode() + virtual void setEolMode(EolMode mode); + + //! If \a visible is true then end-of-lines are made visible. The default + //! is that they are invisible. + //! + //! \sa eolVisibility() + virtual void setEolVisibility(bool visible); + + //! Sets the folding style for margin \a margin to \a fold. The default + //! style is NoFoldStyle (ie. folding is disabled) and the default margin + //! is 2. + //! + //! \sa folding() + virtual void setFolding(FoldStyle fold, int margin = 2); + + //! Sets the indentation of line \a line to \a indentation characters. + //! + //! \sa indentation() + virtual void setIndentation(int line, int indentation); + + //! Enables or disables, according to \a enable, this display of + //! indentation guides. + //! + //! \sa indentationGuides() + virtual void setIndentationGuides(bool enable); + + //! Set the background colour of indentation guides to \a col. + //! + //! \sa setIndentationGuidesForegroundColor() + virtual void setIndentationGuidesBackgroundColor(const QColor &col); + + //! Set the foreground colour of indentation guides to \a col. + //! + //! \sa setIndentationGuidesBackgroundColor() + virtual void setIndentationGuidesForegroundColor(const QColor &col); + + //! If \a tabs is true then indentations are created using tabs and spaces, + //! rather than just spaces. + //! + //! \sa indentationsUseTabs() + virtual void setIndentationsUseTabs(bool tabs); + + //! Sets the indentation width to \a width characters. If \a width is 0 + //! then the value returned by tabWidth() is used. + //! + //! \sa indentationWidth(), tabWidth() + virtual void setIndentationWidth(int width); + + //! Sets the specific language lexer used to style text to \a lex. If + //! \a lex is 0 then syntax styling is disabled. + //! + //! \sa lexer() + virtual void setLexer(QsciLexer *lexer = 0); + + //! Set the background colour of all margins to \a col. The default is a + //! gray. + //! + //! \sa setMarginsForegroundColor() + virtual void setMarginsBackgroundColor(const QColor &col); + + //! Set the font used in all margins to \a f. + virtual void setMarginsFont(const QFont &f); + + //! Set the foreground colour of all margins to \a col. The default is + //! black. + //! + //! \sa setMarginsBackgroundColor() + virtual void setMarginsForegroundColor(const QColor &col); + + //! Enables or disables, according to \a lnrs, the display of line numbers + //! in margin \a margin. + //! + //! \sa marginLineNumbers(), setMarginType(), SCI_SETMARGINTYPEN + virtual void setMarginLineNumbers(int margin, bool lnrs); + + //! Sets the marker mask of margin \a margin to \a mask. Only those + //! markers whose bit is set in the mask are displayed in the margin. + //! + //! \sa marginMarkerMask(), QsciMarker, SCI_SETMARGINMASKN + virtual void setMarginMarkerMask(int margin, int mask); + + //! Enables or disables, according to \a sens, the sensitivity of margin + //! \a margin to mouse clicks. If the user clicks in a sensitive margin + //! the marginClicked() signal is emitted. + //! + //! \sa marginSensitivity(), marginClicked(), SCI_SETMARGINSENSITIVEN + virtual void setMarginSensitivity(int margin, bool sens); + + //! Sets the width of margin \a margin to \a width pixels. If the width of + //! a margin is 0 then it is not displayed. + //! + //! \sa marginWidth(), SCI_SETMARGINWIDTHN + virtual void setMarginWidth(int margin, int width); + + //! Sets the width of margin \a margin so that it is wide enough to display + //! \a s in the current margin font. + //! + //! \sa marginWidth(), SCI_SETMARGINWIDTHN + virtual void setMarginWidth(int margin, const QString &s); + + //! Sets the modified state of the text edit to \a m. Note that it is only + //! possible to clear the modified state (where \a m is false). Attempts + //! to set the modified state (where \a m is true) are ignored. + //! + //! \sa isModified(), modificationChanged() + virtual void setModified(bool m); + + //! The widget's paper (ie. background) colour is set to \a c. This has no + //! effect if a language lexer has been set. + //! + //! \sa paper() + virtual void setPaper(const QColor &c); + + //! Sets the read-only state of the text edit to \a ro. + //! + //! \sa isReadOnly() + virtual void setReadOnly(bool ro); + + //! Sets the selection which starts at position \a indexFrom in line + //! \a lineFrom and ends at position \a indexTo in line \a lineTo. The + //! cursor is moved to position \a indexTo in \a lineTo. + //! + //! \sa getSelection() + virtual void setSelection(int lineFrom, int indexFrom, int lineTo, + int indexTo); + + //! Sets the background colour, including the alpha component, of selected + //! text to \a col. + //! + //! \sa resetSelectionBackgroundColor(), setSelectionForegroundColor() + virtual void setSelectionBackgroundColor(const QColor &col); + + //! Sets the foreground colour of selected text to \a col. + //! + //! \sa resetSelectionForegroundColor(), setSelectionBackgroundColor() + virtual void setSelectionForegroundColor(const QColor &col); + + //! If \a indent is true then the tab key will indent a line rather than + //! insert a tab character. + //! + //! \sa tabIndents(), backspaceUnindents(), setBackspaceUnindents() + virtual void setTabIndents(bool indent); + + //! Sets the tab width to \a width characters. + //! + //! \sa tabWidth() + virtual void setTabWidth(int width); + + //! Replaces all of the current text with \a text. Note that the + //! undo/redo history is cleared by this function. + //! + //! \sa text() + virtual void setText(const QString &text); + + //! Sets the current text encoding. If \a cp is true then UTF8 is used, + //! otherwise Latin1 is used. + //! + //! \sa isUtf8() + virtual void setUtf8(bool cp); + + //! Sets the visibility of whitespace to mode \a mode. The default is that + //! whitespace is invisible. + //! + //! \sa whitespaceVisibility() + virtual void setWhitespaceVisibility(WhitespaceVisibility mode); + + //! Sets the line wrap mode to mode \a mode. The default is that lines are + //! not wrapped. + //! + //! \sa wrapMode() + virtual void setWrapMode(WrapMode mode); + + //! Undo the last change or sequence of changes. + //! + //! Scintilla has multiple level undo and redo. It will continue to record + //! undoable actions until memory runs out. Sequences of typing or + //! deleting are compressed into single actions to make it easier to undo + //! and redo at a sensible level of detail. Sequences of actions can be + //! combined into actions that are undone as a unit. These sequences occur + //! between calls to beginUndoAction() and endUndoAction(). These + //! sequences can be nested and only the top level sequences are undone as + //! units. + //! + //! \sa beginUndoAction(), endUndoAction(), isUndoAvailable() + virtual void undo(); + + //! Decreases the indentation of line \a line by an indentation width. + //! + //! \sa indent() + virtual void unindent(int line); + + //! Zooms in on the text by by making the base font size \a range points + //! larger and recalculating all font sizes. + //! + //! \sa zoomOut(), zoomTo() + virtual void zoomIn(int range); + + //! \overload + //! + //! Zooms in on the text by by making the base font size one point larger + //! and recalculating all font sizes. + virtual void zoomIn(); + + //! Zooms out on the text by by making the base font size \a range points + //! smaller and recalculating all font sizes. + //! + //! \sa zoomIn(), zoomTo() + virtual void zoomOut(int range); + + //! \overload + //! + //! Zooms out on the text by by making the base font size one point larger + //! and recalculating all font sizes. + virtual void zoomOut(); + + //! Zooms the text by making the base font size \a size points and + //! recalculating all font sizes. + //! + //! \sa zoomIn(), zoomOut() + virtual void zoomTo(int size); + +signals: + //! This signal is emitted whenever the cursor position changes. \a line + //! contains the line number and \a pos contains the character position + //! within the line. + void cursorPositionChanged(int line, int pos); + + //! This signal is emitted whenever text is selected or de-selected. + //! \a yes is true if text has been selected and false if text has been + //! deselected. If \a yes is true then copy() can be used to copy the + //! selection to the clipboard. If \a yes is false then copy() does + //! nothing. + //! + //! \sa copy(), selectionChanged() + void copyAvailable(bool yes); + + //! This signal is emitted whenever the number of lines of text changes. + void linesChanged(); + + //! This signal is emitted whenever the user clicks on a sensitive margin. + //! \a margin is the margin. \a line is the number of the line where the + //! user clicked. \a state is the state of the modifier keys + //! (Qt::ShiftModifier, Qt::ControlModifier and Qt::AltModifer) when the + //! user clicked. + //! + //! \sa marginSensitivity(), setMarginSensitivity() + void marginClicked(int margin, int line, Qt::KeyboardModifiers state); + + //! This signal is emitted whenever the user attempts to modify read-only + //! text. + //! + //! \sa isReadOnly(), setReadOnly() + void modificationAttempted(); + + //! This signal is emitted whenever the modification state of the text + //! changes. \a m is true if the text has been modified. + //! + //! \sa isModified(), setModified() + void modificationChanged(bool m); + + //! This signal is emitted whenever the selection changes. + //! + //! \sa copyAvailable() + void selectionChanged(); + + //! This signal is emitted whenever the text in the text edit changes. + void textChanged(); + + //! This signal is emitted when an item in a user defined list is activated + //! (selected). \a id is the list identifier. \a string is the text of + //! the item. + //! + //! \sa showUserList() + void userListActivated(int id, const QString &string); + +private slots: + void handleCallTipClick(int dir); + void handleCharAdded(int charadded); + void handleMarginClick(int pos, int margin, int modifiers); + void handleModified(int pos, int mtype, const char *text, int len, + int added, int line, int foldNow, int foldPrev, int token, + int annotationLinesAdded); + void handlePropertyChange(const char *prop, const char *val); + void handleSavePointReached(); + void handleSavePointLeft(); + void handleSelectionChanged(bool yes); + void handleAutoCompletionSelection(); + void handleUserListSelection(const char *text, int id); + + void handleStyleColorChange(const QColor &c, int style); + void handleStyleEolFillChange(bool eolfill, int style); + void handleStyleFontChange(const QFont &f, int style); + void handleStylePaperChange(const QColor &c, int style); + + void handleUpdateUI(); + +private: + typedef QByteArray ScintillaString; + + void detachLexer(); + + enum IndentState { + isNone, + isKeywordStart, + isBlockStart, + isBlockEnd + }; + + void maintainIndentation(char ch, long pos); + void autoIndentation(char ch, long pos); + void autoIndentLine(long pos, int line, int indent); + int blockIndent(int line); + IndentState getIndentState(int line); + bool rangeIsWhitespace(long spos, long epos); + int findStyledWord(const char *text, int style, const char *words); + + void checkMarker(int &mnr); + int currentIndent() const; + int indentWidth() const; + bool doFind(); + int simpleFind(); + void foldClick(int lineClick, int bstate); + void foldChanged(int line, int levelNow, int levelPrev); + void foldExpand(int &line, bool doExpand, bool force = false, + int visLevels = 0, int level = -1); + void setFoldMarker(int marknr, int mark = SC_MARK_EMPTY); + QString convertTextS2Q(const char *s) const; + ScintillaString convertTextQ2S(const QString &q) const; + void setLexerStyle(int style); + void setStylesFont(const QFont &f, int style); + + void braceMatch(); + bool findMatchingBrace(long &brace, long &other, BraceMatch mode); + long checkBrace(long pos, int brace_style, bool &colonMode); + void gotoMatchingBrace(bool select); + + void startAutoCompletion(AutoCompletionSource acs, bool checkThresh, + bool single); + + int adjustedCallTipPosition(int ctshift) const; + bool getSeparator(int &pos) const; + QString getWord(int &pos) const; + char getCharacter(int &pos) const; + bool isStartChar(char ch) const; + + bool ensureRW(); + void insertAtPos(const QString &text, int pos); + + ScintillaString styleText(const QList &styled_text, + char **styles, int style_offset = 0); + + struct FindState + { + FindState() : inProgress(0) {} + + bool inProgress; + QString expr; + bool wrap; + bool forward; + int flags; + long startpos; + long endpos; + bool show; + }; + + FindState findState; + + unsigned allocatedMarkers; + int oldPos; + int ctPos; + bool selText; + FoldStyle fold; + int foldmargin; + bool autoInd; + BraceMatch braceMode; + AutoCompletionSource acSource; + int acThresh; + QStringList wseps; + const char *wchars; + CallTipsStyle call_tips_style; + int maxCallTips; + QStringList ct_entries; + int ct_cursor; + QList ct_shifts; + bool showSingle; + QPointer lex; + QsciCommandSet *stdCmds; + QsciDocument doc; + QColor nl_text_colour; + QColor nl_paper_colour; + QByteArray explicit_fillups; + bool fillups_enabled; + + // The following allow ListBoxQt to distinguish between an auto-completion + // list and a user list, and to return the full selection of an + // auto-completion list. + friend class ListBoxQt; + + QString acSelection; + bool isAutoCompletionList() const; + + QsciScintilla(const QsciScintilla &); + QsciScintilla &operator=(const QsciScintilla &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciscintillabase.cpp b/harbour/contrib/hbide/qscintilla/qt/qsciscintillabase.cpp new file mode 100644 index 0000000000..a456ff668d --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciscintillabase.cpp @@ -0,0 +1,682 @@ +// This module implements the "official" low-level API. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qsciscintillabase.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ScintillaQt.h" + + +// The #defines in Scintilla.h and the enums in qsciscintillabase.h conflict +// (because we want to use the same names) so we have to undefine those we use +// in this file. +#undef SCI_SETCARETPERIOD +#undef SCK_DOWN +#undef SCK_UP +#undef SCK_LEFT +#undef SCK_RIGHT +#undef SCK_HOME +#undef SCK_END +#undef SCK_PRIOR +#undef SCK_NEXT +#undef SCK_DELETE +#undef SCK_INSERT +#undef SCK_ESCAPE +#undef SCK_BACK +#undef SCK_TAB +#undef SCK_RETURN +#undef SCK_ADD +#undef SCK_SUBTRACT +#undef SCK_DIVIDE +#undef SCK_WIN +#undef SCK_RWIN +#undef SCK_MENU + + +// Remember if we have linked the lexers. +static bool lexersLinked = false; + +// The list of instances. +static QList poolList; + + +// The ctor. +QsciScintillaBase::QsciScintillaBase(QWidget *parent) + : QAbstractScrollArea(parent) +{ + connect(verticalScrollBar(), SIGNAL(valueChanged(int)), + SLOT(handleVSb(int))); + + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), + SLOT(handleHSb(int))); + + setAcceptDrops(true); + setFocusPolicy(Qt::WheelFocus); + setAttribute(Qt::WA_KeyCompression); + + viewport()->setBackgroundRole(QPalette::Base); + viewport()->setMouseTracking(true); + viewport()->setAttribute(Qt::WA_NoSystemBackground); + + triple_click.setSingleShot(true); + + sci = new ScintillaQt(this); + + SendScintilla(SCI_SETCARETPERIOD, QApplication::cursorFlashTime() / 2); + + // Make sure the lexers are linked in. + if (!lexersLinked) + { + Scintilla_LinkLexers(); + lexersLinked = true; + } + + QClipboard *cb = QApplication::clipboard(); + + if (cb->supportsSelection()) + connect(cb, SIGNAL(selectionChanged()), SLOT(handleSelection())); + + // Add it to the pool. + poolList.append(this); +} + + +// The dtor. +QsciScintillaBase::~QsciScintillaBase() +{ + // Remove it from the pool. + poolList.removeAt(poolList.indexOf(this)); + + delete sci; +} + + +// Return an instance from the pool. +QsciScintillaBase *QsciScintillaBase::pool() +{ + return poolList.first(); +} + + +// Send a message to the real Scintilla widget using the low level Scintilla +// API. +long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, + long lParam) const +{ + return sci->WndProc(msg, wParam, lParam); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, + void *lParam) const +{ + return sci->WndProc(msg, wParam, reinterpret_cast(lParam)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, + const char *lParam) const +{ + return sci->WndProc(msg, wParam, reinterpret_cast(lParam)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, + const char *lParam) const +{ + return sci->WndProc(msg, static_cast(0), + reinterpret_cast(lParam)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, const char *wParam, + const char *lParam) const +{ + return sci->WndProc(msg, reinterpret_cast(wParam), + reinterpret_cast(lParam)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, long wParam) const +{ + return sci->WndProc(msg, static_cast(wParam), + static_cast(0)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, int wParam) const +{ + return sci->WndProc(msg, static_cast(wParam), + static_cast(0)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, long cpMin, long cpMax, + char *lpstrText) const +{ + TextRange tr; + + tr.chrg.cpMin = cpMin; + tr.chrg.cpMax = cpMax; + tr.lpstrText = lpstrText; + + return sci->WndProc(msg, static_cast(0), + reinterpret_cast(&tr)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, + const QColor &col) const +{ + sptr_t lParam = (col.blue() << 16) | (col.green() << 8) | col.red(); + + return sci->WndProc(msg, wParam, lParam); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, const QColor &col) const +{ + uptr_t wParam = (col.blue() << 16) | (col.green() << 8) | col.red(); + + return sci->WndProc(msg, wParam, static_cast(0)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, + QPainter *hdc, const QRect &rc, long cpMin, long cpMax) const +{ + RangeToFormat rf; + + rf.hdc = rf.hdcTarget = reinterpret_cast(hdc); + + rf.rc.left = rc.left(); + rf.rc.top = rc.top(); + rf.rc.right = rc.right() + 1; + rf.rc.bottom = rc.bottom() + 1; + + rf.chrg.cpMin = cpMin; + rf.chrg.cpMax = cpMax; + + return sci->WndProc(msg, wParam, reinterpret_cast(&rf)); +} + + +// Overloaded message send. +long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, + const QPixmap &lParam) const +{ + return sci->WndProc(msg, wParam, reinterpret_cast(&lParam)); +} + + +// Send a message to the real Scintilla widget using the low level Scintilla +// API that returns a pointer result. +void *QsciScintillaBase::SendScintillaPtrResult(unsigned int msg) const +{ + return reinterpret_cast(sci->WndProc(msg, static_cast(0), + static_cast(0))); +} + + +// Handle the timer on behalf of the ScintillaQt instance. +void QsciScintillaBase::handleTimer() +{ + sci->Tick(); +} + + +// Re-implemented to handle the context menu. +void QsciScintillaBase::contextMenuEvent(QContextMenuEvent *e) +{ + sci->ContextMenu(Point(e->globalX(), e->globalY())); +} + + +// Re-implemented to tell the widget it has the focus. +void QsciScintillaBase::focusInEvent(QFocusEvent *) +{ + sci->SetFocusState(true); +} + + +// Re-implemented to tell the widget it has lost the focus. +void QsciScintillaBase::focusOutEvent(QFocusEvent *) +{ + // If an autocompletion list is being displayed (a Qt::Tool) and it is + // clicked on, then we receive this event but the current focus event is 0. + // We detect this and don't tell Scintilla as it would immediately destroy + // the list. + if (qApp->focusWidget()) + sci->SetFocusState(false); +} + + +// Re-implemented to make sure tabs are passed to the editor. +bool QsciScintillaBase::focusNextPrevChild(bool next) +{ + if (!sci->pdoc->IsReadOnly()) + return false; + + return QAbstractScrollArea::focusNextPrevChild(next); +} + + +// Handle the selection changing. +void QsciScintillaBase::handleSelection() +{ + if (!QApplication::clipboard()->ownsSelection()) + sci->UnclaimSelection(); +} + + +// Handle key presses. +void QsciScintillaBase::keyPressEvent(QKeyEvent *e) +{ + unsigned key; + QByteArray utf8; + + bool shift = e->modifiers() & Qt::ShiftModifier; + bool ctrl = e->modifiers() & Qt::ControlModifier; + bool alt = e->modifiers() & Qt::AltModifier; + + switch (e->key()) + { + case Qt::Key_Down: + key = SCK_DOWN; + break; + + case Qt::Key_Up: + key = SCK_UP; + break; + + case Qt::Key_Left: + key = SCK_LEFT; + break; + + case Qt::Key_Right: + key = SCK_RIGHT; + break; + + case Qt::Key_Home: + key = SCK_HOME; + break; + + case Qt::Key_End: + key = SCK_END; + break; + + case Qt::Key_PageUp: + key = SCK_PRIOR; + break; + + case Qt::Key_PageDown: + key = SCK_NEXT; + break; + + case Qt::Key_Delete: + key = SCK_DELETE; + break; + + case Qt::Key_Insert: + key = SCK_INSERT; + break; + + case Qt::Key_Escape: + key = SCK_ESCAPE; + break; + + case Qt::Key_Backspace: + key = SCK_BACK; + break; + + case Qt::Key_Tab: + key = SCK_TAB; + break; + + case Qt::Key_Return: + case Qt::Key_Enter: + key = SCK_RETURN; + break; + + case Qt::Key_Super_L: + key = SCK_WIN; + break; + + case Qt::Key_Super_R: + key = SCK_RWIN; + break; + + case Qt::Key_Menu: + key = SCK_MENU; + break; + + default: + // See if the input was a single ASCII key. If so it will be passed to + // KeyDown to allow it to be filtered. Correct the modifiers and key + // for ASCII letters as Qt uses the ASCII code of uppercase letters for + // Key_A etc. + utf8 = e->text().toUtf8(); + + if (utf8.length() == 0) + key = e->key(); + else if (utf8.length() != 1) + key = 0; + else if ((key = utf8[0]) >= 0x80) + key = 0; + else if (key >= 0x01 && key <= 0x1a) + key += 0x40; + else if (key >= 'A' && key <= 'Z') + shift = true; + else if (key >= 'a' && key <= 'z') + { + key -= 0x20; + shift = false; + } + } + + if (key) + { + bool consumed = false; + + sci->KeyDown(key, shift, ctrl, alt, &consumed); + + if (consumed) + { + e->accept(); + return; + } + } + + // Add the text if it has a compatible size depending on what Unicode mode + // we are in. + if (utf8.length() > 0 && (sci->IsUnicodeMode() || utf8.length() == 1)) + { + sci->AddCharUTF(utf8.data(), utf8.length()); + e->accept(); + } + else + QAbstractScrollArea::keyPressEvent(e); +} + + +// Handle composed characters. Note that this is the minumum needed to retain +// the QScintilla v1 functionality. +void QsciScintillaBase::inputMethodEvent(QInputMethodEvent *e) +{ + QByteArray utf8 = e->commitString().toUtf8(); + + sci->AddCharUTF(utf8.data(), utf8.length()); + e->accept(); +} + + +// Handle a mouse button double click. +void QsciScintillaBase::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) + { + e->ignore(); + return; + } + + setFocus(); + + // Make sure Scintilla will interpret this as a double-click. + unsigned clickTime = sci->lastClickTime + Platform::DoubleClickTime() - 1; + + bool shift = e->modifiers() & Qt::ShiftModifier; + bool ctrl = e->modifiers() & Qt::ControlModifier; + bool alt = e->modifiers() & Qt::AltModifier; + + sci->ButtonDown(Point(e->x(), e->y()), clickTime, shift, ctrl, alt); + + // Remember the current position and time in case it turns into a triple + // click. + triple_click_at = e->globalPos(); + triple_click.start(QApplication::doubleClickInterval()); +} + + +// Handle a mouse move. +void QsciScintillaBase::mouseMoveEvent(QMouseEvent *e) +{ + sci->ButtonMove(Point(e->x(), e->y())); +} + + +// Handle a mouse button press. +void QsciScintillaBase::mousePressEvent(QMouseEvent *e) +{ + setFocus(); + + Point pt(e->x(), e->y()); + + if (e->button() == Qt::LeftButton) + { + unsigned clickTime; + + // It is a triple click if the timer is running and the mouse hasn't + // moved too much. + if (triple_click.isActive() && (e->globalPos() - triple_click_at).manhattanLength() < QApplication::startDragDistance()) + clickTime = sci->lastClickTime + Platform::DoubleClickTime() - 1; + else + clickTime = sci->lastClickTime + Platform::DoubleClickTime() + 1; + + triple_click.stop(); + + bool shift = e->modifiers() & Qt::ShiftModifier; + bool ctrl = e->modifiers() & Qt::ControlModifier; + bool alt = e->modifiers() & Qt::AltModifier; + + sci->ButtonDown(pt, clickTime, shift, ctrl, alt); + } + else if (e->button() == Qt::MidButton) + { + QClipboard *cb = QApplication::clipboard(); + + if (cb->supportsSelection()) + { + int pos = sci->PositionFromLocation(pt); + + sci->SetSelection(pos, pos); + sci->pasteFromClipboard(QClipboard::Selection); + } + } +} + + +// Handle a mouse button releases. +void QsciScintillaBase::mouseReleaseEvent(QMouseEvent *e) +{ + if (sci->HaveMouseCapture() && e->button() == Qt::LeftButton) + { + bool ctrl = e->modifiers() & Qt::ControlModifier; + + sci->ButtonUp(Point(e->x(), e->y()), 0, ctrl); + } +} + + +// Handle paint events. +void QsciScintillaBase::paintEvent(QPaintEvent *e) +{ + sci->paintEvent(e); +} + + +// Handle resize events. +void QsciScintillaBase::resizeEvent(QResizeEvent *) +{ + sci->ChangeSize(); +} + + +// Re-implemented to suppress the default behaviour as Scintilla works at a +// more fundamental level. +void QsciScintillaBase::scrollContentsBy(int, int) +{ +} + + +// Handle the vertical scrollbar. +void QsciScintillaBase::handleVSb(int value) +{ + sci->ScrollTo(value); +} + + +// Handle the horizontal scrollbar. +void QsciScintillaBase::handleHSb(int value) +{ + sci->HorizontalScrollTo(value); +} + + +// Handle drag enters. +void QsciScintillaBase::dragEnterEvent(QDragEnterEvent *e) +{ + QsciScintillaBase::dragMoveEvent(e); +} + + +// Handle drag leaves. +void QsciScintillaBase::dragLeaveEvent(QDragLeaveEvent *) +{ + sci->SetDragPosition(-1); +} + + +// Handle drag moves. +void QsciScintillaBase::dragMoveEvent(QDragMoveEvent *e) +{ + sci->SetDragPosition(sci->PositionFromLocation(Point(e->pos().x(), + e->pos().y()))); + + acceptAction(e); +} + + +// Handle drops. +void QsciScintillaBase::dropEvent(QDropEvent *e) +{ + bool moving; + const char *s; + + acceptAction(e); + + if (!e->isAccepted()) + return; + + moving = (e->dropAction() == Qt::MoveAction); + + QString qs = fromMimeData(e->mimeData()); + QByteArray ba; + + if (sci->IsUnicodeMode()) + ba = qs.toUtf8(); + else + ba = qs.toLatin1(); + + s = ba.data(); + + sci->DropAt(sci->posDrop, s, moving, false); + sci->Redraw(); +} + + +void QsciScintillaBase::acceptAction(QDropEvent *e) +{ + if (sci->pdoc->IsReadOnly() || !canInsertFromMimeData(e->mimeData())) + { + e->ignore(); + } + else if ((e->source() == this || e->source() == viewport()) && (e->keyboardModifiers() & Qt::ControlModifier) == 0) + { + e->setDropAction(Qt::MoveAction); + e->accept(); + } + else + { + e->acceptProposedAction(); + } +} + + + +// See if a MIME data object can be decoded. +bool QsciScintillaBase::canInsertFromMimeData(const QMimeData *source) const +{ + return source->hasText() && !source->text().isEmpty(); +} + + +// Create text from a MIME data object. +QString QsciScintillaBase::fromMimeData(const QMimeData *source) const +{ + return source->text(); +} + + +// Create a MIME data object for some text. +QMimeData *QsciScintillaBase::toMimeData(const QString &text) const +{ + QMimeData *mime = new QMimeData; + + mime->setText(text); + + return mime; +} + diff --git a/harbour/contrib/hbide/qscintilla/qt/qsciscintillabase.h b/harbour/contrib/hbide/qscintilla/qt/qsciscintillabase.h new file mode 100644 index 0000000000..945cc40047 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qsciscintillabase.h @@ -0,0 +1,2802 @@ +// This class defines the "official" low-level API. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCISCINTILLABASE_H +#define QSCISCINTILLABASE_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + +#include + +#include +#include + +#include + + +class QColor; +class QPainter; +class QPixmap; +class QMimeData; + +class ScintillaQt; + + +//! \brief The QsciScintillaBase class implements the Scintilla editor widget +//! and its low-level API. +//! +//! Scintilla (http://www.scintilla.org) is a powerful C++ editor class that +//! supports many features including syntax styling, error indicators, code +//! completion and call tips. It is particularly useful as a programmer's +//! editor. +//! +//! QsciScintillaBase is a port to Qt of Scintilla. It implements the standard +//! Scintilla API which consists of a number of messages each taking up to +//! two arguments. +//! +//! See QsciScintilla for the implementation of a higher level API that is more +//! consistent with the rest of the Qt toolkit. +class QSCINTILLA_EXPORT QsciScintillaBase : public QAbstractScrollArea +{ + Q_OBJECT + +public: + //! The low-level Scintilla API is implemented as a set of messages each of + //! which takes up to two parameters (\a wParam and \a lParam) and + //! optionally return a value. This enum defines all the possible messages. + enum + { + //! + SCI_START = 2000, + + //! + SCI_OPTIONAL_START = 3000, + + //! + SCI_LEXER_START = 4000, + + //! This message appends some text to the end of the document. + //! \a wParam is the length of the text. + //! \a lParam is the text to be appended. + SCI_ADDTEXT = 2001, + + //! + SCI_ADDSTYLEDTEXT = 2002, + + //! + SCI_INSERTTEXT = 2003, + + //! + SCI_CLEARALL = 2004, + + //! + SCI_CLEARDOCUMENTSTYLE = 2005, + + //! + SCI_GETLENGTH = 2006, + + //! + SCI_GETCHARAT = 2007, + + //! This message returns the current position. + //! + //! \sa SCI_SETCURRENTPOS + SCI_GETCURRENTPOS = 2008, + + //! This message returns the anchor. + //! + //! \sa SCI_SETANCHOR + SCI_GETANCHOR = 2009, + + //! + SCI_GETSTYLEAT = 2010, + + //! + SCI_REDO = 2011, + + //! + SCI_SETUNDOCOLLECTION = 2012, + + //! + SCI_SELECTALL = 2013, + + //! This message marks the current state of the text as the the save + //! point. This is usually done when the text is saved or loaded. + //! + //! \sa SCN_SAVEPOINTREACHED(), SCN_SAVEPOINTLEFT() + SCI_SETSAVEPOINT = 2014, + + //! + SCI_GETSTYLEDTEXT = 2015, + + //! + SCI_CANREDO = 2016, + + //! This message returns the line that contains a particular instance + //! of a marker. + //! \a wParam is the handle of the marker. + //! + //! \sa SCI_MARKERADD + SCI_MARKERLINEFROMHANDLE = 2017, + + //! This message removes a particular instance of a marker. + //! \a wParam is the handle of the marker. + //! + //! \sa SCI_MARKERADD + SCI_MARKERDELETEHANDLE = 2018, + + //! + SCI_GETUNDOCOLLECTION = 2019, + + //! + SCI_GETVIEWWS = 2020, + + //! + SCI_SETVIEWWS = 2021, + + //! + SCI_POSITIONFROMPOINT = 2022, + + //! + SCI_POSITIONFROMPOINTCLOSE = 2023, + + //! + SCI_GOTOLINE = 2024, + + //! This message clears the current selection and sets the current + //! position. + //! \a wParam is the new current position. + //! + //! \sa SCI_SETCURRENTPOS + SCI_GOTOPOS = 2025, + + //! This message sets the anchor. + //! \a wParam is the new anchor. + //! + //! \sa SCI_GETANCHOR + SCI_SETANCHOR = 2026, + + //! + SCI_GETCURLINE = 2027, + + //! This message returns the character position of the start of the + //! text that needs to be syntax styled. + //! + //! \sa SCN_STYLENEEDED() + SCI_GETENDSTYLED = 2028, + + //! + SCI_CONVERTEOLS = 2029, + + //! + SCI_GETEOLMODE = 2030, + + //! + SCI_SETEOLMODE = 2031, + + //! + SCI_STARTSTYLING = 2032, + + //! + SCI_SETSTYLING = 2033, + + //! + SCI_GETBUFFEREDDRAW = 2034, + + //! + SCI_SETBUFFEREDDRAW = 2035, + + //! + SCI_SETTABWIDTH = 2036, + + //! + SCI_GETTABWIDTH = 2121, + + //! + SCI_SETCODEPAGE = 2037, + + //! + SCI_SETUSEPALETTE = 2039, + + //! This message sets the symbol used to draw one of 32 markers. Some + //! markers have pre-defined uses, see the SC_MARKNUM_* values. + //! \a wParam is the number of the marker. + //! \a lParam is the marker symbol and is one of the SC_MARK_* values. + //! + //! \sa SCI_MARKERADD, SCI_MARKERDEFINEPIXMAP + SCI_MARKERDEFINE = 2040, + + //! This message sets the foreground colour used to draw a marker. A + //! colour is represented as a 24 bit value. The 8 least significant + //! bits correspond to red, the middle 8 bits correspond to green, and + //! the 8 most significant bits correspond to blue. The default value + //! is 0x000000. + //! \a wParam is the number of the marker. + //! \a lParam is the colour. + //! + //! \sa SCI_MARKERSETBACK + SCI_MARKERSETFORE = 2041, + + //! This message sets the background colour used to draw a marker. A + //! colour is represented as a 24 bit value. The 8 least significant + //! bits correspond to red, the middle 8 bits correspond to green, and + //! the 8 most significant bits correspond to blue. The default value + //! is 0xffffff. + //! \a wParam is the number of the marker. + //! \a lParam is the colour. + //! + //! \sa SCI_MARKERSETFORE + SCI_MARKERSETBACK = 2042, + + //! This message adds a marker to a line. A handle for the marker is + //! returned which can be used to track the marker's position. + //! \a wParam is the line number. + //! \a lParam is the number of the marker. + //! + //! \sa SCI_MARKERDELETE, SCI_MARKERDELETEALL, + //! SCI_MARKERDELETEHANDLE + SCI_MARKERADD = 2043, + + //! This message deletes a marker from a line. + //! \a wParam is the line number. + //! \a lParam is the number of the marker. + //! + //! \sa SCI_MARKERADD, SCI_MARKERDELETEALL + SCI_MARKERDELETE = 2044, + + //! This message deletes all occurences of a marker. + //! \a wParam is the number of the marker. If \a wParam is -1 then all + //! markers are removed. + //! + //! \sa SCI_MARKERADD, SCI_MARKERDELETE + SCI_MARKERDELETEALL = 2045, + + //! This message returns the 32 bit mask of markers at a line. + //! \a wParam is the line number. + SCI_MARKERGET = 2046, + + //! This message looks for the next line to contain at least one marker + //! contained in a 32 bit mask of markers and returns the line number. + //! \a wParam is the line number to start the search from. + //! \a lParam is the mask of markers to search for. + //! + //! \sa SCI_MARKERPREVIOUS + SCI_MARKERNEXT = 2047, + + //! This message looks for the previous line to contain at least one + //! marker contained in a 32 bit mask of markers and returns the line + //! number. + //! \a wParam is the line number to start the search from. + //! \a lParam is the mask of markers to search for. + //! + //! \sa SCI_MARKERNEXT + SCI_MARKERPREVIOUS = 2048, + + //! This message sets the symbol used to draw one of the 32 markers to + //! a pixmap. Pixmaps use the SC_MARK_PIXMAP marker symbol. + //! \a wParam is the number of the marker. + //! \a lParam is a pointer to a QPixmap instance. Note that in other + //! ports of Scintilla this is a pointer to either raw or textual XPM + //! image data. + //! + //! \sa SCI_MARKERDEFINE + SCI_MARKERDEFINEPIXMAP = 2049, + + //! This message sets what can be displayed in a margin. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! \a lParam is the logical or of the SC_MARGIN_* values. + //! + //! \sa SCI_GETMARGINTYPEN + SCI_SETMARGINTYPEN = 2240, + + //! This message returns what can be displayed in a margin. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! + //! \sa SCI_SETMARGINTYPEN + SCI_GETMARGINTYPEN = 2241, + + //! This message sets the width of a margin in pixels. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! \a lParam is the new margin width. + //! + //! \sa SCI_GETMARGINWIDTHN + SCI_SETMARGINWIDTHN = 2242, + + //! This message returns the width of a margin in pixels. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! + //! \sa SCI_SETMARGINWIDTHN + SCI_GETMARGINWIDTHN = 2243, + + //! This message sets the mask of a margin. The mask is a 32 value + //! with one bit for each possible marker. If a bit is set then the + //! corresponding marker is displayed. By default, all markers are + //! displayed. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! \a lParam is the new margin mask. + //! + //! \sa SCI_GETMARGINMASKN, SCI_MARKERDEFINE + SCI_SETMARGINMASKN = 2244, + + //! This message returns the mask of a margin. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! + //! \sa SCI_SETMARGINMASKN + SCI_GETMARGINMASKN = 2245, + + //! This message sets the sensitivity of a margin to mouse clicks. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! \a lParam is non-zero to make the margin sensitive to mouse clicks. + //! When the mouse is clicked the SCN_MARGINCLICK() signal is emitted. + //! + //! \sa SCI_GETMARGINSENSITIVEN, SCN_MARGINCLICK() + SCI_SETMARGINSENSITIVEN = 2246, + + //! This message returns the sensitivity of a margin to mouse clicks. + //! \a wParam is the number of the margin: 0, 1 or 2. + //! + //! \sa SCI_SETMARGINSENSITIVEN, SCN_MARGINCLICK() + SCI_GETMARGINSENSITIVEN = 2247, + + //! + SCI_STYLECLEARALL = 2050, + + //! + SCI_STYLESETFORE = 2051, + + //! + SCI_STYLESETBACK = 2052, + + //! + SCI_STYLESETBOLD = 2053, + + //! + SCI_STYLESETITALIC = 2054, + + //! + SCI_STYLESETSIZE = 2055, + + //! + SCI_STYLESETFONT = 2056, + + //! + SCI_STYLESETEOLFILLED = 2057, + + //! + SCI_STYLERESETDEFAULT = 2058, + + //! + SCI_STYLESETUNDERLINE = 2059, + + //! + SCI_STYLESETCASE = 2060, + + //! + SCI_STYLESETCHARACTERSET = 2066, + + //! + SCI_SETSELFORE = 2067, + + //! + SCI_SETSELBACK = 2068, + + //! + SCI_SETCARETFORE = 2069, + + //! + SCI_ASSIGNCMDKEY = 2070, + + //! + SCI_CLEARCMDKEY = 2071, + + //! + SCI_CLEARALLCMDKEYS = 2072, + + //! + SCI_SETSTYLINGEX = 2073, + + //! + SCI_STYLESETVISIBLE = 2074, + + //! + SCI_GETCARETPERIOD = 2075, + + //! + SCI_SETCARETPERIOD = 2076, + + //! + SCI_SETWORDCHARS = 2077, + + //! + SCI_BEGINUNDOACTION = 2078, + + //! + SCI_ENDUNDOACTION = 2079, + + //! + SCI_INDICSETSTYLE = 2080, + + //! + SCI_INDICGETSTYLE = 2081, + + //! + SCI_INDICSETFORE = 2082, + + //! + SCI_INDICGETFORE = 2083, + + //! + SCI_SETWHITESPACEFORE = 2084, + + //! + SCI_SETWHITESPACEBACK = 2085, + + //! + SCI_SETSTYLEBITS = 2090, + + //! + SCI_GETSTYLEBITS = 2091, + + //! + SCI_SETLINESTATE = 2092, + + //! + SCI_GETLINESTATE = 2093, + + //! + SCI_GETMAXLINESTATE = 2094, + + //! + SCI_GETCARETLINEVISIBLE = 2095, + + //! + SCI_SETCARETLINEVISIBLE = 2096, + + //! + SCI_GETCARETLINEBACK = 2097, + + //! + SCI_SETCARETLINEBACK = 2098, + + //! + SCI_STYLESETCHANGEABLE = 2099, + + //! + SCI_AUTOCSHOW = 2100, + + //! + SCI_AUTOCCANCEL = 2101, + + //! + SCI_AUTOCACTIVE = 2102, + + //! + SCI_AUTOCPOSSTART = 2103, + + //! + SCI_AUTOCCOMPLETE = 2104, + + //! + SCI_AUTOCSTOPS = 2105, + + //! + SCI_AUTOCSETSEPARATOR = 2106, + + //! + SCI_AUTOCGETSEPARATOR = 2107, + + //! + SCI_AUTOCSELECT = 2108, + + //! + SCI_AUTOCSETCANCELATSTART = 2110, + + //! + SCI_AUTOCGETCANCELATSTART = 2111, + + //! + SCI_AUTOCSETFILLUPS = 2112, + + //! + SCI_AUTOCSETCHOOSESINGLE = 2113, + + //! + SCI_AUTOCGETCHOOSESINGLE = 2114, + + //! + SCI_AUTOCSETIGNORECASE = 2115, + + //! + SCI_AUTOCGETIGNORECASE = 2116, + + //! + SCI_USERLISTSHOW = 2117, + + //! + SCI_AUTOCSETAUTOHIDE = 2118, + + //! + SCI_AUTOCGETAUTOHIDE = 2119, + + //! + SCI_AUTOCSETDROPRESTOFWORD = 2270, + + //! + SCI_AUTOCGETDROPRESTOFWORD = 2271, + + //! + SCI_SETINDENT = 2122, + + //! + SCI_GETINDENT = 2123, + + //! + SCI_SETUSETABS = 2124, + + //! + SCI_GETUSETABS = 2125, + + //! + SCI_SETLINEINDENTATION = 2126, + + //! + SCI_GETLINEINDENTATION = 2127, + + //! + SCI_GETLINEINDENTPOSITION = 2128, + + //! + SCI_GETCOLUMN = 2129, + + //! + SCI_SETHSCROLLBAR = 2130, + + //! + SCI_GETHSCROLLBAR = 2131, + + //! + SCI_SETINDENTATIONGUIDES = 2132, + + //! + SCI_GETINDENTATIONGUIDES = 2133, + + //! + SCI_SETHIGHLIGHTGUIDE = 2134, + + //! + SCI_GETHIGHLIGHTGUIDE = 2135, + + //! + SCI_GETLINEENDPOSITION = 2136, + + //! + SCI_GETCODEPAGE = 2137, + + //! + SCI_GETCARETFORE = 2138, + + //! + SCI_GETUSEPALETTE = 2139, + + //! This message returns a non-zero value if the document is read-only. + //! + //! \sa SCI_SETREADONLY + SCI_GETREADONLY = 2140, + + //! This message sets the current position. + //! \a wParam is the new current position. + //! + //! \sa SCI_GETCURRENTPOS + SCI_SETCURRENTPOS = 2141, + + //! + SCI_SETSELECTIONSTART = 2142, + + //! + SCI_GETSELECTIONSTART = 2143, + + //! + SCI_SETSELECTIONEND = 2144, + + //! + SCI_GETSELECTIONEND = 2145, + + //! + SCI_SETPRINTMAGNIFICATION = 2146, + + //! + SCI_GETPRINTMAGNIFICATION = 2147, + + //! + SCI_SETPRINTCOLOURMODE = 2148, + + //! + SCI_GETPRINTCOLOURMODE = 2149, + + //! + SCI_FINDTEXT = 2150, + + //! + SCI_FORMATRANGE = 2151, + + //! + SCI_GETFIRSTVISIBLELINE = 2152, + + //! + SCI_GETLINE = 2153, + + //! + SCI_GETLINECOUNT = 2154, + + //! + SCI_SETMARGINLEFT = 2155, + + //! + SCI_GETMARGINLEFT = 2156, + + //! + SCI_SETMARGINRIGHT = 2157, + + //! + SCI_GETMARGINRIGHT = 2158, + + //! This message returns a non-zero value if the document has been + //! modified. + SCI_GETMODIFY = 2159, + + //! + SCI_SETSEL = 2160, + + //! + SCI_GETSELTEXT = 2161, + + //! + SCI_GETTEXTRANGE = 2162, + + //! + SCI_HIDESELECTION = 2163, + + //! + SCI_POINTXFROMPOSITION = 2164, + + //! + SCI_POINTYFROMPOSITION = 2165, + + //! + SCI_LINEFROMPOSITION = 2166, + + //! + SCI_POSITIONFROMLINE = 2167, + + //! + SCI_LINESCROLL = 2168, + + //! + SCI_SCROLLCARET = 2169, + + //! + SCI_REPLACESEL = 2170, + + //! This message sets the read-only state of the document. + //! \a wParam is the new read-only state of the document. + //! + //! \sa SCI_GETREADONLY + SCI_SETREADONLY = 2171, + + //! + SCI_NULL = 2172, + + //! + SCI_CANPASTE = 2173, + + //! + SCI_CANUNDO = 2174, + + //! This message empties the undo buffer. + SCI_EMPTYUNDOBUFFER = 2175, + + //! + SCI_UNDO = 2176, + + //! + SCI_CUT = 2177, + + //! + SCI_COPY = 2178, + + //! + SCI_PASTE = 2179, + + //! + SCI_CLEAR = 2180, + + //! This message sets the text of the document. + //! \a wParam is unused. + //! \a lParam is the new text of the document. + //! + //! \sa SCI_GETTEXT + SCI_SETTEXT = 2181, + + //! This message gets the text of the document. + //! \a wParam is size of the buffer that the text is copied to. + //! \a lParam is the address of the buffer that the text is copied to. + //! + //! \sa SCI_SETTEXT + SCI_GETTEXT = 2182, + + //! This message returns the length of the document. + SCI_GETTEXTLENGTH = 2183, + + //! + SCI_GETDIRECTFUNCTION = 2184, + + //! + SCI_GETDIRECTPOINTER = 2185, + + //! + SCI_SETOVERTYPE = 2186, + + //! + SCI_GETOVERTYPE = 2187, + + //! + SCI_SETCARETWIDTH = 2188, + + //! + SCI_GETCARETWIDTH = 2189, + + //! + SCI_SETTARGETSTART = 2190, + + //! + SCI_GETTARGETSTART = 2191, + + //! + SCI_SETTARGETEND = 2192, + + //! + SCI_GETTARGETEND = 2193, + + //! + SCI_REPLACETARGET = 2194, + + //! + SCI_REPLACETARGETRE = 2195, + + //! + SCI_SEARCHINTARGET = 2197, + + //! + SCI_SETSEARCHFLAGS = 2198, + + //! + SCI_GETSEARCHFLAGS = 2199, + + //! + SCI_CALLTIPSHOW = 2200, + + //! + SCI_CALLTIPCANCEL = 2201, + + //! + SCI_CALLTIPACTIVE = 2202, + + //! + SCI_CALLTIPPOSSTART = 2203, + + //! + SCI_CALLTIPSETHLT = 2204, + + //! + SCI_CALLTIPSETBACK = 2205, + + //! + SCI_CALLTIPSETFORE = 2206, + + //! + SCI_CALLTIPSETFOREHLT = 2207, + + //! + SCI_AUTOCSETMAXWIDTH = 2208, + + //! + SCI_AUTOCGETMAXWIDTH = 2209, + + //! This message is not implemented. + SCI_AUTOCSETMAXHEIGHT = 2210, + + //! + SCI_AUTOCGETMAXHEIGHT = 2211, + + //! + SCI_CALLTIPUSESTYLE = 2212, + + //! + SCI_VISIBLEFROMDOCLINE = 2220, + + //! + SCI_DOCLINEFROMVISIBLE = 2221, + + //! + SCI_SETFOLDLEVEL = 2222, + + //! + SCI_GETFOLDLEVEL = 2223, + + //! + SCI_GETLASTCHILD = 2224, + + //! + SCI_GETFOLDPARENT = 2225, + + //! + SCI_SHOWLINES = 2226, + + //! + SCI_HIDELINES = 2227, + + //! + SCI_GETLINEVISIBLE = 2228, + + //! + SCI_SETFOLDEXPANDED = 2229, + + //! + SCI_GETFOLDEXPANDED = 2230, + + //! + SCI_TOGGLEFOLD = 2231, + + //! + SCI_ENSUREVISIBLE = 2232, + + //! + SCI_SETFOLDFLAGS = 2233, + + //! + SCI_ENSUREVISIBLEENFORCEPOLICY = 2234, + + //! + SCI_WRAPCOUNT = 2235, + + //! + SCI_SETTABINDENTS = 2260, + + //! + SCI_GETTABINDENTS = 2261, + + //! + SCI_SETBACKSPACEUNINDENTS = 2262, + + //! + SCI_GETBACKSPACEUNINDENTS = 2263, + + //! + SCI_SETMOUSEDWELLTIME = 2264, + + //! + SCI_GETMOUSEDWELLTIME = 2265, + + //! + SCI_WORDSTARTPOSITION = 2266, + + //! + SCI_WORDENDPOSITION = 2267, + + //! + SCI_SETWRAPMODE = 2268, + + //! + SCI_GETWRAPMODE = 2269, + + //! + SCI_SETLAYOUTCACHE = 2272, + + //! + SCI_GETLAYOUTCACHE = 2273, + + //! + SCI_SETSCROLLWIDTH = 2274, + + //! + SCI_GETSCROLLWIDTH = 2275, + + //! This message returns the width of some text when rendered in a + //! particular style. + //! \a wParam is the style number and is one of the STYLE_* values or + //! one of the styles defined by a lexer. + //! \a lParam is a pointer to the text. + SCI_TEXTWIDTH = 2276, + + //! + SCI_SETENDATLASTLINE = 2277, + + //! + SCI_GETENDATLASTLINE = 2278, + + //! + SCI_TEXTHEIGHT = 2279, + + //! + SCI_SETVSCROLLBAR = 2280, + + //! + SCI_GETVSCROLLBAR = 2281, + + //! + SCI_APPENDTEXT = 2282, + + //! + SCI_GETTWOPHASEDRAW = 2283, + + //! + SCI_SETTWOPHASEDRAW = 2284, + + //! + SCI_AUTOCGETTYPESEPARATOR = 2285, + + //! + SCI_AUTOCSETTYPESEPARATOR = 2286, + + //! + SCI_TARGETFROMSELECTION = 2287, + + //! + SCI_LINESJOIN = 2288, + + //! + SCI_LINESSPLIT = 2289, + + //! + SCI_SETFOLDMARGINCOLOUR = 2290, + + //! + SCI_SETFOLDMARGINHICOLOUR = 2291, + + //! + SCI_LINEDOWN = 2300, + + //! + SCI_LINEDOWNEXTEND = 2301, + + //! + SCI_LINEUP = 2302, + + //! + SCI_LINEUPEXTEND = 2303, + + //! + SCI_CHARLEFT = 2304, + + //! + SCI_CHARLEFTEXTEND = 2305, + + //! + SCI_CHARRIGHT = 2306, + + //! + SCI_CHARRIGHTEXTEND = 2307, + + //! + SCI_WORDLEFT = 2308, + + //! + SCI_WORDLEFTEXTEND = 2309, + + //! + SCI_WORDRIGHT = 2310, + + //! + SCI_WORDRIGHTEXTEND = 2311, + + //! + SCI_HOME = 2312, + + //! + SCI_HOMEEXTEND = 2313, + + //! + SCI_LINEEND = 2314, + + //! + SCI_LINEENDEXTEND = 2315, + + //! + SCI_DOCUMENTSTART = 2316, + + //! + SCI_DOCUMENTSTARTEXTEND = 2317, + + //! + SCI_DOCUMENTEND = 2318, + + //! + SCI_DOCUMENTENDEXTEND = 2319, + + //! + SCI_PAGEUP = 2320, + + //! + SCI_PAGEUPEXTEND = 2321, + + //! + SCI_PAGEDOWN = 2322, + + //! + SCI_PAGEDOWNEXTEND = 2323, + + //! + SCI_EDITTOGGLEOVERTYPE = 2324, + + //! + SCI_CANCEL = 2325, + + //! + SCI_DELETEBACK = 2326, + + //! + SCI_TAB = 2327, + + //! + SCI_BACKTAB = 2328, + + //! + SCI_NEWLINE = 2329, + + //! + SCI_FORMFEED = 2330, + + //! + SCI_VCHOME = 2331, + + //! + SCI_VCHOMEEXTEND = 2332, + + //! + SCI_ZOOMIN = 2333, + + //! + SCI_ZOOMOUT = 2334, + + //! + SCI_DELWORDLEFT = 2335, + + //! + SCI_DELWORDRIGHT = 2336, + + //! + SCI_LINECUT = 2337, + + //! + SCI_LINEDELETE = 2338, + + //! + SCI_LINETRANSPOSE = 2339, + + //! + SCI_LOWERCASE = 2340, + + //! + SCI_UPPERCASE = 2341, + + //! + SCI_LINESCROLLDOWN = 2342, + + //! + SCI_LINESCROLLUP = 2343, + + //! + SCI_DELETEBACKNOTLINE = 2344, + + //! + SCI_HOMEDISPLAY = 2345, + + //! + SCI_HOMEDISPLAYEXTEND = 2346, + + //! + SCI_LINEENDDISPLAY = 2347, + + //! + SCI_LINEENDDISPLAYEXTEND = 2348, + + //! + SCI_MOVECARETINSIDEVIEW = 2401, + + //! + SCI_LINELENGTH = 2350, + + //! + SCI_BRACEHIGHLIGHT = 2351, + + //! + SCI_BRACEBADLIGHT = 2352, + + //! + SCI_BRACEMATCH = 2353, + + //! + SCI_GETVIEWEOL = 2355, + + //! + SCI_SETVIEWEOL = 2356, + + //! + SCI_GETDOCPOINTER = 2357, + + //! + SCI_SETDOCPOINTER = 2358, + + //! + SCI_SETMODEVENTMASK = 2359, + + //! + SCI_GETEDGECOLUMN = 2360, + + //! + SCI_SETEDGECOLUMN = 2361, + + //! + SCI_GETEDGEMODE = 2362, + + //! + SCI_SETEDGEMODE = 2363, + + //! + SCI_GETEDGECOLOUR = 2364, + + //! + SCI_SETEDGECOLOUR = 2365, + + //! + SCI_SEARCHANCHOR = 2366, + + //! + SCI_SEARCHNEXT = 2367, + + //! + SCI_SEARCHPREV = 2368, + + //! + SCI_LINESONSCREEN = 2370, + + //! + SCI_USEPOPUP = 2371, + + //! + SCI_SELECTIONISRECTANGLE = 2372, + + //! + SCI_SETZOOM = 2373, + + //! + SCI_GETZOOM = 2374, + + //! + SCI_CREATEDOCUMENT = 2375, + + //! + SCI_ADDREFDOCUMENT = 2376, + + //! + SCI_RELEASEDOCUMENT = 2377, + + //! + SCI_GETMODEVENTMASK = 2378, + + //! + SCI_SETFOCUS = 2380, + + //! + SCI_GETFOCUS = 2381, + + //! + SCI_SETSTATUS = 2382, + + //! + SCI_GETSTATUS = 2383, + + //! + SCI_SETMOUSEDOWNCAPTURES = 2384, + + //! + SCI_GETMOUSEDOWNCAPTURES = 2385, + + //! + SCI_SETCURSOR = 2386, + + //! + SCI_GETCURSOR = 2387, + + //! + SCI_SETCONTROLCHARSYMBOL = 2388, + + //! + SCI_GETCONTROLCHARSYMBOL = 2389, + + //! + SCI_WORDPARTLEFT = 2390, + + //! + SCI_WORDPARTLEFTEXTEND = 2391, + + //! + SCI_WORDPARTRIGHT = 2392, + + //! + SCI_WORDPARTRIGHTEXTEND = 2393, + + //! + SCI_SETVISIBLEPOLICY = 2394, + + //! + SCI_DELLINELEFT = 2395, + + //! + SCI_DELLINERIGHT = 2396, + + //! + SCI_SETXOFFSET = 2397, + + //! + SCI_GETXOFFSET = 2398, + + //! + SCI_CHOOSECARETX = 2399, + + //! + SCI_GRABFOCUS = 2400, + + //! + SCI_SETXCARETPOLICY = 2402, + + //! + SCI_SETYCARETPOLICY = 2403, + + //! + SCI_LINEDUPLICATE = 2404, + + //! This message takes a copy of an image and registers it so that it + //! can be refered to by a unique integer identifier. + //! \a wParam is the image's identifier. + //! \a lParam is a pointer to a QPixmap instance. Note that in other + //! ports of Scintilla this is a pointer to either raw or textual XPM + //! image data. + //! + //! \sa SCI_CLEARREGISTEREDIMAGES + SCI_REGISTERIMAGE = 2405, + + //! + SCI_SETPRINTWRAPMODE = 2406, + + //! + SCI_GETPRINTWRAPMODE = 2407, + + //! This message de-registers all currently registered images. + //! + //! \sa SCI_REGISTERIMAGE + SCI_CLEARREGISTEREDIMAGES = 2408, + + //! + SCI_STYLESETHOTSPOT = 2409, + + //! + SCI_SETHOTSPOTACTIVEFORE = 2410, + + //! + SCI_SETHOTSPOTACTIVEBACK = 2411, + + //! + SCI_SETHOTSPOTACTIVEUNDERLINE = 2412, + + //! + SCI_PARADOWN = 2413, + + //! + SCI_PARADOWNEXTEND = 2414, + + //! + SCI_PARAUP = 2415, + + //! + SCI_PARAUPEXTEND = 2416, + + //! + SCI_POSITIONBEFORE = 2417, + + //! + SCI_POSITIONAFTER = 2418, + + //! + SCI_COPYRANGE = 2419, + + //! + SCI_COPYTEXT = 2420, + + //! + SCI_SETSELECTIONMODE = 2422, + + //! + SCI_GETSELECTIONMODE = 2423, + + //! + SCI_GETLINESELSTARTPOSITION = 2424, + + //! + SCI_GETLINESELENDPOSITION = 2425, + + //! + SCI_LINEDOWNRECTEXTEND = 2426, + + //! + SCI_LINEUPRECTEXTEND = 2427, + + //! + SCI_CHARLEFTRECTEXTEND = 2428, + + //! + SCI_CHARRIGHTRECTEXTEND = 2429, + + //! + SCI_HOMERECTEXTEND = 2430, + + //! + SCI_VCHOMERECTEXTEND = 2431, + + //! + SCI_LINEENDRECTEXTEND = 2432, + + //! + SCI_PAGEUPRECTEXTEND = 2433, + + //! + SCI_PAGEDOWNRECTEXTEND = 2434, + + //! + SCI_STUTTEREDPAGEUP = 2435, + + //! + SCI_STUTTEREDPAGEUPEXTEND = 2436, + + //! + SCI_STUTTEREDPAGEDOWN = 2437, + + //! + SCI_STUTTEREDPAGEDOWNEXTEND = 2438, + + //! + SCI_WORDLEFTEND = 2439, + + //! + SCI_WORDLEFTENDEXTEND = 2440, + + //! + SCI_WORDRIGHTEND = 2441, + + //! + SCI_WORDRIGHTENDEXTEND = 2442, + + //! + SCI_SETWHITESPACECHARS = 2443, + + //! + SCI_SETCHARSDEFAULT = 2444, + + //! + SCI_AUTOCGETCURRENT = 2445, + + //! + SCI_ALLOCATE = 2446, + + //! + SCI_HOMEWRAP = 2349, + + //! + SCI_HOMEWRAPEXTEND = 2450, + + //! + SCI_LINEENDWRAP = 2451, + + //! + SCI_LINEENDWRAPEXTEND = 2452, + + //! + SCI_VCHOMEWRAP = 2453, + + //! + SCI_VCHOMEWRAPEXTEND = 2454, + + //! + SCI_LINECOPY = 2455, + + //! + SCI_FINDCOLUMN = 2456, + + //! + SCI_GETCARETSTICKY = 2457, + + //! + SCI_SETCARETSTICKY = 2458, + + //! + SCI_TOGGLECARETSTICKY = 2459, + + //! + SCI_SETWRAPVISUALFLAGS = 2460, + + //! + SCI_GETWRAPVISUALFLAGS = 2461, + + //! + SCI_SETWRAPVISUALFLAGSLOCATION = 2462, + + //! + SCI_GETWRAPVISUALFLAGSLOCATION = 2463, + + //! + SCI_SETWRAPSTARTINDENT = 2464, + + //! + SCI_GETWRAPSTARTINDENT = 2465, + + //! + SCI_MARKERADDSET = 2466, + + //! + SCI_SETPASTECONVERTENDINGS = 2467, + + //! + SCI_GETPASTECONVERTENDINGS = 2468, + + //! + SCI_SELECTIONDUPLICATE = 2469, + + //! + SCI_SETCARETLINEBACKALPHA = 2470, + + //! + SCI_GETCARETLINEBACKALPHA = 2471, + + //! + SCI_MARKERSETALPHA = 2476, + + //! + SCI_GETSELALPHA = 2477, + + //! + SCI_SETSELALPHA = 2478, + + //! + SCI_GETSELEOLFILLED = 2479, + + //! + SCI_SETSELEOLFILLED = 2480, + + //! + SCI_STYLEGETFORE = 2481, + + //! + SCI_STYLEGETBACK = 2482, + + //! + SCI_STYLEGETBOLD = 2483, + + //! + SCI_STYLEGETITALIC = 2484, + + //! + SCI_STYLEGETSIZE = 2485, + + //! + SCI_STYLEGETFONT = 2486, + + //! + SCI_STYLEGETEOLFILLED = 2487, + + //! + SCI_STYLEGETUNDERLINE = 2488, + + //! + SCI_STYLEGETCASE = 2489, + + //! + SCI_STYLEGETCHARACTERSET = 2490, + + //! + SCI_STYLEGETVISIBLE = 2491, + + //! + SCI_STYLEGETCHANGEABLE = 2492, + + //! + SCI_STYLEGETHOTSPOT = 2493, + + //! + SCI_GETHOTSPOTACTIVEFORE = 2494, + + //! + SCI_GETHOTSPOTACTIVEBACK = 2495, + + //! + SCI_GETHOTSPOTACTIVEUNDERLINE = 2496, + + //! + SCI_GETHOTSPOTSINGLELINE = 2497, + + //! + SCI_SETINDICATORCURRENT = 2500, + + //! + SCI_GETINDICATORCURRENT = 2501, + + //! + SCI_SETINDICATORVALUE = 2502, + + //! + SCI_GETINDICATORVALUE = 2503, + + //! + SCI_INDICATORFILLRANGE = 2504, + + //! + SCI_INDICATORCLEARRANGE = 2505, + + //! + SCI_INDICATORALLONFOR = 2506, + + //! + SCI_INDICATORVALUEAT = 2507, + + //! + SCI_INDICATORSTART = 2508, + + //! + SCI_INDICATOREND = 2509, + + //! + SCI_INDICSETUNDER = 2510, + + //! + SCI_INDICGETUNDER = 2511, + + //! + SCI_SETCARETSTYLE = 2512, + + //! + SCI_GETCARETSTYLE = 2513, + + //! + SCI_SETPOSITIONCACHE = 2514, + + //! + SCI_GETPOSITIONCACHE = 2515, + + //! + SCI_SETSCROLLWIDTHTRACKING = 2516, + + //! + SCI_GETSCROLLWIDTHTRACKING = 2517, + + //! + SCI_DELWORDRIGHTEND = 2518, + + //! This message copies the selection. If the selection is empty then + //! copy the line with the caret. + SCI_COPYALLOWLINE = 2519, + + //! This message returns a pointer to the document text. Any + //! subsequent message will invalidate the pointer. + SCI_GETCHARACTERPOINTER = 2520, + + //! + SCI_SETKEYSUNICODE = 2521, + + //! + SCI_GETKEYSUNICODE = 2522, + + //! + SCI_INDICSETALPHA = 2523, + + //! + SCI_INDICGETALPHA = 2524, + + //! + SCI_SETEXTRAASCENT = 2525, + + //! + SCI_GETEXTRAASCENT = 2526, + + //! + SCI_SETEXTRADESCENT = 2527, + + //! + SCI_GETEXTRADESCENT = 2528, + + //! + SCI_MARKERSYMBOLDEFINED = 2529, + + //! + SCI_MARGINSETTEXT = 2530, + + //! + SCI_MARGINGETTEXT = 2531, + + //! + SCI_MARGINSETSTYLE = 2532, + + //! + SCI_MARGINGETSTYLE = 2533, + + //! + SCI_MARGINSETSTYLES = 2534, + + //! + SCI_MARGINGETSTYLES = 2535, + + //! + SCI_MARGINTEXTCLEARALL = 2536, + + //! + SCI_MARGINSETSTYLEOFFSET = 2537, + + //! + SCI_MARGINGETSTYLEOFFSET = 2538, + + //! + SCI_ANNOTATIONSETTEXT = 2540, + + //! + SCI_ANNOTATIONGETTEXT = 2541, + + //! + SCI_ANNOTATIONSETSTYLE = 2542, + + //! + SCI_ANNOTATIONGETSTYLE = 2543, + + //! + SCI_ANNOTATIONSETSTYLES = 2544, + + //! + SCI_ANNOTATIONGETSTYLES = 2545, + + //! + SCI_ANNOTATIONGETLINES = 2546, + + //! + SCI_ANNOTATIONCLEARALL = 2547, + + //! + SCI_ANNOTATIONSETVISIBLE = 2548, + + //! + SCI_ANNOTATIONGETVISIBLE = 2549, + + //! + SCI_ANNOTATIONSETSTYLEOFFSET = 2550, + + //! + SCI_ANNOTATIONGETSTYLEOFFSET = 2551, + + //! + SCI_ADDUNDOACTION = 2560, + + //! + SCI_STARTRECORD = 3001, + + //! + SCI_STOPRECORD = 3002, + + //! This message sets the number of the lexer to use for syntax + //! styling. + //! \a wParam is the number of the lexer and is one of the SCLEX_* + //! values. + SCI_SETLEXER = 4001, + + //! This message returns the number of the lexer being used for syntax + //! styling. + SCI_GETLEXER = 4002, + + //! + SCI_COLOURISE = 4003, + + //! + SCI_SETPROPERTY = 4004, + + //! + SCI_SETKEYWORDS = 4005, + + //! This message sets the name of the lexer to use for syntax styling. + //! \a wParam is unused. + //! \a lParam is the name of the lexer. + SCI_SETLEXERLANGUAGE = 4006, + + //! + SCI_LOADLEXERLIBRARY = 4007, + + //! + SCI_GETPROPERTY = 4008, + + //! + SCI_GETPROPERTYEXPANDED = 4009, + + //! + SCI_GETPROPERTYINT = 4010, + + //! + SCI_GETSTYLEBITSNEEDED = 4011 + }; + + enum + { + SC_ALPHA_TRANSPARENT = 0, + SC_ALPHA_OPAQUE = 255, + SC_ALPHA_NOALPHA = 256 + }; + + enum + { + SC_WRAPVISUALFLAG_NONE = 0x0000, + SC_WRAPVISUALFLAG_END = 0x0001, + SC_WRAPVISUALFLAG_START = 0x0002 + }; + + enum + { + SC_WRAPVISUALFLAGLOC_DEFAULT = 0x0000, + SC_WRAPVISUALFLAGLOC_END_BY_TEXT = 0x0001, + SC_WRAPVISUALFLAGLOC_START_BY_TEXT = 0x0002 + }; + + //! This enum defines the different selection modes. + //! + //! \sa SCI_GETSELECTIONMODE, SCI_SETSELECTIONMODE + enum + { + SC_SEL_STREAM = 0, + SC_SEL_RECTANGLE = 1, + SC_SEL_LINES = 2 + }; + + enum + { + SCWS_INVISIBLE = 0, + SCWS_VISIBLEALWAYS = 1, + SCWS_VISIBLEAFTERINDENT = 2 + }; + + enum + { + SC_EOL_CRLF = 0, + SC_EOL_CR = 1, + SC_EOL_LF = 2 + }; + + enum + { + SC_CP_DBCS = 1, + SC_CP_UTF8 = 65001 + }; + + //! This enum defines the different marker symbols. + //! + //! \sa SCI_MARKERDEFINE + enum + { + //! A circle. + SC_MARK_CIRCLE = 0, + + //! A rectangle. + SC_MARK_ROUNDRECT = 1, + + //! A triangle pointing to the right. + SC_MARK_ARROW = 2, + + //! A smaller rectangle. + SC_MARK_SMALLRECT = 3, + + //! An arrow pointing to the right. + SC_MARK_SHORTARROW = 4, + + //! An invisible marker that allows code to track the movement + //! of lines. + SC_MARK_EMPTY = 5, + + //! A triangle pointing down. + SC_MARK_ARROWDOWN = 6, + + //! A drawn minus sign. + SC_MARK_MINUS = 7, + + //! A drawn plus sign. + SC_MARK_PLUS = 8, + + //! A vertical line drawn in the background colour. + SC_MARK_VLINE = 9, + + //! A bottom left corner drawn in the background colour. + SC_MARK_LCORNER = 10, + + //! A vertical line with a centre right horizontal line drawn + //! in the background colour. + SC_MARK_TCORNER = 11, + + //! A drawn plus sign in a box. + SC_MARK_BOXPLUS = 12, + + //! A drawn plus sign in a connected box. + SC_MARK_BOXPLUSCONNECTED = 13, + + //! A drawn minus sign in a box. + SC_MARK_BOXMINUS = 14, + + //! A drawn minus sign in a connected box. + SC_MARK_BOXMINUSCONNECTED = 15, + + //! A rounded bottom left corner drawn in the background + //! colour. + SC_MARK_LCORNERCURVE = 16, + + //! A vertical line with a centre right curved line drawn in + //! the background colour. + SC_MARK_TCORNERCURVE = 17, + + //! A drawn plus sign in a circle. + SC_MARK_CIRCLEPLUS = 18, + + //! A drawn plus sign in a connected box. + SC_MARK_CIRCLEPLUSCONNECTED = 19, + + //! A drawn minus sign in a circle. + SC_MARK_CIRCLEMINUS = 20, + + //! A drawn minus sign in a connected circle. + SC_MARK_CIRCLEMINUSCONNECTED = 21, + + //! No symbol is drawn but the line of text is drawn with the + //! same background colour. + SC_MARK_BACKGROUND = 22, + + //! Three drawn dots. + SC_MARK_DOTDOTDOT = 23, + + //! Three drawn arrows pointing right. + SC_MARK_ARROWS = 24, + + //! An XPM format pixmap. + SC_MARK_PIXMAP = 25, + + //! A full rectangle (ie. the margin background). + SC_MARK_FULLRECT = 26, + + //! A left rectangle (ie. part of the margin background). + SC_MARK_LEFTRECT = 27, + + //! The value is available for plugins to use. + SC_MARK_AVAILABLE = 28, + + //! Characters can be used as symbols by adding this to the ASCII value + //! of the character. + SC_MARK_CHARACTER = 10000 + }; + + enum + { + SC_MARKNUM_FOLDEREND = 25, + SC_MARKNUM_FOLDEROPENMID = 26, + SC_MARKNUM_FOLDERMIDTAIL = 27, + SC_MARKNUM_FOLDERTAIL = 28, + SC_MARKNUM_FOLDERSUB = 29, + SC_MARKNUM_FOLDER = 30, + SC_MARKNUM_FOLDEROPEN = 31, + SC_MASK_FOLDERS = 0xfe000000 + }; + + //! This enum defines what can be displayed in a margin. + //! + //! \sa SCI_GETMARGINTYPEN, SCI_SETMARGINTYPEN + enum + { + //! The margin can display symbols. Note that all margins can display + //! symbols. + SC_MARGIN_SYMBOL = 0, + + //! The margin will display line numbers. + SC_MARGIN_NUMBER = 1, + + //! The margin's background color will be set to the default background + //! color. + SC_MARGIN_BACK = 2, + + //! The margin's background color will be set to the default foreground + //! color. + SC_MARGIN_FORE = 3, + + //! The margin will display text. + SC_MARGIN_TEXT = 4, + + //! The margin will display right justified text. + SC_MARGIN_RTEXT = 5 + }; + + enum + { + STYLE_DEFAULT = 32, + STYLE_LINENUMBER = 33, + STYLE_BRACELIGHT = 34, + STYLE_BRACEBAD = 35, + STYLE_CONTROLCHAR = 36, + STYLE_INDENTGUIDE = 37, + STYLE_CALLTIP = 38, + STYLE_LASTPREDEFINED = 39, + STYLE_MAX = 255 + }; + + enum + { + SC_CHARSET_ANSI = 0, + SC_CHARSET_DEFAULT = 1, + SC_CHARSET_BALTIC = 186, + SC_CHARSET_CHINESEBIG5 = 136, + SC_CHARSET_EASTEUROPE = 238, + SC_CHARSET_GB2312 = 134, + SC_CHARSET_GREEK = 161, + SC_CHARSET_HANGUL = 129, + SC_CHARSET_MAC = 77, + SC_CHARSET_OEM = 255, + SC_CHARSET_RUSSIAN = 204, + SC_CHARSET_SHIFTJIS = 128, + SC_CHARSET_SYMBOL = 2, + SC_CHARSET_TURKISH = 162, + SC_CHARSET_JOHAB = 130, + SC_CHARSET_HEBREW = 177, + SC_CHARSET_ARABIC = 178, + SC_CHARSET_VIETNAMESE = 163, + SC_CHARSET_THAI = 222, + SC_CHARSET_8859_15 = 1000 + }; + + enum + { + SC_CASE_MIXED = 0, + SC_CASE_UPPER = 1, + SC_CASE_LOWER = 2 + }; + + //! This enum defines the different indentation guide views. + //! + //! \sa SCI_GETINDENTATIONGUIDES, SCI_SETINDENTATIONGUIDES + enum + { + //! No indentation guides are shown. + SC_IV_NONE = 0, + + //! Indentation guides are shown inside real indentation white space. + SC_IV_REAL = 1, + + //! Indentation guides are shown beyond the actual indentation up to + //! the level of the next non-empty line. If the previous non-empty + //! line was a fold header then indentation guides are shown for one + //! more level of indent than that line. This setting is good for + //! Python. + SC_IV_LOOKFORWARD = 2, + + //! Indentation guides are shown beyond the actual indentation up to + //! the level of the next non-empty line or previous non-empty line + //! whichever is the greater. This setting is good for most languages. + SC_IV_LOOKBOTH = 3 + }; + + enum + { + INDIC_MAX = 31, + INDIC_PLAIN = 0, + INDIC_SQUIGGLE = 1, + INDIC_TT = 2, + INDIC_DIAGONAL = 3, + INDIC_STRIKE = 4, + INDIC_HIDDEN = 5, + INDIC_BOX = 6, + INDIC_ROUNDBOX = 7, + INDIC_CONTAINER = 8, + INDIC0_MASK = 0x20, + INDIC1_MASK = 0x40, + INDIC2_MASK = 0x80, + INDICS_MASK = 0xe0 + }; + + enum + { + SC_PRINT_NORMAL = 0, + SC_PRINT_INVERTLIGHT = 1, + SC_PRINT_BLACKONWHITE = 2, + SC_PRINT_COLOURONWHITE = 3, + SC_PRINT_COLOURONWHITEDEFAULTBG = 4 + }; + + enum + { + SCFIND_WHOLEWORD = 2, + SCFIND_MATCHCASE = 4, + SCFIND_WORDSTART = 0x00100000, + SCFIND_REGEXP = 0x00200000, + SCFIND_POSIX = 0x00400000 + }; + + enum + { + SC_FOLDLEVELBASE = 0x00400, + SC_FOLDLEVELWHITEFLAG = 0x01000, + SC_FOLDLEVELHEADERFLAG = 0x02000, + SC_FOLDLEVELNUMBERMASK = 0x00fff + }; + + enum + { + SC_FOLDFLAG_LINEBEFORE_EXPANDED = 0x0002, + SC_FOLDFLAG_LINEBEFORE_CONTRACTED = 0x0004, + SC_FOLDFLAG_LINEAFTER_EXPANDED = 0x0008, + SC_FOLDFLAG_LINEAFTER_CONTRACTED = 0x0010, + SC_FOLDFLAG_LEVELNUMBERS = 0x0040 + }; + + enum + { + SC_TIME_FOREVER = 10000000 + }; + + enum + { + SC_WRAP_NONE = 0, + SC_WRAP_WORD = 1, + SC_WRAP_CHAR = 2 + }; + + enum + { + SC_CACHE_NONE = 0, + SC_CACHE_CARET = 1, + SC_CACHE_PAGE = 2, + SC_CACHE_DOCUMENT = 3 + }; + + enum + { + ANNOTATION_HIDDEN = 0, + ANNOTATION_STANDARD = 1, + ANNOTATION_BOXED = 2 + }; + + enum + { + EDGE_NONE = 0, + EDGE_LINE = 1, + EDGE_BACKGROUND = 2 + }; + + enum + { + SC_CURSORNORMAL = -1, + SC_CURSORWAIT = 4 + }; + + enum + { + UNDO_MAY_COALESCE = 1 + }; + + enum + { + VISIBLE_SLOP = 0x01, + VISIBLE_STRICT = 0x04 + }; + + enum + { + CARET_SLOP = 0x01, + CARET_STRICT = 0x04, + CARET_JUMPS = 0x10, + CARET_EVEN = 0x08 + }; + + enum + { + CARETSTYLE_INVISIBLE = 0, + CARETSTYLE_LINE = 1, + CARETSTYLE_BLOCK = 2 + }; + + enum + { + SC_MOD_INSERTTEXT = 0x1, + SC_MOD_DELETETEXT = 0x2, + SC_MOD_CHANGESTYLE = 0x4, + SC_MOD_CHANGEFOLD = 0x8, + SC_PERFORMED_USER = 0x10, + SC_PERFORMED_UNDO = 0x20, + SC_PERFORMED_REDO = 0x40, + SC_MULTISTEPUNDOREDO = 0x80, + SC_LASTSTEPINUNDOREDO = 0x100, + SC_MOD_CHANGEMARKER = 0x200, + SC_MOD_BEFOREINSERT = 0x400, + SC_MOD_BEFOREDELETE = 0x800, + SC_MULTILINEUNDOREDO = 0x1000, + SC_STARTACTION = 0x2000, + SC_MOD_CHANGEINDICATOR = 0x4000, + SC_MOD_CHANGELINESTATE = 0x8000, + SC_MOD_CHANGEMARGIN = 0x10000, + SC_MOD_CHANGEANNOTATION = 0x20000, + SC_MOD_CONTAINER = 0x40000, + SC_MODEVENTMASKALL = 0x7ffff + }; + + enum + { + SCK_DOWN = 300, + SCK_UP = 301, + SCK_LEFT = 302, + SCK_RIGHT = 303, + SCK_HOME = 304, + SCK_END = 305, + SCK_PRIOR = 306, + SCK_NEXT = 307, + SCK_DELETE = 308, + SCK_INSERT = 309, + SCK_ESCAPE = 7, + SCK_BACK = 8, + SCK_TAB = 9, + SCK_RETURN = 13, + SCK_ADD = 310, + SCK_SUBTRACT = 311, + SCK_DIVIDE = 312, + SCK_WIN = 313, + SCK_RWIN = 314, + SCK_MENU = 315 + }; + + //! This enum defines the different modifier keys. + enum + { + //! No modifier key. + SCMOD_NORM = 0, + + //! Shift key. + SCMOD_SHIFT = 1, + + //! Control key. + SCMOD_CTRL = 2, + + //! Alt key. + SCMOD_ALT = 4 + }; + + //! This enum defines the different language lexers. + //! + //! \sa SCI_GETLEXER, SCI_SETLEXER + enum + { + //! No lexer is selected and the SCN_STYLENEEDED signal is emitted so + //! that the application can style the text as needed. This is the + //! default. + SCLEX_CONTAINER = 0, + + //! Select the null lexer that does no syntax styling. + SCLEX_NULL = 1, + + //! Select the Python lexer. + SCLEX_PYTHON = 2, + + //! Select the C++ lexer. + SCLEX_CPP = 3, + + //! Select the HTML lexer. + SCLEX_HTML = 4, + + //! Select the XML lexer. + SCLEX_XML = 5, + + //! Select the Perl lexer. + SCLEX_PERL = 6, + + //! Select the SQL lexer. + SCLEX_SQL = 7, + + //! Select the Visual Basic lexer. + SCLEX_VB = 8, + + //! Select the lexer for properties style files. + SCLEX_PROPERTIES = 9, + + //! Select the lexer for error list style files. + SCLEX_ERRORLIST = 10, + + //! Select the Makefile lexer. + SCLEX_MAKEFILE = 11, + + //! Select the Windows batch file lexer. + SCLEX_BATCH = 12, + + //! Select the LaTex lexer. + SCLEX_LATEX = 14, + + //! Select the Lua lexer. + SCLEX_LUA = 15, + + //! Select the lexer for diff output. + SCLEX_DIFF = 16, + + //! Select the lexer for Apache configuration files. + SCLEX_CONF = 17, + + //! Select the Pascal lexer. + SCLEX_PASCAL = 18, + + //! Select the Avenue lexer. + SCLEX_AVE = 19, + + //! Select the Ada lexer. + SCLEX_ADA = 20, + + //! Select the Lisp lexer. + SCLEX_LISP = 21, + + //! Select the Ruby lexer. + SCLEX_RUBY = 22, + + //! Select the Eiffel lexer. + SCLEX_EIFFEL = 23, + + //! Select the Eiffel lexer folding at keywords. + SCLEX_EIFFELKW = 24, + + //! Select the Tcl lexer. + SCLEX_TCL = 25, + + //! Select the lexer for nnCron files. + SCLEX_NNCRONTAB = 26, + + //! Select the Bullant lexer. + SCLEX_BULLANT = 27, + + //! Select the VBScript lexer. + SCLEX_VBSCRIPT = 28, + + //! Select the ASP lexer. + SCLEX_ASP = SCLEX_HTML, + + //! Select the PHP lexer. + SCLEX_PHP = SCLEX_HTML, + + //! Select the Baan lexer. + SCLEX_BAAN = 31, + + //! Select the Matlab lexer. + SCLEX_MATLAB = 32, + + //! Select the Scriptol lexer. + SCLEX_SCRIPTOL = 33, + + //! Select the assembler lexer. + SCLEX_ASM = 34, + + //! Select the C++ lexer with case insensitive keywords. + SCLEX_CPPNOCASE = 35, + + //! Select the FORTRAN lexer. + SCLEX_FORTRAN = 36, + + //! Select the FORTRAN77 lexer. + SCLEX_F77 = 37, + + //! Select the CSS lexer. + SCLEX_CSS = 38, + + //! Select the POV lexer. + SCLEX_POV = 39, + + //! Select the Basser Lout typesetting language lexer. + SCLEX_LOUT = 40, + + //! Select the EScript lexer. + SCLEX_ESCRIPT = 41, + + //! Select the PostScript lexer. + SCLEX_PS = 42, + + //! Select the NSIS lexer. + SCLEX_NSIS = 43, + + //! Select the MMIX assembly language lexer. + SCLEX_MMIXAL = 44, + + //! Select the Clarion lexer. + SCLEX_CLW = 45, + + //! Select the Clarion lexer with case insensitive keywords. + SCLEX_CLWNOCASE = 46, + + //! Select the MPT text log file lexer. + SCLEX_LOT = 47, + + //! Select the YAML lexer. + SCLEX_YAML = 48, + + //! Select the TeX lexer. + SCLEX_TEX = 49, + + //! Select the Metapost lexer. + SCLEX_METAPOST = 50, + + //! Select the PowerBASIC lexer. + SCLEX_POWERBASIC = 51, + + //! Select the Forth lexer. + SCLEX_FORTH = 52, + + //! Select the Erlang lexer. + SCLEX_ERLANG = 53, + + //! Select the Octave lexer. + SCLEX_OCTAVE = 54, + + //! Select the MS SQL lexer. + SCLEX_MSSQL = 55, + + //! Select the Verilog lexer. + SCLEX_VERILOG = 56, + + //! Select the KIX-Scripts lexer. + SCLEX_KIX = 57, + + //! Select the Gui4Cli lexer. + SCLEX_GUI4CLI = 58, + + //! Select the Specman E lexer. + SCLEX_SPECMAN = 59, + + //! Select the AutoIt3 lexer. + SCLEX_AU3 = 60, + + //! Select the APDL lexer. + SCLEX_APDL = 61, + + //! Select the Bash lexer. + SCLEX_BASH = 62, + + //! Select the ASN.1 lexer. + SCLEX_ASN1 = 63, + + //! Select the VHDL lexer. + SCLEX_VHDL = 64, + + //! Select the Caml lexer. + SCLEX_CAML = 65, + + //! Select the BlitzBasic lexer. + SCLEX_BLITZBASIC = 66, + + //! Select the PureBasic lexer. + SCLEX_PUREBASIC = 67, + + //! Select the Haskell lexer. + SCLEX_HASKELL = 68, + + //! Select the PHPScript lexer. + SCLEX_PHPSCRIPT = 69, + + //! Select the TADS3 lexer. + SCLEX_TADS3 = 70, + + //! Select the REBOL lexer. + SCLEX_REBOL = 71, + + //! Select the Smalltalk lexer. + SCLEX_SMALLTALK = 72, + + //! Select the FlagShip lexer. + SCLEX_FLAGSHIP = 73, + + //! Select the Csound lexer. + SCLEX_CSOUND = 74, + + //! Select the FreeBasic lexer. + SCLEX_FREEBASIC = 75, + + //! Select the InnoSetup lexer. + SCLEX_INNOSETUP = 76, + + //! Select the Opal lexer. + SCLEX_OPAL = 77, + + //! Select the Spice lexer. + SCLEX_SPICE = 78, + + //! Select the D lexer. + SCLEX_D = 79, + + //! Select the CMake lexer. + SCLEX_CMAKE = 80, + + //! Select the GAP lexer. + SCLEX_GAP = 81, + + //! Select the PLM lexer. + SCLEX_PLM = 82, + + //! Select the Progress lexer. + SCLEX_PROGRESS = 83, + + //! Select the Abaqus lexer. + SCLEX_ABAQUS = 84, + + //! Select the Asymptote lexer. + SCLEX_ASYMPTOTE = 85, + + //! Select the R lexer. + SCLEX_R = 86, + + //! Select the MagikSF lexer. + SCLEX_MAGIK = 87, + + //! Select the PowerShell lexer. + SCLEX_POWERSHELL = 88, + + //! Select the MySQL lexer. + SCLEX_MYSQL = 89, + + //! Select the gettext .po file lexer. + SCLEX_PO = 90, + + //! Select the TAL lexer. + SCLEX_TAL = 91, + + //! Select the COBOL lexer. + SCLEX_COBOL = 92, + + //! Select the TACL lexer. + SCLEX_TACL = 93, + + //! Select the Sorcus lexer. + SCLEX_SORCUS = 94, + + //! Select the PowerPro lexer. + SCLEX_POWERPRO = 95, + + //! Select the Nimrod lexer. + SCLEX_NIMROD = 96, + + //! Select the SML lexer. + SCLEX_SML = 97 + }; + + //! Construct an empty QsciScintillaBase with parent \a parent. + explicit QsciScintillaBase(QWidget *parent = 0); + + //! Destroys the QsciScintillaBase instance. + virtual ~QsciScintillaBase(); + + //! Returns a pointer to a QsciScintillaBase instance, or 0 if there isn't + //! one. This can be used by the higher level API to send messages that + //! aren't associated with a particular instance. + static QsciScintillaBase *pool(); + + //! Send the Scintilla message \a msg with the optional parameters \a + //! wParam and \a lParam. + long SendScintilla(unsigned int msg, unsigned long wParam = 0, + long lParam = 0) const; + + //! \overload + long SendScintilla(unsigned int msg, unsigned long wParam, + void *lParam) const; + + //! \overload + long SendScintilla(unsigned int msg, unsigned long wParam, + const char *lParam) const; + + //! \overload + long SendScintilla(unsigned int msg, const char *lParam) const; + + //! \overload + long SendScintilla(unsigned int msg, const char *wParam, + const char *lParam) const; + + //! \overload + long SendScintilla(unsigned int msg, long wParam) const; + + //! \overload + long SendScintilla(unsigned int msg, int wParam) const; + + //! \overload + long SendScintilla(unsigned int msg, long cpMin, long cpMax, + char *lpstrText) const; + + //! \overload + long SendScintilla(unsigned int msg, unsigned long wParam, + const QColor &col) const; + + //! \overload + long SendScintilla(unsigned int msg, const QColor &col) const; + + //! \overload + long SendScintilla(unsigned int msg, unsigned long wParam, QPainter *hdc, + const QRect &rc, long cpMin, long cpMax) const; + + //! \overload + long SendScintilla(unsigned int msg, unsigned long wParam, + const QPixmap &lParam) const; + + //! Send the Scintilla message \a msg and return a pointer result. + void *SendScintillaPtrResult(unsigned int msg) const; + + +signals: + //! This signal is emitted when text is selected or de-selected. + //! \a yes is true if text has been selected and false if text has been + //! deselected. + void QSCN_SELCHANGED(bool yes); + + //! This signal is emitted when the user cancels an auto-completion list. + //! + //! \sa SCN_AUTOCSELECTION() + void SCN_AUTOCCANCELLED(); + + //! This signal is emitted when the user deletes a character when an + //! auto-completion list is active. + void SCN_AUTOCCHARDELETED(); + + //! This signal is emitted when the user selects an item in an + //! auto-completion list. It is emitted before the selection is inserted. + //! The insertion can be cancelled by sending an SCI_AUTOCANCEL message + //! from a connected slot. + //! \a selection is the text of the selection. + //! \a position is the start position of the word being completed. + //! + //! \sa SCN_AUTOCCANCELLED() + void SCN_AUTOCSELECTION(const char *selection, int position); + + //! This signal is emitted when the document has changed for any reason. + void SCEN_CHANGE(); + + //! This signal ir emitted when the user clicks on a calltip. + //! \a direction is 1 if the user clicked on the up arrow, 2 if the user + //! clicked on the down arrow, and 0 if the user clicked elsewhere. + void SCN_CALLTIPCLICK(int direction); + + //! This signal is emitted whenever the user enters an ordinary character + //! into the text. + //! \a charadded is the character. It can be used to decide to display a + //! call tip or an auto-completion list. + void SCN_CHARADDED(int charadded); + + //! This signal is emitted when the user double clicks. + //! \a position is the position in the text where the click occured. + //! \a line is the number of the line in the text where the click occured. + //! \a modifiers is the logical or of the modifier keys that were pressed + //! when the user double clicked. + void SCN_DOUBLECLICK(int position, int line, int modifiers); + + //! + void SCN_DWELLEND(int, int, int); + + //! + void SCN_DWELLSTART(int, int, int); + + //! This signal is emitted when the user clicks on text in a style with the + //! hotspot attribute set. + //! \a position is the position in the text where the click occured. + //! \a modifiers is the logical or of the modifier keys that were pressed + //! when the user clicked. + void SCN_HOTSPOTCLICK(int position, int modifiers); + + //! This signal is emitted when the user double clicks on text in a style + //! with the hotspot attribute set. + //! \a position is the position in the text where the double click occured. + //! \a modifiers is the logical or of the modifier keys that were pressed + //! when the user double clicked. + void SCN_HOTSPOTDOUBLECLICK(int position, int modifiers); + + //! This signal is emitted when the user clicks on text that has an + //! indicator. + //! \a position is the position in the text where the click occured. + //! \a modifiers is the logical or of the modifier keys that were pressed + //! when the user clicked. + void SCN_INDICATORCLICK(int position, int modifiers); + + //! This signal is emitted when the user releases the mouse button on text + //! that has an indicator. + //! \a position is the position in the text where the release occured. + //! \a modifiers is the logical or of the modifier keys that were pressed + //! when the user released. + void SCN_INDICATORRELEASE(int position, int modifiers); + + //! This signal is emitted when a recordable editor command has been + //! executed. + void SCN_MACRORECORD(unsigned int, unsigned long, void *); + + //! This signal is emitted when the user clicks on a sensitive margin. + //! \a position is the position of the start of the line against which the + //! user clicked. + //! \a modifiers is the logical or of the modifier keys that were pressed + //! when the user clicked. + //! \a margin is the number of the margin the user clicked in: 0, 1 or 2. + //! + //! \sa SCI_GETMARGINSENSITIVEN, SCI_SETMARGINSENSITIVEN + void SCN_MARGINCLICK(int position, int modifiers, int margin); + + //! + void SCN_MODIFIED(int, int, const char *, int, int, int, int, int, int, int); + + //! This signal is emitted when the user attempts to modify read-only + //! text. + void SCN_MODIFYATTEMPTRO(); + + //! + void SCN_NEEDSHOWN(int, int); + + //! This signal is emitted when painting has been completed. It is useful + //! to trigger some other change but to have the paint be done first to + //! appear more reponsive to the user. + void SCN_PAINTED(); + + //! This signal is emitted when the current state of the text no longer + //! corresponds to the state of the text at the save point. + //! + //! \sa SCI_SETSAVEPOINT, SCN_SAVEPOINTREACHED() + void SCN_SAVEPOINTLEFT(); + + //! This signal is emitted when the current state of the text corresponds + //! to the state of the text at the save point. This allows feedback to be + //! given to the user as to whether the text has been modified since it was + //! last saved. + //! + //! \sa SCI_SETSAVEPOINT, SCN_SAVEPOINTLEFT() + void SCN_SAVEPOINTREACHED(); + + //! This signal is emitted when a range of text needs to be syntax styled. + //! The range is from the value returned by the SCI_GETENDSTYLED message + //! and \a position. It is only emitted if the currently selected lexer is + //! SCLEX_CONTAINER. + //! + //! \sa SCI_COLOURISE, SCI_GETENDSTYLED + void SCN_STYLENEEDED(int position); + + //! + void SCN_UPDATEUI(); + + //! + void SCN_USERLISTSELECTION(const char *, int); + + //! + void SCN_ZOOM(); + +protected: + //! Returns true if the contents of a MIME data object can be decoded and + //! inserted into the document. It is called during drag and paste + //! operations. + //! \a source is the MIME data object. + //! + //! \sa fromMimeData(), toMimeData() + virtual bool canInsertFromMimeData(const QMimeData *source) const; + + //! Returns the text decoded from a MIME data object. It is called when a + //! drag and drop is completed and when text is pasted from the clipboard. + //! \a source is the MIME data object. + //! + //! \sa canInsertFromMimeData(), toMimeData() + virtual QString fromMimeData(const QMimeData *source) const; + + //! Returns a new MIME data object that encodes some text. It is called + //! when a drag and drop is started and when the selection is copied to the + //! clipboard. Ownership of the object is passed to the caller. + //! \a text is the text to encode. + //! + //! \sa canInsertFromMimeData(), fromMimeData() + virtual QMimeData *toMimeData(const QString &text) const; + + //! Re-implemented to handle the context menu. + virtual void contextMenuEvent(QContextMenuEvent *e); + + //! Re-implemented to handle drag enters. + virtual void dragEnterEvent(QDragEnterEvent *e); + + //! Re-implemented to handle drag leaves. + virtual void dragLeaveEvent(QDragLeaveEvent *e); + + //! Re-implemented to handle drag moves. + virtual void dragMoveEvent(QDragMoveEvent *e); + + //! Re-implemented to handle drops. + virtual void dropEvent(QDropEvent *e); + + //! Re-implemented to tell Scintilla it has the focus. + virtual void focusInEvent(QFocusEvent *e); + + //! Re-implemented to tell Scintilla it has lost the focus. + virtual void focusOutEvent(QFocusEvent *e); + + //! Re-implemented to allow tabs to be entered as text. + virtual bool focusNextPrevChild(bool next); + + //! Re-implemented to handle key presses. + virtual void keyPressEvent(QKeyEvent *e); + + //! Re-implemented to handle composed characters. + virtual void inputMethodEvent(QInputMethodEvent *e); + + //! Re-implemented to handle mouse double-clicks. + virtual void mouseDoubleClickEvent(QMouseEvent *e); + + //! Re-implemented to handle mouse moves. + virtual void mouseMoveEvent(QMouseEvent *e); + + //! Re-implemented to handle mouse presses. + virtual void mousePressEvent(QMouseEvent *e); + + //! Re-implemented to handle mouse releases. + virtual void mouseReleaseEvent(QMouseEvent *e); + + //! Re-implemented to paint the viewport. + virtual void paintEvent(QPaintEvent *e); + + //! Re-implemented to handle resizes. + virtual void resizeEvent(QResizeEvent *e); + + //! \internal Re-implemented to handle scrolling. + virtual void scrollContentsBy(int dx, int dy); + +private slots: + void handleTimer(); + void handleVSb(int value); + void handleHSb(int value); + void handleSelection(); + +private: + // This is needed to allow ScintillaQt to emit this class's signals. + friend class ScintillaQt; + + ScintillaQt *sci; + QPoint triple_click_at; + QTimer triple_click; + + void acceptAction(QDropEvent *e); + + QsciScintillaBase(const QsciScintillaBase &); + QsciScintillaBase &operator=(const QsciScintillaBase &); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscistyle.cpp b/harbour/contrib/hbide/qscintilla/qt/qscistyle.cpp new file mode 100644 index 0000000000..15d8e98adf --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscistyle.cpp @@ -0,0 +1,245 @@ +// This module implements the QsciStyle class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscistyle.h" + +#include + +#include "qsciscintillabase.h" + + +// A ctor. +QsciStyle::QsciStyle(int style) +{ + init(style); + + QPalette pal = QApplication::palette(); + setColor(pal.text().color()); + setPaper(pal.base().color()); + + setFont(QApplication::font()); + setEolFill(false); +} + + +// A ctor. +QsciStyle::QsciStyle(int style, const QString &description, + const QColor &color, const QColor &paper, const QFont &font, + bool eol_fill) +{ + init(style); + + setDescription(description); + + setColor(color); + setPaper(paper); + + setFont(font); + setEolFill(eol_fill); +} + + +// Initialisation common to all ctors. +void QsciStyle::init(int style) +{ + // The next style number to allocate. + static int next_style_nr = QsciScintillaBase::STYLE_MAX; + + // See if a new style should be allocated. Note that we allow styles to be + // passed in that are bigger than STYLE_MAX because the styles used for + // annotations are allowed to be. + if (style < 0) + { + // Note that we don't deal with the situation where the newly allocated + // style number has already been used explicitly. + if (next_style_nr > QsciScintillaBase::STYLE_LASTPREDEFINED) + style = next_style_nr--; + } + + style_nr = style; + + // Initialise the minor attributes. + setTextCase(QsciStyle::OriginalCase); + setVisible(true); + setChangeable(true); + setHotspot(false); +} + + +// Set the color attribute. +void QsciStyle::setColor(const QColor &color) +{ + style_color = color; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFORE, style_nr, + style_color); + } +} + + +// Set the paper attribute. +void QsciStyle::setPaper(const QColor &paper) +{ + style_paper = paper; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETBACK, style_nr, + style_paper); + } +} + + +// Set the font attribute. +void QsciStyle::setFont(const QFont &font) +{ + style_font = font; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + { + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETFONT, style_nr, + style_font.family().toAscii().data()); + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETSIZE, style_nr, + style_font.pointSize()); + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETBOLD, style_nr, + style_font.bold()); + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETITALIC, style_nr, + style_font.italic()); + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETUNDERLINE, + style_nr, style_font.underline()); + } + } +} + + +// Set the eol fill attribute. +void QsciStyle::setEolFill(bool eol_fill) +{ + style_eol_fill = eol_fill; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETEOLFILLED, + style_nr, style_eol_fill); + } +} + + +// Set the text case attribute. +void QsciStyle::setTextCase(QsciStyle::TextCase text_case) +{ + style_case = text_case; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETCASE, style_nr, + (long)style_case); + } +} + + +// Set the visible attribute. +void QsciStyle::setVisible(bool visible) +{ + style_visible = visible; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETVISIBLE, + style_nr, style_visible); + } +} + + +// Set the changeable attribute. +void QsciStyle::setChangeable(bool changeable) +{ + style_changeable = changeable; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETCHANGEABLE, + style_nr, style_changeable); + } +} + + +// Set the hotspot attribute. +void QsciStyle::setHotspot(bool hotspot) +{ + style_hotspot = hotspot; + + if (style_nr >= 0) + { + QsciScintillaBase *sci = QsciScintillaBase::pool(); + + if (sci) + sci->SendScintilla(QsciScintillaBase::SCI_STYLESETHOTSPOT, + style_nr, style_hotspot); + } +} + + +// Refresh the style. +void QsciStyle::refresh() +{ + setColor(color()); + setPaper(paper()); + setFont(font()); + setEolFill(eolFill()); + setTextCase(textCase()); + setVisible(visible()); + setChangeable(changeable()); + setHotspot(hotspot()); +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscistyle.h b/harbour/contrib/hbide/qscintilla/qt/qscistyle.h new file mode 100644 index 0000000000..24a876323b --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscistyle.h @@ -0,0 +1,201 @@ +// This module defines interface to the QsciStyle class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCISTYLE_H +#define QSCISTYLE_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include +#include +#include + +#include + + +//! \brief The QsciStyle class encapsulates all the attributes of a style. +//! +//! Each character of a document has an associated style which determines how +//! the character is displayed, e.g. its font and color. A style is identified +//! by a number. Lexers define styles for each of the language's features so +//! that they are displayed differently. Some style numbers have hard-coded +//! meanings, e.g. the style used for call tips. +class QSCINTILLA_EXPORT QsciStyle +{ +public: + //! This enum defines the different ways the displayed case of the text can + //! be changed. + enum TextCase { + //! The text is displayed as its original case. + OriginalCase = 0, + + //! The text is displayed as upper case. + UpperCase = 1, + + //! The text is displayed as lower case. + LowerCase = 2 + }; + + //! Constructs a QsciStyle instance for style number \a style. If \a style + //! is negative then a new style number is automatically allocated. + QsciStyle(int style = -1); + + //! Constructs a QsciStyle instance for style number \a style. If \a style + //! is negative then a new style number is automatically allocated. The + //! styles description, color, paper color, font and end-of-line fill are + //! set to \a description, \a color, \a paper, \a font and \a eol_fill + //! respectively. + QsciStyle(int style, const QString &description, const QColor &color, + const QColor &paper, const QFont &font, bool eol_fill = false); + + //! Returns the number of the style. + int style() const {return style_nr;} + + //! The style's description is set to \a description. + //! + //! \sa description() + void setDescription(const QString &description) {style_description = description;} + + //! Returns the style's description. + //! + //! \sa setDescription() + QString description() const {return style_description;} + + //! The style's foreground color is set to \a color. The default is taken + //! from the application's default palette. + //! + //! \sa color() + void setColor(const QColor &color); + + //! Returns the style's foreground color. + //! + //! \sa setColor() + QColor color() const {return style_color;} + + //! The style's background color is set to \a paper. The default is taken + //! from the application's default palette. + //! + //! \sa paper() + void setPaper(const QColor &paper); + + //! Returns the style's background color. + //! + //! \sa setPaper() + QColor paper() const {return style_paper;} + + //! The style's font is set to \a font. The default is the application's + //! default font. + //! + //! \sa font() + void setFont(const QFont &font); + + //! Returns the style's font. + //! + //! \sa setFont() + QFont font() const {return style_font;} + + //! The style's end-of-line fill is set to \a fill. The default is false. + //! + //! \sa eolFill() + void setEolFill(bool fill); + + //! Returns the style's end-of-line fill. + //! + //! \sa setEolFill() + bool eolFill() const {return style_eol_fill;} + + //! The style's text case is set to \a text_case. The default is + //! OriginalCase. + //! + //! \sa textCase() + void setTextCase(TextCase text_case); + + //! Returns the style's text case. + //! + //! \sa setTextCase() + TextCase textCase() const {return style_case;} + + //! The style's visibility is set to \a visible. The default is true. + //! + //! \sa visible() + void setVisible(bool visible); + + //! Returns the style's visibility. + //! + //! \sa setVisible() + bool visible() const {return style_visible;} + + //! The style's changeability is set to \a changeable. The default is + //! true. + //! + //! \sa changeable() + void setChangeable(bool changeable); + + //! Returns the style's changeability. + //! + //! \sa setChangeable() + bool changeable() const {return style_changeable;} + + //! The style's sensitivity to mouse clicks is set to \a hotspot. The + //! default is false. + //! + //! \sa hotspot() + void setHotspot(bool hotspot); + + //! Returns the style's sensitivity to mouse clicks. + //! + //! \sa setHotspot() + bool hotspot() const {return style_hotspot;} + + //! Refresh the style settings. + void refresh(); + +private: + int style_nr; + QString style_description; + QColor style_color; + QColor style_paper; + QFont style_font; + bool style_eol_fill; + TextCase style_case; + bool style_visible; + bool style_changeable; + bool style_hotspot; + + void init(int style); +}; + +#ifdef __APPLE__ +} +#endif + +#endif diff --git a/harbour/contrib/hbide/qscintilla/qt/qscistyledtext.cpp b/harbour/contrib/hbide/qscintilla/qt/qscistyledtext.cpp new file mode 100644 index 0000000000..d190ce25a1 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscistyledtext.cpp @@ -0,0 +1,47 @@ +// This module implements the QsciStyledText class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#include "qscistyledtext.h" + +#include "qscistyle.h" + + +// A ctor. +QsciStyledText::QsciStyledText(const QString &text, int style) + : styled_text(text), style_nr(style) +{ +} + + +// A ctor. +QsciStyledText::QsciStyledText(const QString &text, const QsciStyle &style) + : styled_text(text), style_nr(style.style()) +{ +} diff --git a/harbour/contrib/hbide/qscintilla/qt/qscistyledtext.h b/harbour/contrib/hbide/qscintilla/qt/qscistyledtext.h new file mode 100644 index 0000000000..e164748d79 --- /dev/null +++ b/harbour/contrib/hbide/qscintilla/qt/qscistyledtext.h @@ -0,0 +1,75 @@ +// This module defines interface to the QsciStyledText class. +// +// Copyright (c) 2010 Riverbank Computing Limited +// +// This file is part of QScintilla. +// +// This file may be used under the terms of the GNU General Public +// License versions 2.0 or 3.0 as published by the Free Software +// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 +// included in the packaging of this file. Alternatively you may (at +// your option) use any later version of the GNU General Public +// License if such license has been publicly approved by Riverbank +// Computing Limited (or its successors, if any) and the KDE Free Qt +// Foundation. In addition, as a special exception, Riverbank gives you +// certain additional rights. These rights are described in the Riverbank +// GPL Exception version 1.1, which can be found in the file +// GPL_EXCEPTION.txt in this package. +// +// Please review the following information to ensure GNU General +// Public Licensing requirements will be met: +// http://trolltech.com/products/qt/licenses/licensing/opensource/. If +// you are unsure which license is appropriate for your use, please +// review the following information: +// http://trolltech.com/products/qt/licenses/licensing/licensingoverview +// or contact the sales department at sales@riverbankcomputing.com. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +#ifndef QSCISTYLEDTEXT_H +#define QSCISTYLEDTEXT_H + +#ifdef __APPLE__ +extern "C++" { +#endif + +#include + +#include + + +class QsciStyle; + + +//! \brief The QsciStyledText class is a container for a piece of text and the +//! style used to display the text. +class QSCINTILLA_EXPORT QsciStyledText +{ +public: + //! Constructs a QsciStyledText instance for text \a text and style number + //! \a style. + QsciStyledText(const QString &text, int style); + + //! Constructs a QsciStyledText instance for text \a text and style \a + //! style. + QsciStyledText(const QString &text, const QsciStyle &style); + + + //! Returns a reference to the text. + const QString &text() const {return styled_text;} + + //! Returns the number of the style. + int style() const {return style_nr;} + +private: + QString styled_text; + int style_nr; +}; + +#ifdef __APPLE__ +} +#endif + +#endif