From 9ce192d417eb9eb614bcf8510e91dac318706249 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Thu, 9 Mar 2000 19:42:06 +0000 Subject: [PATCH] Initial version of wxStyledTextCtrl, a Scintilla wrapper. There is still LOTS and LOTS to be done, but this is already very functional. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6555 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- contrib/include/wx/stc/stc.h | 547 +++ contrib/samples/stc/.cvsignore | 1 + contrib/samples/stc/makefile.vc | 14 + contrib/samples/stc/stctest.cpp | 204 + contrib/samples/stc/stctest.rc | 1 + contrib/src/stc/PlatWX.cpp | 585 +++ contrib/src/stc/README.txt | 47 + contrib/src/stc/ScintillaWX.cpp | 457 ++ contrib/src/stc/ScintillaWX.h | 148 + contrib/src/stc/makefile.vc | 106 + contrib/src/stc/scintilla/README.txt | 7 + contrib/src/stc/scintilla/include/Accessor.h | 76 + contrib/src/stc/scintilla/include/KeyWords.h | 8 + contrib/src/stc/scintilla/include/Platform.h | 392 ++ contrib/src/stc/scintilla/include/PropSet.h | 180 + contrib/src/stc/scintilla/include/SciLexer.h | 134 + contrib/src/stc/scintilla/include/Scintilla.h | 415 ++ contrib/src/stc/scintilla/include/WinDefs.h | 218 + contrib/src/stc/scintilla/src/Accessor.cxx | 112 + .../src/stc/scintilla/src/AutoComplete.cxx | 104 + contrib/src/stc/scintilla/src/AutoComplete.h | 43 + contrib/src/stc/scintilla/src/CallTip.cxx | 168 + contrib/src/stc/scintilla/src/CallTip.h | 46 + contrib/src/stc/scintilla/src/CellBuffer.cxx | 950 +++++ contrib/src/stc/scintilla/src/CellBuffer.h | 197 + .../stc/scintilla/src/ContractionState.cxx | 203 + .../src/stc/scintilla/src/ContractionState.h | 50 + contrib/src/stc/scintilla/src/Document.cxx | 734 ++++ contrib/src/stc/scintilla/src/Document.h | 222 + contrib/src/stc/scintilla/src/Editor.cxx | 3693 +++++++++++++++++ contrib/src/stc/scintilla/src/Editor.h | 281 ++ contrib/src/stc/scintilla/src/Indicator.cxx | 45 + contrib/src/stc/scintilla/src/Indicator.h | 18 + contrib/src/stc/scintilla/src/KeyMap.cxx | 111 + contrib/src/stc/scintilla/src/KeyMap.h | 35 + contrib/src/stc/scintilla/src/KeyWords.cxx | 2217 ++++++++++ contrib/src/stc/scintilla/src/LineMarker.cxx | 125 + contrib/src/stc/scintilla/src/LineMarker.h | 22 + contrib/src/stc/scintilla/src/PropSet.cxx | 399 ++ contrib/src/stc/scintilla/src/SVector.h | 110 + .../src/stc/scintilla/src/ScintillaBase.cxx | 399 ++ contrib/src/stc/scintilla/src/ScintillaBase.h | 68 + contrib/src/stc/scintilla/src/Style.cxx | 63 + contrib/src/stc/scintilla/src/Style.h | 37 + contrib/src/stc/scintilla/src/ViewStyle.cxx | 183 + contrib/src/stc/scintilla/src/ViewStyle.h | 59 + contrib/src/stc/stc.cpp | 1386 +++++++ include/wx/stc/stc.h | 547 +++ samples/stc/.cvsignore | 1 + samples/stc/makefile.vc | 14 + samples/stc/stctest.cpp | 204 + samples/stc/stctest.rc | 1 + src/stc/PlatWX.cpp | 585 +++ src/stc/README.txt | 47 + src/stc/ScintillaWX.cpp | 457 ++ src/stc/ScintillaWX.h | 148 + src/stc/makefile.vc | 106 + src/stc/scintilla/README.txt | 7 + src/stc/scintilla/include/Accessor.h | 76 + src/stc/scintilla/include/KeyWords.h | 8 + src/stc/scintilla/include/Platform.h | 392 ++ src/stc/scintilla/include/PropSet.h | 180 + src/stc/scintilla/include/SciLexer.h | 134 + src/stc/scintilla/include/Scintilla.h | 415 ++ src/stc/scintilla/include/WinDefs.h | 218 + src/stc/scintilla/src/Accessor.cxx | 112 + src/stc/scintilla/src/AutoComplete.cxx | 104 + src/stc/scintilla/src/AutoComplete.h | 43 + src/stc/scintilla/src/CallTip.cxx | 168 + src/stc/scintilla/src/CallTip.h | 46 + src/stc/scintilla/src/CellBuffer.cxx | 950 +++++ src/stc/scintilla/src/CellBuffer.h | 197 + src/stc/scintilla/src/ContractionState.cxx | 203 + src/stc/scintilla/src/ContractionState.h | 50 + src/stc/scintilla/src/Document.cxx | 734 ++++ src/stc/scintilla/src/Document.h | 222 + src/stc/scintilla/src/Editor.cxx | 3693 +++++++++++++++++ src/stc/scintilla/src/Editor.h | 281 ++ src/stc/scintilla/src/Indicator.cxx | 45 + src/stc/scintilla/src/Indicator.h | 18 + src/stc/scintilla/src/KeyMap.cxx | 111 + src/stc/scintilla/src/KeyMap.h | 35 + src/stc/scintilla/src/KeyWords.cxx | 2217 ++++++++++ src/stc/scintilla/src/LineMarker.cxx | 125 + src/stc/scintilla/src/LineMarker.h | 22 + src/stc/scintilla/src/PropSet.cxx | 399 ++ src/stc/scintilla/src/SVector.h | 110 + src/stc/scintilla/src/ScintillaBase.cxx | 399 ++ src/stc/scintilla/src/ScintillaBase.h | 68 + src/stc/scintilla/src/Style.cxx | 63 + src/stc/scintilla/src/Style.h | 37 + src/stc/scintilla/src/ViewStyle.cxx | 183 + src/stc/scintilla/src/ViewStyle.h | 59 + src/stc/stc.cpp | 1386 +++++++ 94 files changed, 31240 insertions(+) create mode 100644 contrib/include/wx/stc/stc.h create mode 100644 contrib/samples/stc/.cvsignore create mode 100644 contrib/samples/stc/makefile.vc create mode 100644 contrib/samples/stc/stctest.cpp create mode 100644 contrib/samples/stc/stctest.rc create mode 100644 contrib/src/stc/PlatWX.cpp create mode 100644 contrib/src/stc/README.txt create mode 100644 contrib/src/stc/ScintillaWX.cpp create mode 100644 contrib/src/stc/ScintillaWX.h create mode 100644 contrib/src/stc/makefile.vc create mode 100644 contrib/src/stc/scintilla/README.txt create mode 100644 contrib/src/stc/scintilla/include/Accessor.h create mode 100644 contrib/src/stc/scintilla/include/KeyWords.h create mode 100644 contrib/src/stc/scintilla/include/Platform.h create mode 100644 contrib/src/stc/scintilla/include/PropSet.h create mode 100644 contrib/src/stc/scintilla/include/SciLexer.h create mode 100644 contrib/src/stc/scintilla/include/Scintilla.h create mode 100644 contrib/src/stc/scintilla/include/WinDefs.h create mode 100644 contrib/src/stc/scintilla/src/Accessor.cxx create mode 100644 contrib/src/stc/scintilla/src/AutoComplete.cxx create mode 100644 contrib/src/stc/scintilla/src/AutoComplete.h create mode 100644 contrib/src/stc/scintilla/src/CallTip.cxx create mode 100644 contrib/src/stc/scintilla/src/CallTip.h create mode 100644 contrib/src/stc/scintilla/src/CellBuffer.cxx create mode 100644 contrib/src/stc/scintilla/src/CellBuffer.h create mode 100644 contrib/src/stc/scintilla/src/ContractionState.cxx create mode 100644 contrib/src/stc/scintilla/src/ContractionState.h create mode 100644 contrib/src/stc/scintilla/src/Document.cxx create mode 100644 contrib/src/stc/scintilla/src/Document.h create mode 100644 contrib/src/stc/scintilla/src/Editor.cxx create mode 100644 contrib/src/stc/scintilla/src/Editor.h create mode 100644 contrib/src/stc/scintilla/src/Indicator.cxx create mode 100644 contrib/src/stc/scintilla/src/Indicator.h create mode 100644 contrib/src/stc/scintilla/src/KeyMap.cxx create mode 100644 contrib/src/stc/scintilla/src/KeyMap.h create mode 100644 contrib/src/stc/scintilla/src/KeyWords.cxx create mode 100644 contrib/src/stc/scintilla/src/LineMarker.cxx create mode 100644 contrib/src/stc/scintilla/src/LineMarker.h create mode 100644 contrib/src/stc/scintilla/src/PropSet.cxx create mode 100644 contrib/src/stc/scintilla/src/SVector.h create mode 100644 contrib/src/stc/scintilla/src/ScintillaBase.cxx create mode 100644 contrib/src/stc/scintilla/src/ScintillaBase.h create mode 100644 contrib/src/stc/scintilla/src/Style.cxx create mode 100644 contrib/src/stc/scintilla/src/Style.h create mode 100644 contrib/src/stc/scintilla/src/ViewStyle.cxx create mode 100644 contrib/src/stc/scintilla/src/ViewStyle.h create mode 100644 contrib/src/stc/stc.cpp create mode 100644 include/wx/stc/stc.h create mode 100644 samples/stc/.cvsignore create mode 100644 samples/stc/makefile.vc create mode 100644 samples/stc/stctest.cpp create mode 100644 samples/stc/stctest.rc create mode 100644 src/stc/PlatWX.cpp create mode 100644 src/stc/README.txt create mode 100644 src/stc/ScintillaWX.cpp create mode 100644 src/stc/ScintillaWX.h create mode 100644 src/stc/makefile.vc create mode 100644 src/stc/scintilla/README.txt create mode 100644 src/stc/scintilla/include/Accessor.h create mode 100644 src/stc/scintilla/include/KeyWords.h create mode 100644 src/stc/scintilla/include/Platform.h create mode 100644 src/stc/scintilla/include/PropSet.h create mode 100644 src/stc/scintilla/include/SciLexer.h create mode 100644 src/stc/scintilla/include/Scintilla.h create mode 100644 src/stc/scintilla/include/WinDefs.h create mode 100644 src/stc/scintilla/src/Accessor.cxx create mode 100644 src/stc/scintilla/src/AutoComplete.cxx create mode 100644 src/stc/scintilla/src/AutoComplete.h create mode 100644 src/stc/scintilla/src/CallTip.cxx create mode 100644 src/stc/scintilla/src/CallTip.h create mode 100644 src/stc/scintilla/src/CellBuffer.cxx create mode 100644 src/stc/scintilla/src/CellBuffer.h create mode 100644 src/stc/scintilla/src/ContractionState.cxx create mode 100644 src/stc/scintilla/src/ContractionState.h create mode 100644 src/stc/scintilla/src/Document.cxx create mode 100644 src/stc/scintilla/src/Document.h create mode 100644 src/stc/scintilla/src/Editor.cxx create mode 100644 src/stc/scintilla/src/Editor.h create mode 100644 src/stc/scintilla/src/Indicator.cxx create mode 100644 src/stc/scintilla/src/Indicator.h create mode 100644 src/stc/scintilla/src/KeyMap.cxx create mode 100644 src/stc/scintilla/src/KeyMap.h create mode 100644 src/stc/scintilla/src/KeyWords.cxx create mode 100644 src/stc/scintilla/src/LineMarker.cxx create mode 100644 src/stc/scintilla/src/LineMarker.h create mode 100644 src/stc/scintilla/src/PropSet.cxx create mode 100644 src/stc/scintilla/src/SVector.h create mode 100644 src/stc/scintilla/src/ScintillaBase.cxx create mode 100644 src/stc/scintilla/src/ScintillaBase.h create mode 100644 src/stc/scintilla/src/Style.cxx create mode 100644 src/stc/scintilla/src/Style.h create mode 100644 src/stc/scintilla/src/ViewStyle.cxx create mode 100644 src/stc/scintilla/src/ViewStyle.h create mode 100644 src/stc/stc.cpp diff --git a/contrib/include/wx/stc/stc.h b/contrib/include/wx/stc/stc.h new file mode 100644 index 0000000000..4920f70b33 --- /dev/null +++ b/contrib/include/wx/stc/stc.h @@ -0,0 +1,547 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: stc.h +// Purpose: A wxWindows implementation of Scintilla. This class is the +// one meant to be used directly by wx applications. It does not +// derive directly from the Scintilla classes, and in fact there +// is no mention of Scintilla classes at all in this header. +// This class delegates all method calls and events to the +// Scintilla objects and so forth. This allows the use of +// Scintilla without polluting the namespace with all the +// classes and itentifiers from Scintilla. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __stc_h__ +#define __stc_h__ + + +#include + + +//---------------------------------------------------------------------- +// constants and stuff + +enum wxSTC_UndoType { + wxSTC_UndoCollectNone, + wxSTC_UndoCollectAutoStart +}; + + +enum wxSTC_EOL { + wxSTC_EOL_CRLF, + wxSTC_EOL_CR, + wxSTC_EOL_LF +}; + +enum wxSTC_EDGE { + wxSTC_EDGE_NONE, + wxSTC_EDGE_LINE, + wxSTC_EDGE_BACKGROUND +}; + + + +const int wxSTC_LEX_STYLE_MAX = 31; +const int wxSTC_STYLE_DEFAULT = 32; +const int wxSTC_STYLE_LINENUMBER = 33; +const int wxSTC_STYLE_BRACELIGHT = 34; +const int wxSTC_STYLE_BRACEBAD = 35; +const int wxSTC_STYLE_CONTROLCHAR = 36; +const int wxSTC_STYLE_MAX = 63; +const int wxSTC_STYLE_MASK = 31; + +const int wxSTC_MARKER_MAX = 31; +const int wxSTC_MARK_CIRCLE = 0; +const int wxSTC_MARK_ROUNDRECT = 1; +const int wxSTC_MARK_ARROW = 2; +const int wxSTC_MARK_SMALLRECT = 3; +const int wxSTC_MARK_SHORTARROW = 4; +const int wxSTC_MARK_EMPTY = 5; + +const int wxSTC_INDIC_PLAIN = 0; +const int wxSTC_INDIC_SQUIGGLE = 1; +const int wxSTC_INDIC_TT = 2; +const int wxSTC_INDIC0_MASK = 32; +const int wxSTC_INDIC1_MASK = 64; +const int wxSTC_INDIC2_MASK = 128; +const int wxSTC_INDICS_MASK = (wxSTC_INDIC0_MASK | wxSTC_INDIC1_MASK | wxSTC_INDIC2_MASK); + + +// key commands +enum { + wxSTC_CMD_LINEDOWN = 2300, + wxSTC_CMD_LINEDOWNEXTEND, + wxSTC_CMD_LINEUP, + wxSTC_CMD_LINEUPEXTEND, + wxSTC_CMD_CHARLEFT, + wxSTC_CMD_CHARLEFTEXTEND, + wxSTC_CMD_CHARRIGHT, + wxSTC_CMD_CHARRIGHTEXTEND, + wxSTC_CMD_WORDLEFT, + wxSTC_CMD_WORDLEFTEXTEND, + wxSTC_CMD_WORDRIGHT, + wxSTC_CMD_WORDRIGHTEXTEND, + wxSTC_CMD_HOME, + wxSTC_CMD_HOMEEXTEND, + wxSTC_CMD_LINEEND, + wxSTC_CMD_LINEENDEXTEND, + wxSTC_CMD_DOCUMENTSTART, + wxSTC_CMD_DOCUMENTSTARTEXTEND, + wxSTC_CMD_DOCUMENTEND, + wxSTC_CMD_DOCUMENTENDEXTEND, + wxSTC_CMD_PAGEUP, + wxSTC_CMD_PAGEUPEXTEND, + wxSTC_CMD_PAGEDOWN, + wxSTC_CMD_PAGEDOWNEXTEND, + wxSTC_CMD_EDITTOGGLEOVERTYPE, + wxSTC_CMD_CANCEL, + wxSTC_CMD_DELETEBACK, + wxSTC_CMD_TAB, + wxSTC_CMD_BACKTAB, + wxSTC_CMD_NEWLINE, + wxSTC_CMD_FORMFEED, + wxSTC_CMD_VCHOME, + wxSTC_CMD_VCHOMEEXTEND, + wxSTC_CMD_ZOOMIN, + wxSTC_CMD_ZOOMOUT, + wxSTC_CMD_DELWORDLEFT, + wxSTC_CMD_DELWORDRIGHT +}; + + +enum wxSTC_LEX { + wxSTC_LEX_CONTAINER=0, + wxSTC_LEX_NULL, + wxSTC_LEX_PYTHON, + wxSTC_LEX_CPP, + wxSTC_LEX_HTML, + wxSTC_LEX_XML, + wxSTC_LEX_PERL, + wxSTC_LEX_SQL, + wxSTC_LEX_VB, + wxSTC_LEX_PROPERTIES, + wxSTC_LEX_ERRORLIST, + wxSTC_LEX_MAKEFILE, + wxSTC_LEX_BATCH, +}; + + + +const int wxSTC_CARET_SLOP = 0x01; +const int WXSTC_CARET_CENTER = 0x02; +const int wxSTC_CARET_STRICT = 0x04; + +const int wxSTC_MARGIN_SYMBOL = 0; +const int wxSTC_MARGIN_NUMBER = 1; + + +class ScintillaWX; // forward declare +class WordList; +struct SCNotification; + + +extern const wxChar* wxSTCNameStr; + +//---------------------------------------------------------------------- + +class wxStyledTextCtrl : public wxControl { +public: + + wxStyledTextCtrl(wxWindow *parent, wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, + const wxString& name = wxSTCNameStr); + ~wxStyledTextCtrl(); + + + + // Text retrieval and modification + wxString GetText(); + bool SetText(const wxString& text); + wxString GetLine(int line); + void ReplaceSelection(const wxString& text); + void SetReadOnly(bool readOnly); + bool GetReadOnly(); + wxString GetTextRange(int startPos, int endPos); + wxString GetStyledTextRange(int startPos, int endPos); + void GetTextRange(int startPos, int endPos, char* buff); + void GetStyledTextRange(int startPos, int endPos, char* buff); + void AddText(const wxString& text); + void AddStyledText(const wxString& text); + void InsertText(int pos, const wxString& text); + void ClearAll(); + char GetCharAt(int pos); + char GetStyleAt(int pos); + void SetStyleBits(int bits); + int GetStyleBits(); + + + // Clipboard + void Cut(); + void Copy(); + void Paste(); + bool CanPaste(); + void ClearClipbrd(); // avoiding name conflict with virtual in wxWindow + + + // Undo and Redo + void Undo(); + bool CanUndo(); + void EmptyUndoBuffer(); + void Redo(); + bool CanRedo(); + void SetUndoCollection(wxSTC_UndoType type); + wxSTC_UndoType GetUndoCollection(); + void BeginUndoAction(); + void EndUndoAction(); + + + // Selection and information + void GetSelection(int* startPos, int* endPos); + void SetSelection(int startPos, int endPos); + wxString GetSelectedText(); + void HideSelection(bool hide); + bool GetHideSelection(); + + int GetTextLength(); + int GetFirstVisibleLine(); + bool GetModified(); + int GetLineCount(); + wxRect GetRect(); + int GetLineFromPos(int pos); + int GetLineStartPos(int line); + int GetLineLengthAtPos(int pos); + int GetLineLength(int line); + wxString GetCurrentLineText(int* linePos=NULL); + int GetCurrentLine(); + int PositionFromPoint(wxPoint pt); + int LineFromPoint(wxPoint pt); + wxPoint PointFromPosition(int pos); + int GetCurrentPos(); + int GetAnchor(); + void SelectAll(); + void SetCurrentPosition(int pos); + void SetAnchor(int pos); + void GotoPos(int pos); + void GotoLine(int line); + void ChangePosition(int delta, bool extendSelection); + void PageMove(int cmdKey, bool extendSelection); + + void ScrollBy(int columnDelta, int lineDelta); + void ScrollToLine(int line); + void ScrollToColumn(int column); + void EnsureCaretVisible(); + void SetCaretPolicy(int policy, int slop=0); + int GetSelectionType(); + + + + // Searching + int FindText(int minPos, int maxPos, const wxString& text, + bool caseSensitive, bool wholeWord); + void SearchAnchor(); + int SearchNext(const wxString& text, bool caseSensitive, bool wholeWord); + int SearchPrev(const wxString& text, bool caseSensitive, bool wholeWord); + + + // Visible whitespace + bool GetViewWhitespace(); + void SetViewWhitespace(bool visible); + + + // Line endings + wxSTC_EOL GetEOLMode(); + void SetEOLMode(wxSTC_EOL mode); + bool GetViewEOL(); + void SetViewEOL(bool visible); + void ConvertEOL(wxSTC_EOL mode); + + + // Styling + int GetEndStyled(); + void StartStyling(int pos, int mask); + void SetStyleFor(int length, int style); + void SetStyleBytes(int length, char* styleBytes); + + + // Style Definition + void StyleClearAll(); + void StyleResetDefault(); + void StyleSetSpec(int styleNum, const wxString& spec); + void StyleSetForeground(int styleNum, const wxColour& colour); + void StyleSetBackground(int styleNum, const wxColour& colour); + void StyleSetFont(int styleNum, wxFont& font); + void StyleSetFontAttr(int styleNum, int size, const wxString& faceName, bool bold, bool italic); + void StyleSetBold(int styleNum, bool bold); + void StyleSetItalic(int styleNum, bool italic); + void StyleSetFaceName(int styleNum, const wxString& faceName); + void StyleSetSize(int styleNum, int pointSize); + void StyleSetEOLFilled(int styleNum, bool fillEOL); + + + // Margins in the edit area + int GetLeftMargin(); + int GetRightMargin(); + void SetMargins(int left, int right); + + + // Margins for selection, markers, etc. + void SetMarginType(int margin, int type); + int GetMarginType(int margin); + void SetMarginWidth(int margin, int pixelWidth); + int GetMarginWidth(int margin); + void SetMarginMask(int margin, int mask); + int GetMarginMask(int margin); + void SetMarginSensitive(int margin, bool sensitive); + bool GetMarginSensitive(int margin); + + + // Selection and Caret styles + void SetSelectionForeground(const wxColour& colour); + void SetSelectionBackground(const wxColour& colour); + void SetCaretForeground(const wxColour& colour); + int GetCaretPeriod(); + void SetCaretPeriod(int milliseconds); + + + // Other settings + void SetBufferedDraw(bool isBuffered); + void SetTabWidth(int numChars); + void SetWordChars(const wxString& wordChars); + + + // Brace highlighting + void BraceHighlight(int pos1, int pos2); + void BraceBadlight(int pos); + int BraceMatch(int pos, int maxReStyle=0); + + + // Markers + void MarkerDefine(int markerNumber, int markerSymbol, + const wxColour& foreground, + const wxColour& background); + void MarkerSetType(int markerNumber, int markerSymbol); + void MarkerSetForeground(int markerNumber, const wxColour& colour); + void MarkerSetBackground(int markerNumber, const wxColour& colour); + int MarkerAdd(int line, int markerNumber); + void MarkerDelete(int line, int markerNumber); + void MarkerDeleteAll(int markerNumber); + int MarkerGet(int line); + int MarkerGetNextLine(int lineStart, int markerMask); + int MarkerGetPrevLine(int lineStart, int markerMask); + int MarkerLineFromHandle(int handle); + void MarkerDeleteHandle(int handle); + + + // Indicators + void IndicatorSetStyle(int indicNum, int indicStyle); + int IndicatorGetStyle(int indicNum); + void IndicatorSetColour(int indicNum, const wxColour& colour); + + + // Auto completion + void AutoCompShow(const wxString& listOfWords); + void AutoCompCancel(); + bool AutoCompActive(); + int AutoCompPosAtStart(); + void AutoCompComplete(); + void AutoCompStopChars(const wxString& stopChars); + + + // Call tips + void CallTipShow(int pos, const wxString& text); + void CallTipCancel(); + bool CallTipActive(); + int CallTipPosAtStart(); + void CallTipSetHighlight(int start, int end); + void CallTipSetBackground(const wxColour& colour); + + + // Key bindings + void CmdKeyAssign(int key, int modifiers, int cmd); + void CmdKeyClear(int key, int modifiers); + void CmdKeyClearAll(); + void CmdKeyExecute(int cmd); + + + // Print formatting + int FormatRange(bool doDraw, + int startPos, + int endPos, + wxDC* draw, + wxDC* target, // Why does it use two? Can they be the same? + wxRect renderRect, + wxRect pageRect); + + + // Document Sharing (multiple views) + void* GetDocument(); + void SetDocument(void* document); + // TODO: create a wx wrapper for Scintilla's document class + + + // TODO: Folding + + + // Long Lines + int GetEdgeColumn(); + void SetEdgeColumn(int column); + wxSTC_EDGE GetEdgeMode(); + void SetEdgeMode(wxSTC_EDGE mode); + wxColour GetEdgeColour(); + void SetEdgeColour(const wxColour& colour); + + + // Lexer + void SetLexer(wxSTC_LEX lexer); + wxSTC_LEX GetLexer(); + void Colourise(int start, int end); + void SetProperty(const wxString& key, const wxString& value); + void SetKeywords(int keywordSet, const wxString& keywordList); + + + +private: + // Event handlers + void OnPaint(wxPaintEvent& evt); + void OnScrollWin(wxScrollWinEvent& evt); + void OnSize(wxSizeEvent& evt); + void OnMouseLeftDown(wxMouseEvent& evt); + void OnMouseMove(wxMouseEvent& evt); + void OnMouseLeftUp(wxMouseEvent& evt); + void OnMouseRightUp(wxMouseEvent& evt); + void OnChar(wxKeyEvent& evt); + void OnLoseFocus(wxFocusEvent& evt); + void OnGainFocus(wxFocusEvent& evt); + void OnSysColourChanged(wxSysColourChangedEvent& evt); + void OnEraseBackground(wxEraseEvent& evt); + void OnMenu(wxCommandEvent& evt); + + + // Turn notifications from Scintilla into events + void NotifyChange(); + void NotifyParent(SCNotification* scn); + + long SendMsg(int msg, long wp=0, long lp=0); + +private: + DECLARE_EVENT_TABLE() + + ScintillaWX* m_swx; + wxStopWatch m_stopWatch; + bool m_readOnly; + wxSTC_UndoType m_undoType; + + + friend class ScintillaWX; + friend class Platform; +}; + +//---------------------------------------------------------------------- + +class wxStyledTextEvent : public wxCommandEvent { +public: + wxStyledTextEvent(wxEventType commandType, int id); + ~wxStyledTextEvent() {} + + void SetPosition(int pos) { m_position = pos; } + void SetKey(int k) { m_key = k; } + void SetModifiers(int m) { m_modifiers = m; } + void SetModificationType(int t) { m_modificationType = t; } + void SetText(const char* t) { m_text = t; } + void SetLength(int len) { m_length = len; } + void SetLinesAdded(int num) { m_linesAdded = num; } + void SetLine(int val) { m_line = val; } + void SetFoldLevelNow(int val) { m_foldLevelNow = val; } + void SetFoldLevelPrev(int val) { m_foldLevelPrev = val; } + void SetMargin(int val) { m_margin = val; } + void SetMessage(int val) { m_message = val; } + void SetWParam(int val) { m_wParam = val; } + void SetLParam(int val) { m_lParam = val; } + + int GetPosition() const { return m_position; } + int GetKey() const { return m_key; } + int GetModifiers() const { return m_modifiers; } + int GetModificationType() const { return m_modificationType; } + wxString GetText() const { return m_text; } + int GetLength() const { return m_length; } + int GetLinesAdded() const { return m_linesAdded; } + int GetLine() const { return m_line; } + int GetFoldLevelNow() const { return m_foldLevelNow; } + int GetFoldLevelPrev() const { return m_foldLevelPrev; } + int GetMargin() const { return m_margin; } + int GetMessage() const { return m_message; } + int GetWParam() const { return m_wParam; } + int GetLParam() const { return m_lParam; } + + bool GetShift() const; + bool GetControl() const; + bool GetAlt() const; + + void CopyObject(wxObject& obj) const; + +private: + int m_position; + int m_key; + int m_modifiers; + + int m_modificationType; // wxEVT_STC_MODIFIED + wxString m_text; + int m_length; + int m_linesAdded; + int m_line; + int m_foldLevelNow; + int m_foldLevelPrev; + + int m_margin; // wxEVT_STC_MARGINCLICK + + int m_message; // wxEVT_STC_MACRORECORD + int m_wParam; + int m_lParam; + +}; + + + +enum { + wxEVT_STC_CHANGE = 1650, + wxEVT_STC_STYLENEEDED, + wxEVT_STC_CHARADDED, + wxEVT_STC_UPDATEUI, + wxEVT_STC_SAVEPOINTREACHED, + wxEVT_STC_SAVEPOINTLEFT, + wxEVT_STC_ROMODIFYATTEMPT, + wxEVT_STC_DOUBLECLICK, + wxEVT_STC_MODIFIED, + wxEVT_STC_KEY, + wxEVT_STC_MACRORECORD, + wxEVT_STC_MARGINCLICK, + wxEVT_STC_NEEDSHOWN +}; + +typedef void (wxEvtHandler::*wxStyledTextEventFunction)(wxStyledTextEvent&); + +#define EVT_STC_CHANGE(id, fn) { wxEVT_STC_CHANGE, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_STYLENEEDED(id, fn) { wxEVT_STC_STYLENEEDED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_CHARADDED(id, fn) { wxEVT_STC_CHARADDED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_UPDATEUI(id, fn) { wxEVT_STC_UPDATEUI, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_SAVEPOINTREACHED(id, fn) { wxEVT_STC_SAVEPOINTREACHED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_SAVEPOINTLEFT(id, fn) { wxEVT_STC_SAVEPOINTLEFT, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_ROMODIFYATTEMPT(id, fn) { wxEVT_STC_ROMODIFYATTEMPT, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_DOUBLECLICK(id, fn) { wxEVT_STC_DOUBLECLICK, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_MODIFIED(id, fn) { wxEVT_STC_MODIFIED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_CMDKEY(id, fn) { wxEVT_STC_CMDKEY, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_UNKNOWNCMDKEY(id, fn) { wxEVT_STC_UNKNOWNCMDKEY, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, + + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +#endif + + diff --git a/contrib/samples/stc/.cvsignore b/contrib/samples/stc/.cvsignore new file mode 100644 index 0000000000..bfe355bda3 --- /dev/null +++ b/contrib/samples/stc/.cvsignore @@ -0,0 +1 @@ +stctest.res diff --git a/contrib/samples/stc/makefile.vc b/contrib/samples/stc/makefile.vc new file mode 100644 index 0000000000..956b781364 --- /dev/null +++ b/contrib/samples/stc/makefile.vc @@ -0,0 +1,14 @@ +# File: makefile.vc For stectrl +# Author: Robin Dunn +# Created: 1-Feb-2000 +# Updated: + +WXDIR = $(WXWIN) +PROGRAM = stctest + +OBJECTS = $(PROGRAM).obj +EXTRALIBS = $(WXDIR)\contrib\lib\stc$(LIBEXT).lib +EXTRAINC = -I$(WXDIR)\contrib\include + +!include $(WXDIR)\src\makeprog.vc + diff --git a/contrib/samples/stc/stctest.cpp b/contrib/samples/stc/stctest.cpp new file mode 100644 index 0000000000..fe337aadb3 --- /dev/null +++ b/contrib/samples/stc/stctest.cpp @@ -0,0 +1,204 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: stctest.cpp +// Purpose: sample of using wxStyledTextCtrl +// Author: Robin Dunn +// Modified by: +// Created: 3-Feb-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "stctest.cpp" + #pragma interface "stctest.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include + +#include + +//---------------------------------------------------------------------- + +class MyApp : public wxApp +{ +public: + virtual bool OnInit(); +}; + +//---------------------------------------------------------------------- + +// Define a new frame type: this is going to be our main frame +class MyFrame : public wxFrame +{ +public: + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnStyleNeeded(wxStyledTextEvent& event); + +private: + wxStyledTextCtrl* ed; + + DECLARE_EVENT_TABLE() +}; + + +// IDs for the controls and the menu commands +enum +{ + // menu items + ID_Quit = 1, + ID_About, + ID_ED +}; + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU (ID_Quit, MyFrame::OnQuit) + EVT_MENU (ID_About, MyFrame::OnAbout) + EVT_STC_STYLENEEDED (ID_ED, MyFrame::OnStyleNeeded) +END_EVENT_TABLE() + +IMPLEMENT_APP(MyApp) + +//---------------------------------------------------------------------- +// `Main program' equivalent: the program execution "starts" here + +bool MyApp::OnInit() +{ + MyFrame *frame = new MyFrame("Testing wxStyledTextCtrl", + wxPoint(5, 5), wxSize(400, 600)); + + frame->Show(TRUE); + return TRUE; +} + +//---------------------------------------------------------------------- + +// frame constructor +MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) +{ +#ifdef __WXMAC__ + // we need this in order to allow the about menu relocation, since ABOUT is + // not the default id of the about menu + wxApp::s_macAboutMenuItemId = ID_About; +#endif + + + // create a menu bar + wxMenu *menuFile = new wxMenu("", wxMENU_TEAROFF); + + // the "About" item should be in the help menu + wxMenu *helpMenu = new wxMenu; + helpMenu->Append(ID_About, "&About...\tCtrl-A", "Show about dialog"); + + menuFile->Append(ID_Quit, "E&xit\tAlt-X", "Quit this program"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar(); + menuBar->Append(menuFile, "&File"); + menuBar->Append(helpMenu, "&Help"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + +#if wxUSE_STATUSBAR + CreateStatusBar(2); + SetStatusText("Testing wxStyledTextCtrl"); +#endif // wxUSE_STATUSBAR + + + //---------------------------------------- + // Setup the editor + ed = new wxStyledTextCtrl(this, ID_ED); + + // Default font + wxFont font(8, wxMODERN, wxNORMAL, wxNORMAL); + ed->StyleSetFont(wxSTC_STYLE_DEFAULT, font); + ed->StyleClearAll(); + + ed->StyleSetForeground(0, wxColour(0x80, 0x80, 0x80)); + ed->StyleSetForeground(1, wxColour(0x00, 0x7f, 0x00)); + //ed->StyleSetForeground(2, wxColour(0x00, 0x7f, 0x00)); + ed->StyleSetForeground(3, wxColour(0x7f, 0x7f, 0x7f)); + ed->StyleSetForeground(4, wxColour(0x00, 0x7f, 0x7f)); + ed->StyleSetForeground(5, wxColour(0x00, 0x00, 0x7f)); + ed->StyleSetForeground(6, wxColour(0x7f, 0x00, 0x7f)); + ed->StyleSetForeground(7, wxColour(0x7f, 0x00, 0x7f)); + ed->StyleSetForeground(8, wxColour(0x00, 0x7f, 0x7f)); + ed->StyleSetForeground(9, wxColour(0x7f, 0x7f, 0x7f)); + ed->StyleSetForeground(10, wxColour(0x00, 0x00, 0x00)); + ed->StyleSetForeground(11, wxColour(0x00, 0x00, 0x00)); + ed->StyleSetBold(5, TRUE); + ed->StyleSetBold(10, TRUE); + +#ifdef __WXMSW__ + ed->StyleSetSpec(2, "fore:#007f00,bold,face:Arial,size:7"); +#else + ed->StyleSetSpec(2, "fore:#007f00,bold,face:Helvetica,size:7"); +#endif + + // give it some text to play with + wxFile file("stctest.cpp"); + wxString st; + + char* buff = st.GetWriteBuf(file.Length()); + file.Read(buff, file.Length()); + st.UngetWriteBuf(); + + ed->InsertText(0, st); + ed->EmptyUndoBuffer(); + + ed->SetLexer(wxSTC_LEX_CPP); + ed->SetKeywords(0, + "asm auto bool break case catch char class 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 operator 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"); + +} + + +// event handlers + +void MyFrame::OnStyleNeeded(wxStyledTextEvent& event) { + int currEndStyled = ed->GetEndStyled(); + ed->Colourise(currEndStyled, event.GetPosition()); +} + + + + +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + // TRUE is to force the frame to close + Close(TRUE); +} + +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxString msg; + msg.Printf( _T("Testing wxStyledTextCtrl...\n")); + + wxMessageBox(msg, "About This Test", wxOK | wxICON_INFORMATION, this); +} diff --git a/contrib/samples/stc/stctest.rc b/contrib/samples/stc/stctest.rc new file mode 100644 index 0000000000..b86c4e2265 --- /dev/null +++ b/contrib/samples/stc/stctest.rc @@ -0,0 +1 @@ +#include "wx/msw/wx.rc" diff --git a/contrib/src/stc/PlatWX.cpp b/contrib/src/stc/PlatWX.cpp new file mode 100644 index 0000000000..0dbd3d5ea7 --- /dev/null +++ b/contrib/src/stc/PlatWX.cpp @@ -0,0 +1,585 @@ +// Scintilla source code edit control +// PlatWX.cxx - implementation of platform facilities on wxWindows +// Copyright 1998-1999 by Neil Hodgson +// Robin Dunn +// The License.txt file describes the conditions under which this software may be distributed. + + +#include "Platform.h" +#include "wx/stc/stc.h" + +Point Point::FromLong(long lpoint) { + return Point(lpoint & 0xFFFF, lpoint >> 32); +} + +wxRect wxRectFromPRectangle(PRectangle prc) { + wxRect rc(prc.left, prc.top, + prc.right-prc.left+1, prc.bottom-prc.top+1); + return rc; +} + +PRectangle PRectangleFromwxRect(wxRect rc) { + return PRectangle(rc.GetLeft(), rc.GetTop(), rc.GetRight(), rc.GetBottom()); +} + +Colour::Colour(long lcol) { + co.Set(lcol & 0xff, (lcol >> 8) & 0xff, (lcol >> 16) & 0xff); +} + +Colour::Colour(unsigned int red, unsigned int green, unsigned int blue) { + co.Set(red, green, blue); +} + +bool Colour::operator==(const Colour &other) const { + return co == other.co; +} + +long Colour::AsLong() const { + return (((long)co.Blue() << 16) | + ((long)co.Green() << 8) | + ((long)co.Red())); +} + +unsigned int Colour::GetRed() { + return co.Red(); +} + +unsigned int Colour::GetGreen() { + return co.Green(); +} + +unsigned int Colour::GetBlue() { + return co.Blue(); +} + +Palette::Palette() { + used = 0; + allowRealization = false; +} + +Palette::~Palette() { + Release(); +} + +void Palette::Release() { + used = 0; +} + +// 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 Palette::WantFind(ColourPair &cp, bool want) { + if (want) { + for (int i=0; i < used; i++) { + if (entries[i].desired == cp.desired) + return; + } + + if (used < numEntries) { + entries[used].desired = cp.desired; + entries[used].allocated = cp.desired; + used++; + } + } else { + for (int i=0; i < used; i++) { + if (entries[i].desired == cp.desired) { + cp.allocated = entries[i].allocated; + return; + } + } + cp.allocated = cp.desired; + } +} + +void Palette::Allocate(Window &) { + if (allowRealization) { + } +} + + +Font::Font() { + id = 0; + ascent = 0; +} + +Font::~Font() { +} + +void Font::Create(const char *faceName, int size, bool bold, bool italic) { + Release(); + id = new wxFont(size, + wxDEFAULT, + italic ? wxITALIC : wxNORMAL, + bold ? wxBOLD : wxNORMAL, + false, + faceName); +} + + +void Font::Release() { + if (id) + delete id; + id = 0; +} + + +Surface::Surface() : + hdc(0), hdcOwned(0), bitmap(0), + x(0), y(0) { +} + +Surface::~Surface() { + Release(); +} + +void Surface::Release() { + if (bitmap) { + ((wxMemoryDC*)hdc)->SelectObject(wxNullBitmap); + delete bitmap; + bitmap = 0; + } + if (hdcOwned) { + delete hdc; + hdc = 0; + hdcOwned = false; + } +} + + +bool Surface::Initialised() { + return hdc != 0; +} + +void Surface::Init() { + Release(); + hdc = new wxMemoryDC(); + hdcOwned = true; + // **** ::SetTextAlign(hdc, TA_BASELINE); +} + +void Surface::Init(SurfaceID hdc_) { + Release(); + hdc = hdc_; + // **** ::SetTextAlign(hdc, TA_BASELINE); +} + +void Surface::InitPixMap(int width, int height, Surface *surface_) { + Release(); + hdc = new wxMemoryDC(surface_->hdc); + hdcOwned = true; + bitmap = new wxBitmap(width, height); + ((wxMemoryDC*)hdc)->SelectObject(*bitmap); + // **** ::SetTextAlign(hdc, TA_BASELINE); +} + +void Surface::PenColour(Colour fore) { + hdc->SetPen(wxPen(fore.co, 1, wxSOLID)); +} + +void Surface::BrushColor(Colour back) { + hdc->SetBrush(wxBrush(back.co, wxSOLID)); +} + +void Surface::SetFont(Font &font_) { + hdc->SetFont(*font_.GetID()); +} + +int Surface::LogPixelsY() { + return hdc->GetPPI().y; +} + +void Surface::MoveTo(int x_, int y_) { + x = x_; + y = y_; +} + +void Surface::LineTo(int x_, int y_) { + hdc->DrawLine(x,y, x_,y_); + x = x_; + y = y_; +} + +void Surface::Polygon(Point *pts, int npts, Colour fore, + Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawPolygon(npts, (wxPoint*)pts); +} + +void Surface::RectangleDraw(PRectangle rc, Colour fore, Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawRectangle(wxRectFromPRectangle(rc)); +} + +void Surface::FillRectangle(PRectangle rc, Colour back) { + BrushColor(back); + hdc->SetPen(*wxTRANSPARENT_PEN); + hdc->DrawRectangle(wxRectFromPRectangle(rc)); +} + +void Surface::FillRectangle(PRectangle rc, Surface &surfacePattern) { + wxBrush br; + if (surfacePattern.bitmap) + br = wxBrush(*surfacePattern.bitmap); + else // Something is wrong so display in red + br = wxBrush(*wxRED, wxSOLID); + hdc->SetPen(*wxTRANSPARENT_PEN); + hdc->SetBrush(br); + hdc->DrawRectangle(wxRectFromPRectangle(rc)); +} + +void Surface::RoundedRectangle(PRectangle rc, Colour fore, Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawRoundedRectangle(wxRectFromPRectangle(rc), 8); +} + +void Surface::Ellipse(PRectangle rc, Colour fore, Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawEllipse(wxRectFromPRectangle(rc)); +} + +void Surface::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + hdc->Blit(rc.left, rc.top, rc.Width(), rc.Height(), + surfaceSource.hdc, from.x, from.y, wxCOPY); +} + +void Surface::DrawText(PRectangle rc, Font &font, int ybase, + const char *s, int len, Colour fore, Colour back) { + SetFont(font); + hdc->SetTextForeground(fore.co); + hdc->SetTextBackground(back.co); + FillRectangle(rc, back); + + // ybase is where the baseline should be, but wxWin uses the upper left + // corner, so I need to calculate the real position for the text... + hdc->DrawText(wxString(s, len), rc.left, ybase - font.ascent); +} + +void Surface::DrawTextClipped(PRectangle rc, Font &font, int ybase, const char *s, int len, Colour fore, Colour back) { + SetFont(font); + hdc->SetTextForeground(fore.co); + hdc->SetTextBackground(back.co); + FillRectangle(rc, back); + hdc->SetClippingRegion(wxRectFromPRectangle(rc)); + + // see comments above + hdc->DrawText(wxString(s, len), rc.left, ybase - font.ascent); + hdc->DestroyClippingRegion(); +} + +int Surface::WidthText(Font &font, const char *s, int len) { + SetFont(font); + int w; + int h; + hdc->GetTextExtent(wxString(s, len), &w, &h); + return w; +} + +void Surface::MeasureWidths(Font &font, const char *s, int len, int *positions) { + SetFont(font); + int totalWidth = 0; + for (int i=0; iGetTextExtent(s[i], &w, &h); + totalWidth += w; + positions[i] = totalWidth; + } +} + +int Surface::WidthChar(Font &font, char ch) { + SetFont(font); + int w; + int h; + hdc->GetTextExtent(ch, &w, &h); + return w; +} + +#define EXTENT_TEST " `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +int Surface::Ascent(Font &font) { + SetFont(font); + int w, h, d, e; + hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e); + font.ascent = h - d; + return font.ascent; +} + +int Surface::Descent(Font &font) { + SetFont(font); + int w, h, d, e; + hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e); + return d; +} + +int Surface::InternalLeading(Font &font) { + return 0; +} + +int Surface::ExternalLeading(Font &font) { + SetFont(font); + int w, h, d, e; + hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e); + return e; +} + +int Surface::Height(Font &font) { + SetFont(font); + return hdc->GetCharHeight(); +} + +int Surface::AverageCharWidth(Font &font) { + SetFont(font); + return hdc->GetCharWidth(); +} + +int Surface::SetPalette(Palette *pal, bool inBackGround) { + return 0; // **** figure out what to do with palettes... +} + +void Surface::SetClip(PRectangle rc) { + hdc->SetClippingRegion(wxRectFromPRectangle(rc)); +} + + + +Window::~Window() { +} + +void Window::Destroy() { + if (id) + id->Destroy(); + id = 0; +} + +bool Window::HasFocus() { + return wxWindow::FindFocus() == id; +} + +PRectangle Window::GetPosition() { + wxRect rc(id->GetPosition(), id->GetSize()); + return PRectangleFromwxRect(rc); +} + +void Window::SetPosition(PRectangle rc) { + id->SetSize(rc.left, rc.top, rc.Width(), rc.Height()); +} + +void Window::SetPositionRelative(PRectangle rc, Window) { + SetPosition(rc); // ???? +} + +PRectangle Window::GetClientPosition() { + wxSize sz = id->GetClientSize(); + return PRectangle(0, 0, sz.x - 1, sz.y - 1); +} + +void Window::Show(bool show) { + id->Show(show); +} + +void Window::InvalidateAll() { + id->Refresh(false); +} + +void Window::InvalidateRectangle(PRectangle rc) { + id->Refresh(false, &wxRectFromPRectangle(rc)); +} + +void Window::SetFont(Font &font) { + id->SetFont(*font.GetID()); +} + +void Window::SetCursor(Cursor curs) { + int cursorId; + + switch (curs) { + case cursorText: + cursorId = wxCURSOR_IBEAM; + break; + case cursorArrow: + cursorId = wxCURSOR_ARROW; + break; + case cursorUp: + cursorId = wxCURSOR_ARROW; // ** no up arrow... wxCURSOR_UPARROW; + break; + case cursorWait: + cursorId = wxCURSOR_WAIT; + break; + case cursorHoriz: + cursorId = wxCURSOR_SIZEWE; + break; + case cursorVert: + cursorId = wxCURSOR_SIZENS; + break; + case cursorReverseArrow: + cursorId = wxCURSOR_POINT_RIGHT; + break; + default: + cursorId = wxCURSOR_ARROW; + break; + } + + id->SetCursor(wxCursor(cursorId)); +} + + +void Window::SetTitle(const char *s) { + id->SetTitle(s); +} + + + +ListBox::ListBox() { +} + +ListBox::~ListBox() { +} + +void ListBox::Create(Window &parent, int ctrlID) { + id = new wxListBox(parent.id, ctrlID, wxDefaultPosition, wxDefaultSize, + 0, NULL, wxLB_SINGLE | wxLB_SORT); +} + +void ListBox::Clear() { + ((wxListBox*)id)->Clear(); +} + +void ListBox::Append(char *s) { + ((wxListBox*)id)->Append(s); +} + +int ListBox::Length() { + return ((wxListBox*)id)->Number(); +} + +void ListBox::Select(int n) { + ((wxListBox*)id)->SetSelection(n); +} + +int ListBox::GetSelection() { + return ((wxListBox*)id)->GetSelection(); +} + +int ListBox::Find(const char *prefix) { + return ((wxListBox*)id)->FindString(prefix); +} + +void ListBox::GetValue(int n, char *value, int len) { + wxString text = ((wxListBox*)id)->GetString(n); + strncpy(value, text.c_str(), len); + value[len-1] = '\0'; +} + +void ListBox::Sort() { + // wxWindows keeps sorted so no need to sort +} + + +Menu::Menu() : id(0) { +} + +void Menu::CreatePopUp() { + Destroy(); + id = new wxMenu(); +} + +void Menu::Destroy() { + if (id) + delete id; + id = 0; +} + +void Menu::Show(Point pt, Window &w) { + w.GetID()->PopupMenu(id, pt.x - 4, pt.y); + Destroy(); +} + + +Colour Platform::Chrome() { + wxColour c; + c = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE); + return Colour(c.Red(), c.Green(), c.Blue()); +} + +Colour Platform::ChromeHighlight() { + wxColour c; + c = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT); + return Colour(c.Red(), c.Green(), c.Blue()); +} + +const char *Platform::DefaultFont() { + return wxNORMAL_FONT->GetFaceName(); +} + +int Platform::DefaultFontSize() { + return 8; +} + +unsigned int Platform::DoubleClickTime() { + return 500; // **** ::GetDoubleClickTime(); +} + +void Platform::DebugDisplay(const char *s) { + wxLogDebug(s); +} + +bool Platform::IsKeyDown(int key) { + return false; // I don't think we'll need this. +} + +long Platform::SendScintilla(WindowID w, + unsigned int msg, + unsigned long wParam, + long lParam) { + + wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w; + return stc->SendMsg(msg, wParam, lParam); +} + + +// These are utility functions not really tied to a platform + +int Platform::Minimum(int a, int b) { + if (a < b) + return a; + else + return b; +} + +int Platform::Maximum(int a, int b) { + if (a > b) + return a; + else + return b; +} + +#define TRACE + +void Platform::DebugPrintf(const char *format, ...) { +#ifdef TRACE + char buffer[2000]; + va_list pArguments; + va_start(pArguments, format); + vsprintf(buffer,format,pArguments); + va_end(pArguments); + Platform::DebugDisplay(buffer); +#endif +} + +int Platform::Clamp(int val, int minVal, int maxVal) { + if (val > maxVal) + val = maxVal; + if (val < minVal) + val = minVal; + return val; +} + + + + + + diff --git a/contrib/src/stc/README.txt b/contrib/src/stc/README.txt new file mode 100644 index 0000000000..46bc58fb01 --- /dev/null +++ b/contrib/src/stc/README.txt @@ -0,0 +1,47 @@ +This contrib is the wxStyledTextCtrl, which is a wrapper around the +Scintilla edit control. (See www.scintilla.org) + +There is still VERY MUCH to be done, most notable of which is a more +advanced sample that exercises more of the code. (I havn't tested +AutoComplete or CallTips, or most of the event types at all yet.) And +also documentation, adding wrappers for some new scintilla +functionality, building and testing on wxGTK, etc. Be patient, it all +will get there soon. + + + +Let me describe a bit about the architecture I am implementing... +Obviously there is the Platform layer which implements the varioius +platform classes by using wxWindows classes and filling in where +needed. Then there is a ScintillaWX class that is derived from +ScintillaBase and implements the necessary virtual methods that +Scintilla needs to fully funciton. This class however is not meant to +ever be used directly by wx programmers. I call it one end of the +bridge between the wx and Scintilla worlds. The other end of the +bridge is a class called wxStyledTextCtrl that looks, feels and acts +like other classes in wxWindows. Here is a diagram: + + + +------------------+ +-------------------+ + | wxStyledTextCtrl |--bridge--| ScintillaWX | + +------------------+ +-------------------+ + | ScintillaBase | + +-------------------+ + | Editor | + +-------------------+ + | PlatWX | + +-------------------+ + + +wxStyledTextCtrl derives from wxControl so it has a window that can be +drawn upon. When a wxStyledTextCtrl is constructed it constructs a +ScintillaWX for itself and passes itself to the scintilla object to be +set as the wMain and wDraw attributes. All method calls on the STC +are sent over the bridge in the form of calls to ScintiallWX::WndProc. +All notifications are sent back over the bridge and turned into +wxEvents. + + +Robin + + diff --git a/contrib/src/stc/ScintillaWX.cpp b/contrib/src/stc/ScintillaWX.cpp new file mode 100644 index 0000000000..5b82473a49 --- /dev/null +++ b/contrib/src/stc/ScintillaWX.cpp @@ -0,0 +1,457 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: ScintillaWX.cxx +// Purpose: A wxWindows implementation of Scintilla. A class derived +// from ScintillaBase that uses the "wx platform" defined in +// PlatformWX.cxx This class is one end of a bridge between +// the wx world and the Scintilla world. It needs a peer +// object of type wxStyledTextCtrl to function. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#include "ScintillaWX.h" +#include "wx/stc/stc.h" + + +//---------------------------------------------------------------------- + +const int H_SCROLL_MAX = 2000; +const int H_SCROLL_STEP = 20; +const int H_SCROLL_PAGE = 200; + +//---------------------------------------------------------------------- +// Helper classes + +class wxSTCTimer : public wxTimer { +public: + wxSTCTimer(ScintillaWX* swx) { + this->swx = swx; + } + + void Notify() { + swx->DoTick(); + } + +private: + ScintillaWX* swx; +}; + + + +bool wxSTCDropTarget::OnDropText(wxCoord x, wxCoord y, const wxString& data) { + return swx->DoDropText(x, y, data); +} + +wxDragResult wxSTCDropTarget::OnEnter(wxCoord x, wxCoord y, wxDragResult def) { + return swx->DoDragEnter(x, y, def); +} + +wxDragResult wxSTCDropTarget::OnDragOver(wxCoord x, wxCoord y, wxDragResult def) { + return swx->DoDragOver(x, y, def); +} + +void wxSTCDropTarget::OnLeave() { + swx->DoDragLeave(); +} + + + +//---------------------------------------------------------------------- +// Constructor/Destructor + + +ScintillaWX::ScintillaWX(wxStyledTextCtrl* win) { + capturedMouse = false; + wMain = win; + wDraw = win; + stc = win; + Initialise(); +} + + +ScintillaWX::~ScintillaWX() { + SetTicking(false); +} + +//---------------------------------------------------------------------- +// base class virtuals + + +void ScintillaWX::Initialise() { + //ScintillaBase::Initialise(); + dropTarget.SetScintilla(this); + stc->SetDropTarget(&dropTarget); +} + + +void ScintillaWX::Finalise() { + ScintillaBase::Finalise(); +} + + +void ScintillaWX::StartDrag() { + wxDropSource source; + wxTextDataObject data(dragChars); + wxDragResult result; + + source.SetData(data); + result = source.DoDragDrop(TRUE); + if (result == wxDragMove && dropWentOutside) + ClearSelection(); + inDragDrop = FALSE; + SetDragPosition(invalidPosition); +} + + +void ScintillaWX::SetTicking(bool on) { + wxSTCTimer* steTimer; + if (timer.ticking != on) { + timer.ticking = on; + if (timer.ticking) { + steTimer = new wxSTCTimer(this); + steTimer->Start(timer.tickSize); + timer.tickerID = (int)steTimer; + } else { + steTimer = (wxSTCTimer*)timer.tickerID; + steTimer->Stop(); + delete steTimer; + timer.tickerID = 0; + } + } + timer.ticksToWait = caret.period; +} + + +void ScintillaWX::SetMouseCapture(bool on) { + if (on) + wMain.GetID()->CaptureMouse(); + else + wMain.GetID()->ReleaseMouse(); + capturedMouse = on; +} + + +bool ScintillaWX::HaveMouseCapture() { + return capturedMouse; +} + + +void ScintillaWX::ScrollText(int linesToMove) { + int dy = vs.lineHeight * (linesToMove); + // TODO: calculate the rectangle to refreshed... + wMain.GetID()->ScrollWindow(0, dy); +} + +void ScintillaWX::SetVerticalScrollPos() { + wMain.GetID()->SetScrollPos(wxVERTICAL, topLine); +} + +void ScintillaWX::SetHorizontalScrollPos() { + wMain.GetID()->SetScrollPos(wxHORIZONTAL, xOffset); +} + + +bool ScintillaWX::ModifyScrollBars(int nMax, int nPage) { + bool modified = false; + int sbMax = wMain.GetID()->GetScrollRange(wxVERTICAL); + int sbThumb = wMain.GetID()->GetScrollThumb(wxVERTICAL); + int sbPos = wMain.GetID()->GetScrollPos(wxVERTICAL); + + + if (sbMax != nMax || sbThumb != nPage) { + wMain.GetID()->SetScrollbar(wxVERTICAL, sbPos, nPage, nMax); + modified = true; + } + + sbMax = wMain.GetID()->GetScrollRange(wxHORIZONTAL); + sbThumb = wMain.GetID()->GetScrollThumb(wxHORIZONTAL); + if ((sbMax != H_SCROLL_MAX) || (sbThumb != H_SCROLL_STEP)) { + wMain.GetID()->SetScrollbar(wxHORIZONTAL, 0, H_SCROLL_STEP, H_SCROLL_MAX); + modified = true; + } + return modified; +} + + +void ScintillaWX::NotifyChange() { + stc->NotifyChange(); +} + + +void ScintillaWX::NotifyParent(SCNotification scn) { + stc->NotifyParent(&scn); +} + + + +void ScintillaWX::Copy() { + if (currentPos != anchor) { + char* text = CopySelectionRange(); + textDO.SetText(text); + wxTheClipboard->Open(); + wxTheClipboard->SetData(&textDO); + wxTheClipboard->Close(); + } +} + + +void ScintillaWX::Paste() { + pdoc->BeginUndoAction(); + ClearSelection(); + + wxTextDataObject data; + bool canPaste; + + wxTheClipboard->Open(); + canPaste = wxTheClipboard->GetData(data); + wxTheClipboard->Close(); + if (canPaste) { + wxString str = data.GetText(); + int len = str.Length(); + pdoc->InsertString(currentPos, str.c_str(), len); + SetEmptySelection(currentPos + len); + } + + pdoc->EndUndoAction(); + NotifyChange(); + Redraw(); +} + + +bool ScintillaWX::CanPaste() { + wxTextDataObject data; + bool canPaste; + + wxTheClipboard->Open(); + canPaste = wxTheClipboard->GetData(data); + wxTheClipboard->Close(); + + return canPaste; +} + +void ScintillaWX::CreateCallTipWindow(PRectangle) { + ct.wCallTip = new wxWindow(wDraw.GetID(), -1); + ct.wDraw = ct.wCallTip; +} + + +void ScintillaWX::AddToPopUp(const char *label, int cmd, bool enabled) { + if (!label[0]) + popup.GetID()->AppendSeparator(); + else + popup.GetID()->Append(cmd, label); + + if (!enabled) + popup.GetID()->Enable(cmd, enabled); + + // TODO: need to create event handler mappings for the cmd ID +} + + +void ScintillaWX::ClaimSelection() { + +} + + +LRESULT ScintillaWX::DefWndProc(UINT /*iMessage*/, WPARAM /*wParam*/, LPARAM /*lParam*/) { + return 0; +} + +LRESULT ScintillaWX::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { + switch (iMessage) { + case EM_CANPASTE: + return CanPaste(); + default: + return ScintillaBase::WndProc(iMessage, wParam, lParam); + } + return 0; +} + + + +//---------------------------------------------------------------------- +// Event delegates + +void ScintillaWX::DoPaint(wxDC* dc, wxRect rect) { + + paintState = painting; + Surface surfaceWindow; + surfaceWindow.Init(dc); + PRectangle rcPaint = PRectangleFromwxRect(rect); + dc->BeginDrawing(); + Paint(&surfaceWindow, rcPaint); + dc->EndDrawing(); + surfaceWindow.Release(); + if (paintState == paintAbandoned) { + // Painting area was insufficient to cover new styling or brace highlight positions + FullPaint(); + } + paintState = notPainting; +} + + +void ScintillaWX::DoHScroll(int type, int pos) { + int xPos = xOffset; + switch (type) { + case wxEVT_SCROLLWIN_LINEUP: + xPos -= H_SCROLL_STEP; + break; + case wxEVT_SCROLLWIN_LINEDOWN: + xPos += H_SCROLL_STEP; + break; + case wxEVT_SCROLLWIN_PAGEUP: + xPos -= H_SCROLL_PAGE; + break; + case wxEVT_SCROLLWIN_PAGEDOWN: + xPos += H_SCROLL_PAGE; + break; + case wxEVT_SCROLLWIN_TOP: + xPos = 0; + break; + case wxEVT_SCROLLWIN_BOTTOM: + xPos = H_SCROLL_MAX; + break; + case wxEVT_SCROLLWIN_THUMBTRACK: + xPos = pos; + break; + } + HorizontalScrollTo(xPos); +} + +void ScintillaWX::DoVScroll(int type, int pos) { + int topLineNew = topLine; + switch (type) { + case wxEVT_SCROLLWIN_LINEUP: + topLineNew -= 1; + break; + case wxEVT_SCROLLWIN_LINEDOWN: + topLineNew += 1; + break; + case wxEVT_SCROLLWIN_PAGEUP: + topLineNew -= LinesToScroll(); + break; + case wxEVT_SCROLLWIN_PAGEDOWN: + topLineNew += LinesToScroll(); + break; + case wxEVT_SCROLLWIN_TOP: + topLineNew = 0; + break; + case wxEVT_SCROLLWIN_BOTTOM: + topLineNew = MaxScrollPos(); + break; + case wxEVT_SCROLLWIN_THUMBTRACK: + topLineNew = pos; + break; + } + ScrollTo(topLineNew); +} + +void ScintillaWX::DoSize(int width, int height) { + PRectangle rcClient(0,0,width,height); + SetScrollBarsTo(rcClient); + DropGraphics(); +} + +void ScintillaWX::DoLoseFocus(){ + DropCaret(); +} + +void ScintillaWX::DoGainFocus(){ + ShowCaretAtCurrentPosition(); +} + +void ScintillaWX::DoSysColourChange() { + InvalidateStyleData(); +} + +void ScintillaWX::DoButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + ButtonDown(pt, curTime, shift, ctrl, alt); +} + +void ScintillaWX::DoButtonUp(Point pt, unsigned int curTime, bool ctrl) { + ButtonUp(pt, curTime, ctrl); +} + +void ScintillaWX::DoButtonMove(Point pt) { + ButtonMove(pt); +} + + +void ScintillaWX::DoAddChar(char ch) { + AddChar(ch); +} + +int ScintillaWX::DoKeyDown(int key, bool shift, bool ctrl, bool alt) { + return KeyDown(key, shift, ctrl, alt); +} + + +void ScintillaWX::DoCommand(int ID) { + Command(ID); +} + + +void ScintillaWX::DoContextMenu(Point pt) { + ContextMenu(pt); +} + + +//---------------------------------------------------------------------- + +bool ScintillaWX::DoDropText(long x, long y, const wxString& data) { + SetDragPosition(invalidPosition); + int movePos = PositionFromLocation(Point(x,y)); + DropAt(movePos, data, dragResult == wxDragMove, FALSE); // TODO: rectangular? + return TRUE; +} + + +wxDragResult ScintillaWX::DoDragEnter(wxCoord x, wxCoord y, wxDragResult def) { + return def; +} + + +wxDragResult ScintillaWX::DoDragOver(wxCoord x, wxCoord y, wxDragResult def) { + SetDragPosition(PositionFromLocation(Point(x, y))); + dragResult = def; + return def; +} + + +void ScintillaWX::DoDragLeave() { + SetDragPosition(invalidPosition); +} + +//---------------------------------------------------------------------- + +// Redraw all of text area. This paint will not be abandoned. +void ScintillaWX::FullPaint() { + paintState = painting; + rcPaint = GetTextRectangle(); + wxClientDC dc(wMain.GetID()); + Surface surfaceWindow; + surfaceWindow.Init(&dc); + Paint(&surfaceWindow, rcPaint); + surfaceWindow.Release(); + paintState = notPainting; +} + + +void ScintillaWX::DoScrollToLine(int line) { + ScrollTo(line); +} + + +void ScintillaWX::DoScrollToColumn(int column) { + HorizontalScrollTo(column * vs.spaceWidth); +} + + + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- diff --git a/contrib/src/stc/ScintillaWX.h b/contrib/src/stc/ScintillaWX.h new file mode 100644 index 0000000000..d25eb18188 --- /dev/null +++ b/contrib/src/stc/ScintillaWX.h @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: ScintillaWX.h +// Purpose: A wxWindows implementation of Scintilla. A class derived +// from ScintillaBase that uses the "wx platform" defined in +// PlatWX.cpp. This class is one end of a bridge between +// the wx world and the Scintilla world. It needs a peer +// object of type wxStyledTextCtrl to function. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __ScintillaWX_h__ +#define __ScintillaWX_h__ + +//---------------------------------------------------------------------- + +#include "Platform.h" + +#include "Scintilla.h" +#ifdef SCI_LEXER +#include "SciLexer.h" +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#endif +#include "ContractionState.h" +#include "SVector.h" +#include "CellBuffer.h" +#include "CallTip.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "AutoComplete.h" +#include "Document.h" +#include "Editor.h" +#include "ScintillaBase.h" + +#include +#include +#include +#include + +//---------------------------------------------------------------------- + +class wxStyledTextCtrl; // forward +class ScintillaWX; + + +//---------------------------------------------------------------------- +// Helper classes + +class wxSTCDropTarget : public wxTextDropTarget { +public: + void SetScintilla(ScintillaWX* swx) { + this->swx = swx; + } + + bool OnDropText(wxCoord x, wxCoord y, const wxString& data); + wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def); + wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def); + void OnLeave(); + +private: + ScintillaWX* swx; +}; + + +//---------------------------------------------------------------------- + +class ScintillaWX : public ScintillaBase { +public: + + ScintillaWX(wxStyledTextCtrl* win); + ~ScintillaWX(); + + // base class virtuals + virtual void Initialise(); + virtual void Finalise(); + virtual void StartDrag(); + virtual void SetTicking(bool on); + virtual void SetMouseCapture(bool on); + virtual bool HaveMouseCapture(); + virtual void ScrollText(int linesToMove); + virtual void SetVerticalScrollPos(); + virtual void SetHorizontalScrollPos(); + virtual bool ModifyScrollBars(int nMax, int nPage); + virtual void Copy(); + virtual void Paste(); + virtual void CreateCallTipWindow(PRectangle rc); + virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); + virtual void ClaimSelection(); + + virtual LRESULT DefWndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); + virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); + + virtual void NotifyChange(); + virtual void NotifyParent(SCNotification scn); + + + // Event delegates + void DoPaint(wxDC* dc, wxRect rect); + void DoHScroll(int type, int pos); + void DoVScroll(int type, int pos); + void DoSize(int width, int height); + void DoLoseFocus(); + void DoGainFocus(); + void DoSysColourChange(); + void DoButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); + void DoButtonUp(Point pt, unsigned int curTime, bool ctrl); + void DoButtonMove(Point pt); + void DoAddChar(char ch); + int DoKeyDown(int key, bool shift, bool ctrl, bool alt); + void DoTick() { Tick(); } + + bool DoDropText(long x, long y, const wxString& data); + wxDragResult DoDragEnter(wxCoord x, wxCoord y, wxDragResult def); + wxDragResult DoDragOver(wxCoord x, wxCoord y, wxDragResult def); + void DoDragLeave(); + + void DoCommand(int ID); + void DoContextMenu(Point pt); + + + // helpers + void FullPaint(); + bool CanPaste(); + bool GetHideSelection() { return hideSelection; } + void DoScrollToLine(int line); + void DoScrollToColumn(int column); + +private: + bool capturedMouse; + wxStyledTextCtrl* stc; + + wxTextDataObject textDO; + wxSTCDropTarget dropTarget; + wxDragResult dragResult; +}; + +//---------------------------------------------------------------------- +#endif diff --git a/contrib/src/stc/makefile.vc b/contrib/src/stc/makefile.vc new file mode 100644 index 0000000000..8e91828d3c --- /dev/null +++ b/contrib/src/stc/makefile.vc @@ -0,0 +1,106 @@ +# File: makefile.vc For stectrl +# Author: Robin Dunn +# Created: 1-Feb-2000 +# Updated: + + + +# Set WXDIR for your system +WXDIR = $(WXWIN) +SCINTILLA=.\scintilla +S=$(SCINTILLA)\src +EXTRAINC=-D__WX__ -DSCI_LEXER -I$(SCINTILLA)/include -I$(S) -I. -I$(WXDIR)\contrib\include +NOPCH=1 + +!include $(WXDIR)\src\makevc.env + +OBJECTS = \ + $(D)\Accessor.obj \ + $(D)\AutoComplete.obj \ + $(D)\CallTip.obj \ + $(D)\CellBuffer.obj \ + $(D)\ContractionState.obj\ + $(D)\Document.obj \ + $(D)\Editor.obj \ + $(D)\Indicator.obj \ + $(D)\KeyMap.obj \ + $(D)\KeyWords.obj \ + $(D)\LineMarker.obj \ + $(D)\PropSet.obj \ + $(D)\ScintillaBase.obj \ + $(D)\Style.obj \ + $(D)\ViewStyle.obj \ + \ + $(D)\PlatWX.obj \ + $(D)\ScintillaWX.obj \ + $(D)\stc.obj \ + + + + +LIBTARGET = $(WXDIR)\contrib\lib\stc$(LIBEXT).lib + +all: $(D) $(LIBTARGET) + +$(D) : + mkdir $(D) + +wx: + cd $(WXDIR)\src\msw + nmake -f makefile.vc FINAL=$(FINAL) + cd $(THISDIR) + +wxclean: + cd $(WXDIR)\src\msw + nmake -f makefile.vc clean + cd $(THISDIR) + + + + +$(LIBTARGET): $(OBJECTS) + -erase $(LIBTARGET) + $(implib) @<< +-out:$(LIBTARGET) +-machine:$(CPU) +$(OBJECTS) +<< + + +$(PROGRAM).exe: $(D)\$(PROGRAM).obj $(DUMMYOBJ) $(WXLIB) $(LIBTARGET) $(PROGRAM).res + $(link) @<< +-out:$(PROGRAM).exe +$(LINKFLAGS) +$(DUMMYOBJ) $(D)\$(PROGRAM).obj $(LIBTARGET) $(PROGRAM).res +$(LIBS) +<< + +$(PROGRAM).res : $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc + $(rc) -r /i$(WXDIR)\include -fo$@ $(PROGRAM).rc + + + +{$(S)}.cxx{$(D)}.obj: + $(cc) @<< +$(CPPFLAGS) /c /Fo$@ /Tp $< +<< + +{}.cpp{$(D)}.obj: + $(cc) @<< +$(CPPFLAGS) /c /Fo$@ /Tp $< +<< + + +show: + @echo $(CPPFLAGS) + + +clean: + -erase $(D)\*.obj + -erase *.sbr + -erase *.exe + -erase *.res + -erase *.map + -erase *.pdb + -erase $(LIBTARGET) + diff --git a/contrib/src/stc/scintilla/README.txt b/contrib/src/stc/scintilla/README.txt new file mode 100644 index 0000000000..705fb99652 --- /dev/null +++ b/contrib/src/stc/scintilla/README.txt @@ -0,0 +1,7 @@ +This directory contains copies of the scintilla/src and +scintilla/include directories from the Scintilla/SCiTE source +distribution. All other code needed to implement Scintilla on top of +wxWindows is located in the directory above this one. + +The current version of the Scintilla code is somewhere between 1.22 +and 1.23, (from their CVS.) diff --git a/contrib/src/stc/scintilla/include/Accessor.h b/contrib/src/stc/scintilla/include/Accessor.h new file mode 100644 index 0000000000..1bba4af55e --- /dev/null +++ b/contrib/src/stc/scintilla/include/Accessor.h @@ -0,0 +1,76 @@ +// SciTE - Scintilla based Text Editor +// Accessor.h - rapid easy access to contents of a Scintilla +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +class Accessor { +protected: + // bufferSize is a trade off between time taken to copy the characters and SendMessage overhead + // slopSize positions the buffer before the desired position in case there is some backtracking + enum {bufferSize=4000, slopSize=bufferSize/8}; + char buf[bufferSize+1]; + WindowID id; + PropSet &props; + int startPos; + int endPos; + int lenDoc; + int offset; // Optional but including an offset makes GCC generate better code + void Fill(int position); +public: + Accessor(WindowID id_, PropSet &props_, int offset_=0) : + id(id_), props(props_), startPos(0x7FFFFFFF), endPos(0), + lenDoc(-1), offset(offset_) { + } + char operator[](int position) { + position += offset; + if (position < startPos || position >= endPos) { + Fill(position); + } + return buf[position - startPos]; + } + char SafeGetCharAt(int position, char chDefault=' ') { + // Safe version of operator[], returning a defined value for invalid position + position += offset; + if (position < startPos || position >= endPos) { + Fill(position); + if (position < startPos || position >= endPos) { + // Position is outside range of document + return chDefault; + } + } + return buf[position - startPos]; + } + char StyleAt(int position); + int GetLine(int position); + int LineStart(int line); + int LevelAt(int line); + int Length(); + void Flush() { + startPos = 0x7FFFFFFF; + lenDoc = -1; + } + int GetLineState(int line); + int SetLineState(int line, int state); + PropSet &GetPropSet() { return props; } +}; + +class StylingContext : public Accessor { + char styleBuf[bufferSize]; + int validLen; + char chFlags; + char chWhile; + unsigned int startSeg; +public: + StylingContext(WindowID id_, PropSet &props_, int offset_=0) : + Accessor(id_,props_,offset_), validLen(0), chFlags(0) {} + void StartAt(unsigned int start, char chMask=31); + void SetFlags(char chFlags_, char chWhile_) {chFlags = chFlags_; chWhile = chWhile_; }; + void ColourSegment(unsigned int start, unsigned int end, int chAttr); + unsigned int GetStartSegment() { return startSeg; } + void StartSegment(unsigned int pos); + void ColourTo(unsigned int pos, int chAttr); + int GetLine(int position); + void SetLevel(int line, int level); + void Flush(); +}; + diff --git a/contrib/src/stc/scintilla/include/KeyWords.h b/contrib/src/stc/scintilla/include/KeyWords.h new file mode 100644 index 0000000000..2cc03b788f --- /dev/null +++ b/contrib/src/stc/scintilla/include/KeyWords.h @@ -0,0 +1,8 @@ +// SciTE - Scintilla based Text Editor +// KeyWords.h - colourise for particular languages +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +void ColouriseDoc(int codePage, int startPos, int lengthDoc, int initStyle, + int language, WordList *keywordlists[], StylingContext &styler); + diff --git a/contrib/src/stc/scintilla/include/Platform.h b/contrib/src/stc/scintilla/include/Platform.h new file mode 100644 index 0000000000..3a5e9816dc --- /dev/null +++ b/contrib/src/stc/scintilla/include/Platform.h @@ -0,0 +1,392 @@ +// Scintilla source code edit control +// 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-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PLATFORM_H +#define PLATFORM_H + +// PLAT_GTK = GTK+ on Linux, PLAT_WIN = Win32 API on Win32 OS +// PLAT_WX is wxWindows on any supported platform +// Could also have PLAT_GTKWIN = GTK+ on Win32 OS in future + +#define PLAT_GTK 0 +#define PLAT_WIN 0 +#define PLAT_WX 0 + +#if defined(__WX__) +#undef PLAT_WX +#define PLAT_WX 1 + +#elif defined(GTK) +#undef PLAT_GTK +#define PLAT_GTK 1 + +#else +#undef PLAT_WIN +#define PLAT_WIN 1 + +#endif + + +// Include the main header for each platform + +#if PLAT_GTK +#include +#include +#endif + +#if PLAT_WIN +#define _WIN32_WINNT 0x0400 // Otherwise some required stuff gets ifdef'd out +// Vassili Bourdo: shut up annoying Visual C++ warnings: +#ifdef _MSC_VER +#pragma warning(disable: 4800 4244 4309) +#endif +#include +#include +#endif + +#if PLAT_WX +#include +#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 + +#if PLAT_GTK +typedef GdkColor ColourID; +typedef GdkFont* FontID; +typedef GdkDrawable* SurfaceID; +typedef GtkWidget* WindowID; +typedef GtkItemFactory* MenuID; +#endif + +#if PLAT_WIN +typedef COLORREF ColourID; +typedef HFONT FontID; +typedef HDC SurfaceID; +typedef HWND WindowID; +typedef HMENU MenuID; +#endif + +#if PLAT_WX +typedef wxColour ColourID; +typedef wxFont* FontID; +typedef wxDC* SurfaceID; +typedef wxWindow* WindowID; +typedef wxMenu* MenuID; +#endif + +#if PLAT_GTK || PLAT_WX +#define SHIFT_PRESSED 1 +#define LEFT_CTRL_PRESSED 2 +#define LEFT_ALT_PRESSED 4 +#endif + +// Point is exactly the same as the Win32 POINT and GTK+ GdkPoint so can be used interchangeably + +class Point { +public: + int x; + int y; + + 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); +}; + +// 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 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); + } + int Width() { return right - left; } + int Height() { return bottom - top; } +}; + +#if PLAT_WX +wxRect wxRectFromPRectangle(PRectangle prc); +PRectangle PRectangleFromwxRect(wxRect rc); +#endif + +class Colour { + ColourID co; +public: + Colour(long lcol=0); + Colour(unsigned int red, unsigned int green, unsigned int blue); + bool operator==(const Colour &other) const; + long AsLong() const; + unsigned int GetRed(); + unsigned int GetGreen(); + unsigned int GetBlue(); + + friend class Surface; + friend class Palette; +}; + +// Colour pairs hold a desired colour and the colour that the graphics engine +// allocates to approximate the desired colour. +// To make palette management more automatic, ColourPairs could register at +// construction time with a palette management object. +struct ColourPair { + Colour desired; + Colour allocated; + + ColourPair(Colour desired_=Colour(0,0,0)) { + desired = desired_; + allocated = desired; + } +}; + +class Window; // Forward declaration for Palette + +class Palette { + int used; + enum {numEntries = 100}; + ColourPair entries[numEntries]; +#if PLAT_GTK + GdkColor *allocatedPalette; + int allocatedLen; +#elif PLAT_WIN + HPALETTE hpal; +#elif PLAT_WX + // wxPalette* pal; // **** Is this needed? +#endif +public: + 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); + + friend class Surface; +}; + +class Font { + 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(); + ~Font(); + + void Create(const char *faceName, int size, bool bold=false, bool italic=false); + void Release(); + + FontID GetID() { return id; } + friend class Surface; +}; + +// A surface abstracts a place to draw +class Surface { +private: +#if PLAT_GTK + GdkDrawable *drawable; + GdkGC *gc; + GdkPixmap *ppixmap; + int x; + int y; + bool inited; + bool createdGC; +#elif PLAT_WIN + HDC hdc; + bool hdcOwned; + HPEN pen; + HPEN penOld; + HBRUSH brush; + HBRUSH brushOld; + HFONT font; + HFONT fontOld; + HBITMAP bitmap; + HBITMAP bitmapOld; + HPALETTE paletteOld; +#elif PLAT_WX + wxDC* hdc; + bool hdcOwned; + wxBitmap* bitmap; + int x; + int y; +#endif + + // Private so Surface objects can not be copied + Surface(const Surface &) {} + Surface &operator=(const Surface &) { return *this; } +#if PLAT_WIN || PLAT_WX + void BrushColor(Colour back); + void SetFont(Font &font_); +#endif +public: + Surface(); + ~Surface(); + + void Init(); + void Init(SurfaceID hdc_); + void InitPixMap(int width, int height, Surface *surface_); + + void Release(); + bool Initialised(); + void PenColour(Colour fore); + int LogPixelsY(); + void MoveTo(int x_, int y_); + void LineTo(int x_, int y_); + void Polygon(Point *pts, int npts, Colour fore, Colour back); + void RectangleDraw(PRectangle rc, Colour fore, Colour back); + void FillRectangle(PRectangle rc, Colour back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, Colour fore, Colour back); + void Ellipse(PRectangle rc, Colour fore, Colour back); + void Copy(PRectangle rc, Point from, Surface &surfaceSource); + + void DrawText(PRectangle rc, Font &font_, int ybase, const char *s, int len, Colour fore, Colour back); + void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, Colour fore, Colour back); + 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_); + int ExternalLeading(Font &font_); + int Height(Font &font_); + int AverageCharWidth(Font &font_); + + int SetPalette(Palette *pal, bool inBackGround); + void SetClip(PRectangle rc); +}; + +// 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 { + friend class ListBox; +protected: + WindowID id; +public: + Window() : id(0) {} + virtual ~Window(); + Window &operator=(WindowID id_) { + id = id_; + return *this; + } + WindowID GetID() { return id; } + bool Created() { 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); + void SetFont(Font &font); + enum Cursor { cursorText, cursorArrow, cursorUp, cursorWait, cursorHoriz, cursorVert, cursorReverseArrow }; + void SetCursor(Cursor curs); + void SetTitle(const char *s); +#if PLAT_WIN + LRESULT SendMessage(UINT msg, WPARAM wParam=0, LPARAM lParam=0); + int GetDlgCtrlID(); + HINSTANCE GetInstance(); +#endif +}; + +class ListBox : public Window { +#if PLAT_GTK + WindowID list; + WindowID scroller; + int current; +#endif +public: + ListBox(); + virtual ~ListBox(); + ListBox &operator=(WindowID id_) { + id = id_; + return *this; + } + void Create(Window &parent, int ctrlID); + void Clear(); + void Append(char *s); + int Length(); + void Select(int n); + int GetSelection(); + int Find(const char *prefix); + void GetValue(int n, char *value, int len); + void Sort(); +}; + +class Menu { + MenuID id; +public: + Menu(); + MenuID GetID() { return id; } + void CreatePopUp(); + void Destroy(); + void Show(Point pt, Window &w); +}; + +// 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 Colour Chrome(); + static Colour ChromeHighlight(); + static const char *DefaultFont(); + static int DefaultFontSize(); + static unsigned int DoubleClickTime(); + 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); + + // These are utility functions not really tied to a platform + static int Minimum(int a, int b); + static int Maximum(int a, int b); + static void DebugPrintf(const char *format, ...); + static int Clamp(int val, int minVal, int maxVal); +}; + +#endif diff --git a/contrib/src/stc/scintilla/include/PropSet.h b/contrib/src/stc/scintilla/include/PropSet.h new file mode 100644 index 0000000000..31da01f954 --- /dev/null +++ b/contrib/src/stc/scintilla/include/PropSet.h @@ -0,0 +1,180 @@ +// SciTE - Scintilla based Text Editor +// PropSet.h - a java style properties file module +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PROPSET_H +#define PROPSET_H + +bool EqualCaseInsensitive(const char *a, const char *b); + +// Define another string class. +// While it would be 'better' to use std::string, that doubles the executable size. + +inline char *StringDup(const char *s) { + if (!s) + return 0; + char *sNew = new char[strlen(s) + 1]; + if (sNew) + strcpy(sNew, s); + return sNew; +} + +class SString { + char *s; +public: + SString() { + s = 0; + } + SString(const SString &source) { + s = StringDup(source.s); + } + SString(const char *s_) { + s = StringDup(s_); + } + SString(int i) { + char number[100]; + sprintf(number, "%0d", i); + //itoa(i, number, 10); + s = StringDup(number); + } + ~SString() { + delete []s; + s = 0; + } + SString &operator=(const SString &source) { + if (this != &source) { + delete []s; + s = StringDup(source.s); + } + return *this; + } + bool operator==(const SString &other) const { + if ((s == 0) && (other.s == 0)) + return true; + if ((s == 0) || (other.s == 0)) + return false; + return strcmp(s, other.s) == 0; + } + bool operator==(const char *sother) const { + if ((s == 0) && (sother == 0)) + return true; + if ((s == 0) || (sother == 0)) + return false; + return strcmp(s, sother) == 0; + } + const char *c_str() const { + if (s) + return s; + else + return ""; + } + int length() const { + if (s) + return strlen(s); + else + return 0; + } + char operator[](int i) { + if (s) + return s[i]; + else + return '\0'; + } + SString &operator +=(const char *sother) { + int len = length(); + int lenOther = strlen(sother); + char *sNew = new char[len + lenOther + 1]; + if (sNew) { + if (s) + memcpy(sNew, s, len); + memcpy(sNew + len, sother, lenOther); + sNew[len + lenOther] = '\0'; + delete []s; + s = sNew; + } + return *this; + } + int value() { + if (s) + return atoi(s); + else + return 0; + } +}; + +class PropSet { +private: + char **vals; + int size; + int used; +public: + PropSet *superPS; + PropSet(); + ~PropSet(); + void EnsureCanAddEntry(); + void Set(const char *key, const char *val); + void Set(char *keyval); + SString Get(const char *key); + int GetInt(const char *key, int defaultValue=0); + SString GetWild(const char *keybase, const char *filename); + SString GetNewExpand(const char *keybase, const char *filename); + void Clear(); + void ReadFromMemory(const char *data, int len); + void Read(const char *filename); +}; + +// This is a fixed length list of strings suitable for display in combo boxes +// as a memory of user entries +template +class EntryMemory { + SString entries[sz]; +public: + void Insert(SString s) { + for (int i=0;i0;j--) { + entries[j] = entries[j-1]; + } + entries[0] = s; + return; + } + } + for (int k=sz-1;k>0;k--) { + entries[k] = entries[k-1]; + } + entries[0] = s; + } + int Length() const { + int len = 0; + for (int i=0;i +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCILEXER_H +#define SCILEXER_H + +// SciLexer features - not in standard Scintilla + +#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 + +// Lexical states for SCLEX_PYTHON +#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 + +// Lexical states for SCLEX_CPP, SCLEX_VB +#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_PUNTUATION 8 +#define SCE_C_PREPROCESSOR 9 +#define SCE_C_OPERATOR 10 +#define SCE_C_IDENTIFIER 11 +#define SCE_C_STRINGEOL 12 + +// Lexical states for SCLEX_HTML, SCLEX_xML +#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 +// Embedded Javascript +#define SCE_HJ_START 11 +#define SCE_HJ_DEFAULT 12 +#define SCE_HJ_COMMENT 13 +#define SCE_HJ_COMMENTLINE 14 +#define SCE_HJ_COMMENTDOC 15 +#define SCE_HJ_NUMBER 16 +#define SCE_HJ_WORD 17 +#define SCE_HJ_KEYWORD 18 +#define SCE_HJ_DOUBLESTRING 19 +#define SCE_HJ_SINGLESTRING 20 +#define SCE_HJ_SYMBOLS 21 +#define SCE_HJ_STRINGEOL 28 +// XML and ASP +#define SCE_H_TAGEND 22 +#define SCE_H_XMLSTART 23 +#define SCE_H_XMLEND 24 +#define SCE_H_SCRIPT 25 +#define SCE_H_ASP 26 +#define SCE_H_ASPAT 27 +// Embedded VBScript +#define SCE_HB_START 40 +#define SCE_HB_DEFAULT 41 +#define SCE_HB_COMMENTLINE 42 +#define SCE_HB_NUMBER 43 +#define SCE_HB_WORD 44 +#define SCE_HB_STRING 45 +#define SCE_HB_IDENTIFIER 46 +#define SCE_HB_STRINGEOL 47 +// Embedded Python +#define SCE_HP_START 50 +#define SCE_HP_DEFAULT 51 +#define SCE_HP_COMMENTLINE 52 +#define SCE_HP_NUMBER 53 +#define SCE_HP_STRING 54 +#define SCE_HP_CHARACTER 55 +#define SCE_HP_WORD 56 +#define SCE_HP_TRIPLE 57 +#define SCE_HP_TRIPLEDOUBLE 58 +#define SCE_HP_CLASSNAME 59 +#define SCE_HP_DEFNAME 60 +#define SCE_HP_OPERATOR 61 +#define SCE_HP_IDENTIFIER 62 + +// Lexical states for SCLEX_PERL +#define SCE_PL_DEFAULT 0 +#define SCE_PL_HERE 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_REF 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 + +#endif diff --git a/contrib/src/stc/scintilla/include/Scintilla.h b/contrib/src/stc/scintilla/include/Scintilla.h new file mode 100644 index 0000000000..07572168dc --- /dev/null +++ b/contrib/src/stc/scintilla/include/Scintilla.h @@ -0,0 +1,415 @@ +// Scintilla source code edit control +// Scintilla.h - interface to the edit control +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCINTILLA_H +#define SCINTILLA_H + +// Compile-time configuration options +#define MACRO_SUPPORT 1 // Comment out to remove macro hooks + +#if PLAT_GTK +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCINTILLA(obj) GTK_CHECK_CAST (obj, scintilla_get_type (), ScintillaObject) +#define SCINTILLA_CLASS(klass) GTK_CHECK_CLASS_CAS T (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 + { + GtkFixed vbox; + void *pscin; + }; + + struct _ScintillaClass + { + GtkFixedClass parent_class; + + void (* command) (ScintillaObject *ttt); + void (* notify) (ScintillaObject *ttt); + }; + + guint scintilla_get_type (void); + GtkWidget* scintilla_new (void); + void scintilla_set_id (ScintillaObject *sci,int id); + long scintilla_send_message (ScintillaObject *sci,int iMessage,int wParam,int lParam); + +#include "WinDefs.h" + +#ifdef __cplusplus +} +#endif + +#endif + +#if PLAT_WX +#include "WinDefs.h" +#endif + +// Both GTK and Windows + +#define INVALID_POSITION -1 + +// Define start of Scintilla messages to be greater than all edit (EM_*) messages +// as many EM_ messages can be used. +#define SCI_START 2000 +#define SCI_OPTIONAL_START 3000 +#define SCI_LEXER_START 4000 + +#define SCI_ADDTEXT SCI_START + 1 +#define SCI_ADDSTYLEDTEXT SCI_START + 2 +#define SCI_INSERTTEXT SCI_START + 3 +#define SCI_CLEARALL SCI_START + 4 +#define SCI_GETLENGTH SCI_START + 6 +#define SCI_GETCHARAT SCI_START + 7 +#define SCI_GETCURRENTPOS SCI_START + 8 +#define SCI_GETANCHOR SCI_START + 9 +#define SCI_GETSTYLEAT SCI_START + 10 + +#define SCI_REDO SCI_START + 11 +#define SCI_SETUNDOCOLLECTION SCI_START + 12 +#define SCI_SELECTALL SCI_START + 13 +#define SCI_SETSAVEPOINT SCI_START + 14 +#define SCI_GETSTYLEDTEXT SCI_START + 15 +#define SCI_CANREDO SCI_START + 16 +#define SCI_MARKERLINEFROMHANDLE SCI_START + 17 +#define SCI_MARKERDELETEHANDLE SCI_START + 18 + +#define SC_UNDOCOLLECT_NONE 0 +#define SC_UNDOCOLLECT_AUTOSTART 1 + +#define SCI_GETVIEWWS SCI_START + 20 +#define SCI_SETVIEWWS SCI_START + 21 +#define SCI_CHANGEPOSITION SCI_START + 22 +#define SCI_GOTOLINE SCI_START + 24 +#define SCI_GOTOPOS SCI_START + 25 +#define SCI_SETANCHOR SCI_START + 26 +#define SCI_GETCURLINE SCI_START + 27 +#define SCI_GETENDSTYLED SCI_START + 28 +#define SCI_CONVERTEOLS SCI_START + 29 + +#define SCI_GETEOLMODE SCI_START + 30 +#define SCI_SETEOLMODE SCI_START + 31 + +#define SC_EOL_CRLF 0 +#define SC_EOL_CR 1 +#define SC_EOL_LF 2 + +#define SCI_STARTSTYLING SCI_START + 32 +#define SCI_SETSTYLING SCI_START + 33 + +#define SCI_SETBUFFEREDDRAW SCI_START + 35 +#define SCI_SETTABWIDTH SCI_START + 36 +#define SCI_SETCODEPAGE SCI_START + 37 +#define SCI_SETUSEPALETTE SCI_START + 39 + +#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 SCI_MARKERDEFINE SCI_START + 40 +#define SCI_MARKERSETFORE SCI_START + 41 +#define SCI_MARKERSETBACK SCI_START + 42 +#define SCI_MARKERADD SCI_START + 43 +#define SCI_MARKERDELETE SCI_START + 44 +#define SCI_MARKERDELETEALL SCI_START + 45 +#define SCI_MARKERGET SCI_START + 46 +#define SCI_MARKERNEXT SCI_START + 47 +#define SCI_MARKERPREVIOUS SCI_START + 48 + +#define SC_MARKNUM_FOLDER 30 +#define SC_MARKNUM_FOLDEROPEN 31 + +#define SC_MASK_FOLDERS ((1< +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef WINDEFS_H +#define WINDEFS_H + +#define WORD short +#define WPARAM unsigned long +#define LPARAM long +#define LRESULT long +#define DWORD long + +#define UINT unsigned int +#define LPSTR char * +#define LONG long + +/* RTF control */ +#define EM_CANPASTE (1074) +#define EM_CANUNDO (198) +#define EM_CHARFROMPOS (215) +#define EM_DISPLAYBAND (1075) +#define EM_EMPTYUNDOBUFFER (205) +#define EM_EXGETSEL (1076) +#define EM_EXLIMITTEXT (1077) +#define EM_EXLINEFROMCHAR (1078) +#define EM_EXSETSEL (1079) +#define EM_FINDTEXT (1080) +#define EM_FINDTEXTEX (1103) +#define EM_FINDWORDBREAK (1100) +#define EM_FMTLINES (200) +#define EM_FORMATRANGE (1081) +#define EM_GETCHARFORMAT (1082) +#define EM_GETEVENTMASK (1083) +#define EM_GETFIRSTVISIBLELINE (206) +#define EM_GETHANDLE (189) +#define EM_GETLIMITTEXT (213) +#define EM_GETLINE (196) +#define EM_GETLINECOUNT (186) +#define EM_GETMARGINS (212) +#define EM_GETMODIFY (184) +#define EM_GETIMECOLOR (1129) +#define EM_GETIMEOPTIONS (1131) +#define EM_GETOPTIONS (1102) +#define EM_GETOLEINTERFACE (1084) +#define EM_GETPARAFORMAT (1085) +#define EM_GETPASSWORDCHAR (210) +#define EM_GETPUNCTUATION (1125) +#define EM_GETRECT (178) +#define EM_GETSEL (176) +#define EM_GETSELTEXT (1086) +#define EM_GETTEXTRANGE (1099) +#define EM_GETTHUMB (190) +#define EM_GETWORDBREAKPROC (209) +#define EM_GETWORDBREAKPROCEX (1104) +#define EM_GETWORDWRAPMODE (1127) +#define EM_HIDESELECTION (1087) +#define EM_LIMITTEXT (197) +#define EM_LINEFROMCHAR (201) +#define EM_LINEINDEX (187) +#define EM_LINELENGTH (193) +#define EM_LINESCROLL (182) +#define EM_PASTESPECIAL (1088) +#define EM_POSFROMCHAR (214) +#define EM_REPLACESEL (194) +#define EM_REQUESTRESIZE (1089) +#define EM_SCROLL (181) +#define EM_SCROLLCARET (183) +#define EM_SELECTIONTYPE (1090) +#define EM_SETBKGNDCOLOR (1091) +#define EM_SETCHARFORMAT (1092) +#define EM_SETEVENTMASK (1093) +#define EM_SETHANDLE (188) +#define EM_SETIMECOLOR (1128) +#define EM_SETIMEOPTIONS (1130) +#define EM_SETLIMITTEXT (197) +#define EM_SETMARGINS (211) +#define EM_SETMODIFY (185) +#define EM_SETOLECALLBACK (1094) +#define EM_SETOPTIONS (1101) +#define EM_SETPARAFORMAT (1095) +#define EM_SETPASSWORDCHAR (204) +#define EM_SETPUNCTUATION (1124) +#define EM_SETREADONLY (207) +#define EM_SETRECT (179) +#define EM_SETRECTNP (180) +#define EM_SETSEL (177) +#define EM_SETTABSTOPS (203) +#define EM_SETTARGETDEVICE (1096) +#define EM_SETWORDBREAKPROC (208) +#define EM_SETWORDBREAKPROCEX (1105) +#define EM_SETWORDWRAPMODE (1126) +#define EM_STREAMIN (1097) +#define EM_STREAMOUT (1098) +#define EM_UNDO (199) + +#define WM_NULL (0) +#define WM_CLEAR (771) +#define WM_COMMAND (273) +#define WM_COPY (769) +#define WM_CUT (768) +#define WM_GETTEXT (13) +#define WM_GETTEXTLENGTH (14) +#define WM_NOTIFY (78) +#define WM_PASTE (770) +#define WM_SETTEXT (12) +#define WM_UNDO (772) + +#define EN_CHANGE (768) +#define EN_KILLFOCUS (512) +#define EN_SETFOCUS (256) + +#define EC_LEFTMARGIN 1 +#define EC_RIGHTMARGIN 2 +#define EC_USEFONTINFO 0xffff + +#if PLAT_GTK +#define VK_DOWN GDK_Down +#define VK_UP GDK_Up +#define VK_LEFT GDK_Left +#define VK_RIGHT GDK_Right +#define VK_HOME GDK_Home +#define VK_END GDK_End +#define VK_PRIOR GDK_Page_Up +#define VK_NEXT GDK_Page_Down +#define VK_DELETE GDK_Delete +#define VK_INSERT GDK_Insert +#define VK_ESCAPE GDK_Escape +#define VK_BACK GDK_BackSpace +#define VK_TAB GDK_Tab +#define VK_RETURN GDK_Return +#define VK_ADD GDK_KP_Add +#define VK_SUBTRACT GDK_KP_Subtract +#endif + +#if PLAT_WX +#define VK_DOWN WXK_DOWN +#define VK_UP WXK_UP +#define VK_LEFT WXK_LEFT +#define VK_RIGHT WXK_RIGHT +#define VK_HOME WXK_HOME +#define VK_END WXK_END +#define VK_PRIOR WXK_PRIOR +#define VK_NEXT WXK_NEXT +#define VK_DELETE WXK_DELETE +#define VK_INSERT WXK_INSERT +#define VK_ESCAPE WXK_ESCAPE +#define VK_BACK WXK_BACK +#define VK_TAB WXK_TAB +#define VK_RETURN WXK_RETURN +#define VK_ADD WXK_ADD +#define VK_SUBTRACT WXK_SUBTRACT + +// Are these needed any more +#define LPSTR char * +#define LONG long +#define LPDWORD (long *) +#endif + +/* SELCHANGE structure */ +#define SEL_EMPTY (0) +#define SEL_TEXT (1) +#define SEL_OBJECT (2) +#define SEL_MULTICHAR (4) +#define SEL_MULTIOBJECT (8) + +/* FINDREPLACE structure */ +#define FR_MATCHCASE (0x4) +#define FR_WHOLEWORD (0x2) +#define FR_DOWN (0x1) + +#define SHIFT_PRESSED 1 +#define LEFT_CTRL_PRESSED 2 +#define LEFT_ALT_PRESSED 4 + +struct RECT { + LONG left; + LONG top; + LONG right; + LONG bottom; +}; + +struct CHARRANGE { + LONG cpMin; + LONG cpMax; +}; + +struct TEXTRANGE { + CHARRANGE chrg; + LPSTR lpstrText; +}; + +struct FINDTEXTEX { + CHARRANGE chrg; + LPSTR lpstrText; + CHARRANGE chrgText; +}; + +struct NMHDR { + WindowID hwndFrom; + UINT idFrom; + UINT code; +}; + +struct FORMATRANGE { + SurfaceID hdc; + SurfaceID hdcTarget; + RECT rc; + RECT rcPage; + CHARRANGE chrg; +}; + +#define MAKELONG(a, b) ((a) | ((b) << 16)) +#define LOWORD(x) (x & 0xffff) +#define HIWORD(x) (x >> 16) + +#endif diff --git a/contrib/src/stc/scintilla/src/Accessor.cxx b/contrib/src/stc/scintilla/src/Accessor.cxx new file mode 100644 index 0000000000..57b7e4dc4e --- /dev/null +++ b/contrib/src/stc/scintilla/src/Accessor.cxx @@ -0,0 +1,112 @@ +// SciTE - Scintilla based Text Editor +// Accessor.cxx - rapid easy access to contents of a Scintilla +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "Scintilla.h" + +void Accessor::Fill(int position) { + if (lenDoc == -1) + lenDoc = Platform::SendScintilla(id, WM_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::SendScintilla(id, EM_GETTEXTRANGE, 0, reinterpret_cast(&tr)); +} + +char Accessor::StyleAt(int position) { + return static_cast(Platform::SendScintilla( + id, SCI_GETSTYLEAT, position, 0)); +} + +int Accessor::GetLine(int position) { + return Platform::SendScintilla(id, EM_LINEFROMCHAR, position, 0); +} + +int Accessor::LineStart(int line) { + return Platform::SendScintilla(id, EM_LINEINDEX, line, 0); +} + +int Accessor::LevelAt(int line) { + return Platform::SendScintilla(id, SCI_GETFOLDLEVEL, line, 0); +} + +int Accessor::Length() { + if (lenDoc == -1) + lenDoc = Platform::SendScintilla(id, WM_GETTEXTLENGTH, 0, 0); + return lenDoc; +} + +int Accessor::GetLineState(int line) { + return Platform::SendScintilla(id, SCI_GETLINESTATE, line); +} + +int Accessor::SetLineState(int line, int state) { + return Platform::SendScintilla(id, SCI_SETLINESTATE, line, state); +} + +void StylingContext::StartAt(unsigned int start, char chMask) { + Platform::SendScintilla(id, SCI_STARTSTYLING, start, chMask); +} + +void StylingContext::ColourSegment(unsigned int start, unsigned int end, int chAttr) { + // Only perform styling if non empty range + if (end != start - 1) { + if (end < start) { + Platform::DebugPrintf("Bad colour positions %d - %d\n", start, end); + } + + if (validLen + (end - start + 1) >= bufferSize) + Flush(); + if (validLen + (end - start + 1) >= bufferSize) { + // Too big for buffer so send directly + Platform::SendScintilla(id, SCI_SETSTYLING, end - start + 1, chAttr); + } else { + if (chAttr != chWhile) + chFlags = 0; + chAttr |= chFlags; + for (unsigned int i = start; i <= end; i++) { + styleBuf[validLen++] = chAttr; + } + } + } +} + +void StylingContext::StartSegment(unsigned int pos) { + startSeg = pos; +} + +void StylingContext::ColourTo(unsigned int pos, int chAttr) { + ColourSegment(startSeg, pos, chAttr); + startSeg = pos+1; +} + +int StylingContext::GetLine(int position) { + return Platform::SendScintilla(id, EM_LINEFROMCHAR, position, 0); +} + +void StylingContext::SetLevel(int line, int level) { + Platform::SendScintilla(id, SCI_SETFOLDLEVEL, line, level); +} + +void StylingContext::Flush() { + if (validLen > 0) { + Platform::SendScintilla(id, SCI_SETSTYLINGEX, validLen, + reinterpret_cast(styleBuf)); + validLen = 0; + } +} diff --git a/contrib/src/stc/scintilla/src/AutoComplete.cxx b/contrib/src/stc/scintilla/src/AutoComplete.cxx new file mode 100644 index 0000000000..c3ec29c3c9 --- /dev/null +++ b/contrib/src/stc/scintilla/src/AutoComplete.cxx @@ -0,0 +1,104 @@ +// Scintilla source code edit control +// AutoComplete.cxx - defines the auto completion list box +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "AutoComplete.h" + +AutoComplete::AutoComplete() { + lb = 0; + active = false; + posStart = 0; + strcpy(stopChars, ""); +} + +AutoComplete::~AutoComplete() { + lb.Destroy(); +} + +bool AutoComplete::Active() { + return active; +} + +void AutoComplete::Start(Window &parent, int ctrlID, int position, int startLen_) { + if (!lb.Created()) { + lb.Create(parent, ctrlID); + } + 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); +} + +int AutoComplete::SetList(const char *list) { + int maxStrLen = 12; + lb.Clear(); + char *words = new char[strlen(list) + 1]; + if (words) { + strcpy(words, list); + char *startword = words; + int i = 0; + for (; words && words[i]; i++) { + if (words[i] == ' ') { + words[i] = '\0'; + lb.Append(startword); + maxStrLen = Platform::Maximum(maxStrLen, strlen(startword)); + startword = words + i + 1; + } + } + if (startword) { + lb.Append(startword); + maxStrLen = Platform::Maximum(maxStrLen, strlen(startword)); + } + delete []words; + } + lb.Sort(); + return maxStrLen; +} + +void AutoComplete::Show() { + lb.Show(); + lb.Select(0); +} + +void AutoComplete::Cancel() { + if (lb.Created()) { + lb.Destroy(); + lb = 0; + 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) { + int pos = lb.Find(word); + //Platform::DebugPrintf("Autocompleting at <%s> %d\n", wordCurrent, pos); + if (pos != -1) + lb.Select(pos); +} + diff --git a/contrib/src/stc/scintilla/src/AutoComplete.h b/contrib/src/stc/scintilla/src/AutoComplete.h new file mode 100644 index 0000000000..10216027bd --- /dev/null +++ b/contrib/src/stc/scintilla/src/AutoComplete.h @@ -0,0 +1,43 @@ +// Scintilla source code edit control +// AutoComplete.h - defines the auto completion list box +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef AUTOCOMPLETE_H +#define AUTOCOMPLETE_H + +class AutoComplete { + bool active; + char stopChars[256]; +public: + ListBox lb; + int posStart; + int startLen; + + 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, int startLen_); + + // 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 list string contains a sequence of words separated by spaces + int SetList(const char *list); + + void 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); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/CallTip.cxx b/contrib/src/stc/scintilla/src/CallTip.cxx new file mode 100644 index 0000000000..ad6740208b --- /dev/null +++ b/contrib/src/stc/scintilla/src/CallTip.cxx @@ -0,0 +1,168 @@ +// Scintilla source code edit control +// CallTip.cxx - code for displaying call tips +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "CallTip.h" + +CallTip::CallTip() { + wCallTip = 0; + inCallTipMode = false; + posStartCallTip = 0; + val = 0; + startHighlight = 0; + endHighlight = 0; + + colourBG.desired = Colour(0xff, 0xff, 0xff); + colourUnSel.desired = Colour(0x80, 0x80, 0x80); + colourSel.desired = Colour(0, 0, 0x80); + colourShade.desired = Colour(0, 0, 0); + colourLight.desired = Colour(0xc0, 0xc0, 0xc0); +} + +CallTip::~CallTip() { + 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); +} + +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); + // To make a nice small call tip window, it is only sized to fit most normal characters without accents + int lineHeight = surfaceWindow->Height(font); + 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; + char *chunkVal = val; + bool moreChunks = true; + 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; + int x = 5; + int xEnd = x + surfaceWindow->WidthText(font, chunkVal, thisStartHighlight); + rcClient.left = x; + rcClient.top = ytext - ascent - 1; + rcClient.right = xEnd; + surfaceWindow->DrawText(rcClient, font, ytext, + chunkVal, thisStartHighlight, + colourUnSel.allocated, colourBG.allocated); + x = xEnd; + + xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisStartHighlight, + thisEndHighlight - thisStartHighlight); + rcClient.top = ytext; + rcClient.left = x; + rcClient.right = xEnd; + surfaceWindow->DrawText(rcClient, font, ytext, + chunkVal + thisStartHighlight, thisEndHighlight - thisStartHighlight, + colourSel.allocated, colourBG.allocated); + x = xEnd; + + xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisEndHighlight, + chunkLength - thisEndHighlight); + rcClient.left = x; + rcClient.right = xEnd; + surfaceWindow->DrawText(rcClient, font, ytext, + chunkVal + thisEndHighlight, chunkLength - thisEndHighlight, + colourUnSel.allocated, colourBG.allocated); + chunkVal = chunkEnd + 1; + ytext += lineHeight; + } + // 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); +} + +PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn, + const char *faceName, int size) { + Surface surfaceMeasure; + surfaceMeasure.Init(); + int deviceHeight = (size * surfaceMeasure.LogPixelsY()) / 72; + font.Create(faceName, deviceHeight); + if (val) + delete []val; + val = new char[strlen(defn) + 1]; + if (!val) + return PRectangle(); + strcpy(val, defn); + startHighlight = 0; + endHighlight = 0; + inCallTipMode = true; + posStartCallTip = pos; + // Look for multiple lines in the text + // Only support \n here - simply means container must avoid \r! + int width = 0; + int numLines = 1; + const char *newline; + const char *look = val; + while ((newline = strchr(look, '\n')) != NULL) { + int thisWidth = surfaceMeasure.WidthText(font, look, newline - look); + width = Platform::Maximum(width, thisWidth); + look = newline + 1; + numLines++; + } + int lastWidth = surfaceMeasure.WidthText(font, look, strlen(look)); + width = Platform::Maximum(width, lastWidth) + 10; + int lineHeight = surfaceMeasure.Height(font); + // Extra line for border and an empty line at top and bottom + int height = lineHeight * numLines - surfaceMeasure.InternalLeading(font) + 2 + 2; + return PRectangle(pt.x -5, pt.y + lineHeight + 1, pt.x + width - 5, pt.y + lineHeight + 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(); + } + } +} diff --git a/contrib/src/stc/scintilla/src/CallTip.h b/contrib/src/stc/scintilla/src/CallTip.h new file mode 100644 index 0000000000..cd5b093c84 --- /dev/null +++ b/contrib/src/stc/scintilla/src/CallTip.h @@ -0,0 +1,46 @@ +// Scintilla source code edit control +// CallTip.h - interface to the call tip control +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CALLTIP_H +#define CALLTIP_H + +const char callClassName[] = "CallTip"; + +class CallTip { + int startHighlight; + int endHighlight; + char *val; + Font font; +public: + Window wCallTip; + Window wDraw; + bool inCallTipMode; + int posStartCallTip; + ColourPair colourBG; + ColourPair colourUnSel; + ColourPair colourSel; + ColourPair colourShade; + ColourPair colourLight; + + 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); + + // 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); + + 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); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/CellBuffer.cxx b/contrib/src/stc/scintilla/src/CellBuffer.cxx new file mode 100644 index 0000000000..777688511a --- /dev/null +++ b/contrib/src/stc/scintilla/src/CellBuffer.cxx @@ -0,0 +1,950 @@ +// Scintilla source code edit control +// CellBuffer.cxx - manages a buffer of cells +// Copyright 1998-2000 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 "SVector.h" +#include "CellBuffer.h" + +MarkerHandleSet::MarkerHandleSet() { + root = 0; +} + +MarkerHandleSet::~MarkerHandleSet() { + MarkerHandleNumber *mhn = root; + while (mhn) { + MarkerHandleNumber *mhnToFree = mhn; + mhn = mhn->next; + delete mhnToFree; + } + root = 0; +} + +int MarkerHandleSet::Length() { + int c = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + c++; + mhn = mhn->next; + } + return c; +} + +int MarkerHandleSet::NumberFromHandle(int handle) { + MarkerHandleNumber *mhn = root; + while (mhn) { + if (mhn->handle == handle) { + return mhn->number; + } + mhn = mhn->next; + } + return - 1; +} + +int MarkerHandleSet::MarkValue() { + unsigned int m = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + m |= (1 << mhn->number); + mhn = mhn->next; + } + return m; +} + +bool MarkerHandleSet::Contains(int handle) { + 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); + } +} + +void MarkerHandleSet::RemoveNumber(int markerNum) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + MarkerHandleNumber *mhn = *pmhn; + if (mhn->number == markerNum) { + *pmhn = mhn->next; + delete mhn; + return; + } + pmhn = &((*pmhn)->next); + } +} + +void MarkerHandleSet::CombineWith(MarkerHandleSet *other) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + pmhn = &((*pmhn)->next); + } + *pmhn = other->root; + other->root = 0; +} + +LineVector::LineVector() { + linesData = 0; + lines = 0; + levels = 0; + Init(); +} + +LineVector::~LineVector() { + for (int line = 0; line < lines; line++) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + delete []linesData; + linesData = 0; + delete []levels; + levels = 0; +} + +void LineVector::Init() { + for (int line = 0; line < lines; line++) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + delete []linesData; + linesData = new LineData[static_cast(growSize)]; + size = growSize; + lines = 1; + delete []levels; + levels = 0; + sizeLevels = 0; +} + +void LineVector::Expand(int sizeNew) { + LineData *linesDataNew = new LineData[sizeNew]; + if (linesDataNew) { + for (int i = 0; i < size; i++) + linesDataNew[i] = linesData[i]; + // Do not delete handleSets here as they are transferred to new linesData + delete []linesData; + linesData = linesDataNew; + size = sizeNew; + } else { + Platform::DebugPrintf("No memory available\n"); + // TODO: Blow up + } +} + +void LineVector::ExpandLevels(int sizeNew) { + if (sizeNew == -1) + sizeNew = size; + int *levelsNew = new int[sizeNew]; + if (levelsNew) { + int i = 0; + for (; i < sizeLevels; i++) + levelsNew[i] = levels[i]; + for (; i < sizeNew; i++) + levelsNew[i] = SC_FOLDLEVELBASE; + delete []levels; + levels = levelsNew; + sizeLevels = sizeNew; + } else { + Platform::DebugPrintf("No memory available\n"); + // TODO: Blow up + } +} + +void LineVector::InsertValue(int pos, int value) { + //Platform::DebugPrintf("InsertValue[%d] = %d\n", pos, value); + if ((lines + 2) >= size) { + Expand(size + growSize); + if (levels) { + ExpandLevels(size + growSize); + } + } + lines++; + for (int i = lines + 1; i > pos; i--) { + linesData[i] = linesData[i - 1]; + } + linesData[pos].startPosition = value; + linesData[pos].handleSet = 0; +} + +void LineVector::SetValue(int pos, int value) { + //Platform::DebugPrintf("SetValue[%d] = %d\n", pos, value); + if ((pos + 2) >= size) { + //Platform::DebugPrintf("Resize %d %d\n", size,pos); + Expand(pos + growSize); + //Platform::DebugPrintf("end Resize %d %d\n", size,pos); + lines = pos; + if (levels) { + ExpandLevels(pos + growSize); + } + } + linesData[pos].startPosition = value; +} + +void LineVector::Remove(int pos) { + //Platform::DebugPrintf("Remove %d\n", pos); + // Retain the markers from the deleted line by oring them into the previous line + if (pos > 0) { + MergeMarkers(pos - 1); + } + for (int i = pos; i < lines; i++) { + linesData[i] = linesData[i + 1]; + } + lines--; +} + +int LineVector::LineFromPosition(int pos) { + //Platform::DebugPrintf("LineFromPostion %d lines=%d end = %d\n", pos, lines, linesData[lines].startPosition); + if (lines == 0) + return 0; + //Platform::DebugPrintf("LineFromPosition %d\n", pos); + if (pos >= linesData[lines].startPosition) + return lines - 1; + int lower = 0; + int upper = lines; + int middle = 0; + do { + middle = (upper + lower + 1) / 2; // Round high + if (pos < linesData[middle].startPosition) { + upper = middle - 1; + } else { + lower = middle; + } + } while (lower < upper); + //Platform::DebugPrintf("LineFromPostion %d %d %d\n", pos, lower, linesData[lower].startPosition, linesData[lower > 1 ? lower - 1 : 0].startPosition); + return lower; +} + +int LineVector::AddMark(int line, int markerNum) { + handleCurrent++; + if (!linesData[line].handleSet) { + // Need new structure to hold marker handle + linesData[line].handleSet = new MarkerHandleSet; + if (!linesData[line].handleSet) + return - 1; + } + linesData[line].handleSet->InsertHandle(handleCurrent, markerNum); + + return handleCurrent; +} + +void LineVector::MergeMarkers(int pos) { + if (linesData[pos].handleSet || linesData[pos + 1].handleSet) { + if (linesData[pos].handleSet && linesData[pos + 1].handleSet) { + linesData[pos].handleSet->CombineWith(linesData[pos].handleSet); + linesData[pos].handleSet = 0; + } + } +} + +void LineVector::DeleteMark(int line, int markerNum) { + if (linesData[line].handleSet) { + if (markerNum == -1) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } else { + linesData[line].handleSet->RemoveNumber(markerNum); + if (linesData[line].handleSet->Length() == 0) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + } + } +} + +void LineVector::DeleteMarkFromHandle(int markerHandle) { + int line = LineFromHandle(markerHandle); + if (line >= 0) { + linesData[line].handleSet->RemoveHandle(markerHandle); + if (linesData[line].handleSet->Length() == 0) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + } +} + +int LineVector::LineFromHandle(int markerHandle) { + for (int line = 0; line < lines; line++) { + if (linesData[line].handleSet) { + if (linesData[line].handleSet->Contains(markerHandle)) { + return line; + } + } + } + return - 1; +} + +Action::Action() { + at = startAction; + position = 0; + data = 0; + lenData = 0; +} + +Action::~Action() { + Destroy(); +} + +void Action::Create(actionType at_, int position_, char *data_, int lenData_) { + delete []data; + position = position_; + at = at_; + data = data_; + lenData = lenData_; +} + +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; + + // Ownership of source data transferred to this + source->position = 0; + source->at = startAction; + source->data = 0; + source->lenData = 0; +} + +CellBuffer::CellBuffer(int initialLength) { + body = new char[initialLength]; + size = initialLength; + length = 0; + part1len = 0; + gaplen = initialLength; + part2body = body + gaplen; + readOnly = false; + + lenActions = 100; + actions = new Action[lenActions]; + maxAction = 0; + currentAction = 0; + collectingUndo = undoCollectAutoStart; + undoSequenceDepth = 0; + savePoint = 0; + + actions[currentAction].Create(startAction); +} + +CellBuffer::~CellBuffer() { + delete []body; + body = 0; + delete []actions; + actions = 0; +} + +void CellBuffer::GapTo(int position) { + if (position == part1len) + return; + if (position < part1len) { + int diff = part1len - position; + //Platform::DebugPrintf("Move gap backwards to %d diff = %d part1len=%d length=%d \n", position,diff, part1len, length); + for (int i = 0; i < diff; i++) + body[part1len + gaplen - i - 1] = body[part1len - i - 1]; + } else { // position > part1len + int diff = position - part1len; + //Platform::DebugPrintf("Move gap forwards to %d diff =%d\n", position,diff); + for (int i = 0; i < diff; i++) + body[part1len + i] = body[part1len + gaplen + i]; + } + part1len = position; + part2body = body + gaplen; +} + +void CellBuffer::RoomFor(int insertionLength) { + //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength); + if (gaplen <= insertionLength) { + //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength); + GapTo(length); + int newSize = size + insertionLength + 4000; + //Platform::DebugPrintf("moved gap %d\n", newSize); + char *newBody = new char[newSize]; + memcpy(newBody, body, size); + delete []body; + body = newBody; + gaplen += newSize - size; + part2body = body + gaplen; + size = newSize; + //Platform::DebugPrintf("end need room %d %d - size=%d length=%d\n", gaplen, insertionLength,size,length); + } +} + +// To make it easier to write code that uses ByteAt, a position outside the range of the buffer +// can be retrieved. All characters outside the range have the value '\0'. +char CellBuffer::ByteAt(int position) { + if (position < part1len) { + if (position < 0) { + return '\0'; + } else { + return body[position]; + } + } else { + if (position >= length) { + return '\0'; + } else { + return part2body[position]; + } + } +} + +void CellBuffer::SetByteAt(int position, char ch) { + + if (position < 0) { + //Platform::DebugPrintf("Bad position %d\n",position); + return; + } + if (position >= length + 11) { + Platform::DebugPrintf("Very Bad position %d of %d\n", position, length); + //exit(2); + return; + } + if (position >= length) { + //Platform::DebugPrintf("Bad position %d of %d\n",position,length); + return; + } + + if (position < part1len) { + body[position] = ch; + } else { + part2body[position] = ch; + } +} + +char CellBuffer::CharAt(int position) { + return ByteAt(position*2); +} + +void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) { + if (lengthRetrieve < 0) + return; + if (position < 0) + return; + int bytePos = position * 2; + if ((bytePos + lengthRetrieve * 2) > length) { + Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n",bytePos, + lengthRetrieve, length); + return; + } + GapTo(0); // Move the buffer so its easy to subscript into it + char *pb = part2body + bytePos; + while (lengthRetrieve--) { + *buffer++ = *pb; + pb +=2; + } +} + +char CellBuffer::StyleAt(int position) { + return ByteAt(position*2 + 1); +} + +const char *CellBuffer::InsertString(int position, char *s, int insertLength) { + char *data = 0; + // InsertString and DeleteChars are the bottleneck though which all changes occur + if (!readOnly) { + if (collectingUndo) { + // Save into the undo/redo stack, but only the characters - not the formatting + // This takes up about half load time + data = new char[insertLength / 2]; + for (int i = 0; i < insertLength / 2; i++) { + data[i] = s[i * 2]; + } + AppendAction(insertAction, position, data, insertLength / 2); + } + + BasicInsertString(position, s, insertLength); + } + return data; +} + +void CellBuffer::InsertCharStyle(int position, char ch, char style) { + char s[2]; + s[0] = ch; + s[1] = style; + InsertString(position*2, s, 2); +} + +bool CellBuffer::SetStyleAt(int position, char style, char mask) { + char curVal = ByteAt(position*2 + 1); + if ((curVal & mask) != style) { + SetByteAt(position*2 + 1, (curVal & ~mask) | style); + return true; + } else { + return false; + } +} + +bool CellBuffer::SetStyleFor(int position, int lengthStyle, char style, char mask) { + int bytePos = position * 2 + 1; + bool changed = false; + while (lengthStyle--) { + char curVal = ByteAt(bytePos); + if ((curVal & mask) != style) { + SetByteAt(bytePos, (curVal & ~mask) | style); + changed = true; + } + bytePos += 2; + } + return changed; +} + +void CellBuffer::EnsureUndoRoom() { + //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, length, currentAction); + if (currentAction >= 2) { + // Have to test that there is room for 2 more actions in the array + // as two actions may be created by this 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 CellBuffer::AppendAction(actionType at, int position, char *data, int lengthData) { + EnsureUndoRoom(); + //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction); + if (currentAction >= 2) { + // See if current action can be coalesced into previous action + // Will work if both are inserts or deletes and position is same or two different + if ((at != actions[currentAction - 1].at) || (abs(position - actions[currentAction - 1].position) > 2)) { + currentAction++; + } else if (currentAction == savePoint) { + currentAction++; + } + } else { + currentAction++; + } + actions[currentAction].Create(at, position, data, lengthData); + if ((collectingUndo == undoCollectAutoStart) && (0 == undoSequenceDepth)) { + currentAction++; + actions[currentAction].Create(startAction); + } + maxAction = currentAction; +} + +const char *CellBuffer::DeleteChars(int position, int deleteLength) { + // InsertString and DeleteChars are the bottleneck though which all changes occur + char *data = 0; + if (!readOnly) { + if (collectingUndo) { + // Save into the undo/redo stack, but only the characters - not the formatting + data = new char[deleteLength / 2]; + for (int i = 0; i < deleteLength / 2; i++) { + data[i] = ByteAt(position + i * 2); + } + AppendAction(removeAction, position, data, deleteLength / 2); + } + + BasicDeleteChars(position, deleteLength); + } + return data; +} + +int CellBuffer::ByteLength() { + return length; +} + +int CellBuffer::Length() { + return ByteLength() / 2; +} + +int CellBuffer::Lines() { + //Platform::DebugPrintf("Lines = %d\n", lv.lines); + return lv.lines; +} + +int CellBuffer::LineStart(int line) { + if (line < 0) + return 0; + else if (line > lv.lines) + return length; + else + return lv.linesData[line].startPosition; +} + +bool CellBuffer::IsReadOnly() { + return readOnly; +} + +void CellBuffer::SetReadOnly(bool set) { + readOnly = set; +} + +void CellBuffer::SetSavePoint() { + savePoint = currentAction; +} + +bool CellBuffer::IsSavePoint() { + return savePoint == currentAction; +} + +int CellBuffer::AddMark(int line, int markerNum) { + if ((line >= 0) && (line < lv.lines)) { + return lv.AddMark(line, markerNum); + } + return - 1; +} + +void CellBuffer::DeleteMark(int line, int markerNum) { + if ((line >= 0) && (line < lv.lines)) { + lv.DeleteMark(line, markerNum); + } +} + +void CellBuffer::DeleteMarkFromHandle(int markerHandle) { + lv.DeleteMarkFromHandle(markerHandle); +} + +int CellBuffer::GetMark(int line) { + if ((line >= 0) && (line < lv.lines) && (lv.linesData[line].handleSet)) + return lv.linesData[line].handleSet->MarkValue(); + return 0; +} + +void CellBuffer::DeleteAllMarks(int markerNum) { + for (int line = 0; line < lv.lines; line++) { + lv.DeleteMark(line, markerNum); + } +} + +int CellBuffer::LineFromHandle(int markerHandle) { + return lv.LineFromHandle(markerHandle); +} + +// Without undo + +void CellBuffer::BasicInsertString(int position, char *s, int insertLength) { + //Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength); + if (insertLength == 0) + return; + RoomFor(insertLength); + GapTo(position); + + memcpy(body + part1len, s, insertLength); + length += insertLength; + part1len += insertLength; + gaplen -= insertLength; + part2body = body + gaplen; + + int lineInsert = lv.LineFromPosition(position / 2) + 1; + // Point all the lines after the insertion point further along in the buffer + for (int lineAfter = lineInsert; lineAfter <= lv.lines; lineAfter++) { + lv.linesData[lineAfter].startPosition += insertLength / 2; + } + char chPrev = ' '; + if ((position - 2) >= 0) + chPrev = ByteAt(position - 2); + char chAfter = ' '; + if ((position + insertLength) < length) + chAfter = ByteAt(position + insertLength); + if (chPrev == '\r' && chAfter == '\n') { + //Platform::DebugPrintf("Splitting a crlf pair at %d\n", lineInsert); + // Splitting up a crlf pair at position + lv.InsertValue(lineInsert, position / 2); + lineInsert++; + } + char ch = ' '; + for (int i = 0; i < insertLength; i += 2) { + ch = s[i]; + if (ch == '\r') { + //Platform::DebugPrintf("Inserting cr at %d\n", lineInsert); + lv.InsertValue(lineInsert, (position + i) / 2 + 1); + lineInsert++; + } else if (ch == '\n') { + if (chPrev == '\r') { + //Platform::DebugPrintf("Patching cr before lf at %d\n", lineInsert-1); + // Patch up what was end of line + lv.SetValue(lineInsert - 1, (position + i) / 2 + 1); + } else { + //Platform::DebugPrintf("Inserting lf at %d\n", lineInsert); + lv.InsertValue(lineInsert, (position + i) / 2 + 1); + lineInsert++; + } + } + chPrev = ch; + } + // Joining two lines where last insertion is cr and following text starts with lf + if (chAfter == '\n') { + if (ch == '\r') { + //Platform::DebugPrintf("Joining cr before lf at %d\n", lineInsert-1); + // End of line already in buffer so drop the newly created one + lv.Remove(lineInsert - 1); + } + } +} + +void CellBuffer::BasicDeleteChars(int position, int deleteLength) { + //Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength); + if (deleteLength == 0) + return; + + if ((position == 0) && (deleteLength == length)) { + // If whole buffer is being deleted, faster to reinitialise lines data + // than to delete each line. + //printf("Whole buffer being deleted\n"); + 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 / 2) + 1; + // Point all the lines after the insertion point further along in the buffer + for (int lineAfter = lineRemove; lineAfter <= lv.lines; lineAfter++) { + lv.linesData[lineAfter].startPosition -= deleteLength / 2; + } + char chPrev = ' '; + if (position >= 2) + chPrev = ByteAt(position - 2); + char chBefore = chPrev; + char chNext = ' '; + if (position < length) + chNext = ByteAt(position); + bool ignoreNL = false; + if (chPrev == '\r' && chNext == '\n') { + //Platform::DebugPrintf("Deleting lf after cr, move line end to cr at %d\n", lineRemove); + // Move back one + lv.SetValue(lineRemove, position / 2); + lineRemove++; + ignoreNL = true; // First \n is not real deletion + } + + char ch = chNext; + for (int i = 0; i < deleteLength; i += 2) { + chNext = ' '; + if ((position + i + 2) < length) + chNext = ByteAt(position + i + 2); + //Platform::DebugPrintf("Deleting %d %x\n", i, ch); + if (ch == '\r') { + if (chNext != '\n') { + //Platform::DebugPrintf("Removing cr end of line\n"); + lv.Remove(lineRemove); + } + } else if ((ch == '\n') && !ignoreNL) { + //Platform::DebugPrintf("Removing lf end of line\n"); + lv.Remove(lineRemove); + ignoreNL = false; // Further \n are not real deletions + } + + 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 = ' '; + if ((position + deleteLength) < length) + chAfter = ByteAt(position + deleteLength); + if (chBefore == '\r' && chAfter == '\n') { + //d.printf("Joining cr before lf at %d\n", lineRemove); + // Using lineRemove-1 as cr ended line before start of deletion + lv.Remove(lineRemove - 1); + lv.SetValue(lineRemove - 1, position / 2 + 1); + } + } + GapTo(position); + length -= deleteLength; + gaplen += deleteLength; + part2body = body + gaplen; +} + +undoCollectionType CellBuffer::SetUndoCollection(undoCollectionType collectUndo) { + collectingUndo = collectUndo; + undoSequenceDepth = 0; + return collectingUndo; +} + +bool CellBuffer::IsCollectingUndo() { + return collectingUndo; +} + +void CellBuffer::AppendUndoStartAction() { + EnsureUndoRoom(); + // Finish any currently active undo sequence + undoSequenceDepth = 0; + if (actions[currentAction].at != startAction) { + undoSequenceDepth++; + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } +} + +void CellBuffer::BeginUndoAction() { + EnsureUndoRoom(); + if (undoSequenceDepth == 0) { + if (actions[currentAction].at != startAction) { + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } + } + undoSequenceDepth++; +} + +void CellBuffer::EndUndoAction() { + EnsureUndoRoom(); + undoSequenceDepth--; + if (0 == undoSequenceDepth) { + if (actions[currentAction].at != startAction) { + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } + } +} + +void CellBuffer::DeleteUndoHistory() { + for (int i = 1; i < maxAction; i++) + actions[i].Destroy(); + maxAction = 0; + currentAction = 0; + savePoint = 0; +} + +bool CellBuffer::CanUndo() { + return (!readOnly) && ((currentAction > 0) && (maxAction > 0)); +} + +int CellBuffer::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 &CellBuffer::UndoStep() { + const Action &actionStep = actions[currentAction]; + if (actionStep.at == insertAction) { + BasicDeleteChars(actionStep.position, actionStep.lenData*2); + } else if (actionStep.at == removeAction) { + char *styledData = new char[actionStep.lenData * 2]; + for (int i = 0; i < actionStep.lenData; i++) { + styledData[i*2] = actionStep.data[i]; + styledData[i*2+1] = 0; + } + BasicInsertString(actionStep.position, styledData, actionStep.lenData*2); + delete []styledData; + } + currentAction--; + return actionStep; +} + +bool CellBuffer::CanRedo() { + return (!readOnly) && (maxAction > currentAction); +} + +int CellBuffer::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 &CellBuffer::RedoStep() { + const Action &actionStep = actions[currentAction]; + if (actionStep.at == insertAction) { + char *styledData = new char[actionStep.lenData * 2]; + for (int i = 0; i < actionStep.lenData; i++) { + styledData[i*2] = actionStep.data[i]; + styledData[i*2+1] = 0; + } + BasicInsertString(actionStep.position, styledData, actionStep.lenData*2); + delete []styledData; + } else if (actionStep.at == removeAction) { + BasicDeleteChars(actionStep.position, actionStep.lenData*2); + } + currentAction++; + return actionStep; +} + +int CellBuffer::SetLineState(int line, int state) { + int stateOld = lineStates[line]; + lineStates[line] = state; + return stateOld; +} + +int CellBuffer::GetLineState(int line) { + return lineStates[line]; +} + +int CellBuffer::GetMaxLineState() { + return lineStates.Length(); +} + +int CellBuffer::SetLevel(int line, int level) { + int prev = 0; + if ((line >= 0) && (line < lv.lines)) { + if (!lv.levels) { + lv.ExpandLevels(); + } + prev = lv.levels[line]; + if (lv.levels[line] != level) { + lv.levels[line] = level; + } + } + return prev; +} + +int CellBuffer::GetLevel(int line) { + if (lv.levels && (line >= 0) && (line < lv.lines)) { + return lv.levels[line]; + } else { + return SC_FOLDLEVELBASE; + } +} + diff --git a/contrib/src/stc/scintilla/src/CellBuffer.h b/contrib/src/stc/scintilla/src/CellBuffer.h new file mode 100644 index 0000000000..5fbe2ea8a0 --- /dev/null +++ b/contrib/src/stc/scintilla/src/CellBuffer.h @@ -0,0 +1,197 @@ +// Scintilla source code edit control +// CellBuffer.h - manages the text of the document +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CELLBUFFER_H +#define CELLBUFFER_H + +// 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(); + int NumberFromHandle(int handle); + int MarkValue(); // Bit set of marker numbers + bool Contains(int handle); + bool InsertHandle(int handle, int markerNum); + void RemoveHandle(int handle); + void RemoveNumber(int markerNum); + void CombineWith(MarkerHandleSet *other); +}; + +// Each line stores the starting position of the first character of the line in the cell buffer +// and potentially a marker handle set. Often a line will not have any attached markers. +struct LineData { + int startPosition; + MarkerHandleSet *handleSet; + LineData() : startPosition(0), handleSet(0) { + } +}; + +// The line vector contains information about each of the lines in a cell buffer. +class LineVector { +public: + enum { growSize = 4000 }; + int lines; + LineData *linesData; + int size; + int *levels; + int sizeLevels; + + // Handles are allocated sequentially and should never have to be reused as 32 bit ints are very big. + int handleCurrent; + + LineVector(); + ~LineVector(); + void Init(); + + void Expand(int sizeNew); + void ExpandLevels(int sizeNew=-1); + void InsertValue(int pos, int value); + void SetValue(int pos, int value); + void Remove(int pos); + int LineFromPosition(int pos); + + int AddMark(int line, int marker); + void MergeMarkers(int pos); + void DeleteMark(int line, int markerNum); + void DeleteMarkFromHandle(int markerHandle); + int LineFromHandle(int markerHandle); +}; + +// Actions are used to store all the information required to perform one undo/redo step. +enum actionType { insertAction, removeAction, startAction }; + +class Action { +public: + actionType at; + int position; + char *data; + int lenData; + + Action(); + ~Action(); + void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0); + void Destroy(); + void Grab(Action *source); +}; + +enum undoCollectionType { undoCollectNone, undoCollectAutoStart, undoCollectManualStart }; + +// 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: + char *body; + int size; + int length; + int part1len; + int gaplen; + char *part2body; + bool readOnly; + + Action *actions; + int lenActions; + int maxAction; + int currentAction; + undoCollectionType collectingUndo; + int undoSequenceDepth; + int savePoint; + + LineVector lv; + + SVector lineStates; + + void GapTo(int position); + void RoomFor(int insertionLength); + + void EnsureUndoRoom(); + void AppendAction(actionType at, int position, char *data, int length); + + inline char ByteAt(int position); + void SetByteAt(int position, char ch); + +public: + + CellBuffer(int initialLength = 4000); + ~CellBuffer(); + + // Retrieving positions outside the range of the buffer works and returns 0 + char CharAt(int position); + void GetCharRange(char *buffer, int position, int lengthRetrieve); + char StyleAt(int position); + + int ByteLength(); + int Length(); + int Lines(); + int LineStart(int line); + int LineFromPosition(int pos) { return lv.LineFromPosition(pos); } + const char *InsertString(int position, char *s, int insertLength); + void InsertCharStyle(int position, char ch, char style); + + // Setting styles for positions outside the range of the buffer is safe and has no effect. + // True is returned if the style of a character changed. + bool SetStyleAt(int position, char style, char mask=(char)0xff); + bool SetStyleFor(int position, int length, char style, char mask); + + const char *DeleteChars(int position, int deleteLength); + + 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(); + + // Line marker functions + int AddMark(int line, int markerNum); + void DeleteMark(int line, int markerNum); + void DeleteMarkFromHandle(int markerHandle); + int GetMark(int line); + void DeleteAllMarks(int markerNum); + int LineFromHandle(int markerHandle); + + // Without undo + void BasicInsertString(int position, char *s, int insertLength); + void BasicDeleteChars(int position, int deleteLength); + + undoCollectionType SetUndoCollection(undoCollectionType collectUndo); + bool IsCollectingUndo(); + void AppendUndoStartAction(); + void BeginUndoAction(); + void EndUndoAction(); + void DeleteUndoHistory(); + + // To perform an undo, StartUndo is called to retreive the number of steps, then UndoStep is + // called that many times. Similarly for redo. + bool CanUndo(); + int StartUndo(); + const Action &UndoStep(); + bool CanRedo(); + int StartRedo(); + const Action &RedoStep(); + + int SetLineState(int line, int state); + int GetLineState(int line); + int GetMaxLineState(); + + int SetLevel(int line, int level); + int GetLevel(int line); +}; + +#define CELL_SIZE 2 + +#endif diff --git a/contrib/src/stc/scintilla/src/ContractionState.cxx b/contrib/src/stc/scintilla/src/ContractionState.cxx new file mode 100644 index 0000000000..6f41461eb1 --- /dev/null +++ b/contrib/src/stc/scintilla/src/ContractionState.cxx @@ -0,0 +1,203 @@ +// Scintilla source code edit control +// ContractionState.cxx - manages visibility of lines for folding +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include "Platform.h" + +#include "ContractionState.h" + +OneLine::OneLine() { + displayLine = 0; + docLine = 0; + visible = true; + expanded = true; +} + +ContractionState::ContractionState() { + lines = 0; + size = 0; + linesInDoc = 1; + linesInDisplay = 1; + valid = false; +} + +ContractionState::~ContractionState() { + Clear(); +} + +void ContractionState::MakeValid() const { + if (!valid) { + // Could be cleverer by keeping the index of the last still valid entry + // rather than invalidating all. + int linePrev = -1; + int lineDisplay = 0; + for (int line=0; line= 0) && (lineDoc < linesInDoc)) { + return lines[lineDoc].displayLine; + } + return -1; +} + +int ContractionState::DocFromDisplay(int lineDisplay) const { + if (lineDisplay <= 0) + return 0; + if (lineDisplay >= linesInDisplay) + return linesInDoc-1; + if (size == 0) + return lineDisplay; + MakeValid(); + return lines[lineDisplay].docLine; +} + +void ContractionState::Grow(int sizeNew) { + OneLine *linesNew = new OneLine[sizeNew]; + if (linesNew) { + int i = 0; + for (; i < size; i++) { + linesNew[i] = lines[i]; + } + for (; i < sizeNew; i++) { + linesNew[i].displayLine = i; + } + delete []lines; + lines = linesNew; + size = sizeNew; + valid = false; + } else { + Platform::DebugPrintf("No memory available\n"); + // TODO: Blow up + } +} + +void ContractionState::InsertLines(int lineDoc, int lineCount) { + if (size == 0) { + linesInDoc += lineCount; + linesInDisplay += lineCount; + return; + } + //Platform::DebugPrintf("InsertLine[%d] = %d\n", lineDoc); + if ((linesInDoc + 2) >= size) { + Grow(size + growSize); + } + linesInDoc += lineCount; + linesInDisplay += lineCount; + for (int i = linesInDoc + 1; i >= lineDoc + lineCount; i--) { + lines[i].visible = lines[i - lineCount].visible; + lines[i].expanded = lines[i - lineCount].expanded; + } + for (int d=0;d= 0) && (lineDoc < linesInDoc)) { + return lines[lineDoc].visible; + } else { + return false; + } +} + +bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible) { + if (size == 0) { + Grow(lineDocEnd + growSize); + } + // TODO: modify docLine members to mirror displayLine + int delta = 0; + // Change lineDocs + if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < linesInDoc)) { + for (int line=lineDocStart; line <= lineDocEnd; line++) { + if (lines[line].visible != visible) { + delta += visible ? 1 : -1; + lines[line].visible = visible; + } + lines[line].displayLine += delta; + } + if (delta != 0) { + for (int line=lineDocEnd+1; line <= linesInDoc; line++) { + lines[line].displayLine += delta; + } + } + } + linesInDisplay += delta; + valid = false; + return delta != 0; +} + +bool ContractionState::GetExpanded(int lineDoc) const { + if (size == 0) + return true; + if ((lineDoc >= 0) && (lineDoc < linesInDoc)) { + return lines[lineDoc].expanded; + } else { + return false; + } +} + +bool ContractionState::SetExpanded(int lineDoc, bool expanded) { + if (size == 0) { + Grow(lineDoc + growSize); + } + if ((lineDoc >= 0) && (lineDoc < linesInDoc)) { + if (lines[lineDoc].expanded != expanded) { + lines[lineDoc].expanded = expanded; + return true; + } + } + return false; +} diff --git a/contrib/src/stc/scintilla/src/ContractionState.h b/contrib/src/stc/scintilla/src/ContractionState.h new file mode 100644 index 0000000000..9e17a76937 --- /dev/null +++ b/contrib/src/stc/scintilla/src/ContractionState.h @@ -0,0 +1,50 @@ +// Scintilla source code edit control +// ContractionState.h - manages visibility of lines for folding +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CONTRACTIONSTATE_H +#define CONTRACTIONSTATE_H + +class OneLine { +public: + int displayLine; // position within set of visible lines + int docLine; // inverse of displayLine + bool visible; + bool expanded; + + OneLine(); + virtual ~OneLine() {} +}; + +class ContractionState { + void Grow(int sizeNew); + enum { growSize = 4000 }; + int linesInDoc; + int linesInDisplay; + mutable OneLine *lines; + int size; + mutable bool valid; + void MakeValid() const; +public: + ContractionState(); + virtual ~ContractionState(); + + void Clear(); + + int LinesInDoc() const; + int LinesDisplayed() const; + int DisplayFromDoc(int lineDoc) const; + int DocFromDisplay(int lineDisplay) const; + + void InsertLines(int lineDoc, int lineCount); + 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); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/Document.cxx b/contrib/src/stc/scintilla/src/Document.cxx new file mode 100644 index 0000000000..7d832241fc --- /dev/null +++ b/contrib/src/stc/scintilla/src/Document.cxx @@ -0,0 +1,734 @@ +// Scintilla source code edit control +// Document.cxx - text document that handles notifications, DBCS, styling, words and end of line +// Copyright 1998-2000 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 "SVector.h" +#include "CellBuffer.h" +#include "Document.h" + +Document::Document() { + refCount = 0; +#ifdef unix + eolMode = SC_EOL_LF; +#else + eolMode = SC_EOL_CRLF; +#endif + dbcsCodePage = 0; + stylingBits = 5; + stylingBitsMask = 0x1F; + stylingPos = 0; + stylingMask = 0; + for (int ch = 0; ch < 256; ch++) { + wordchars[ch] = isalnum(ch) || ch == '_'; + } + endStyled = 0; + enteredCount = 0; + tabInChars = 8; + watchers = 0; + lenWatchers = 0; +} + +Document::~Document() { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyDeleted(this, watchers[i].userData); + } + delete []watchers; + watchers = 0; + lenWatchers = 0; +} + +// Increase reference count and return its previous value. +int Document::AddRef() { + return refCount++; +} + +// Decrease reference count and return its provius 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::LineStart(int line) { + return cb.LineStart(line); +} + +int Document::LineFromPosition(int pos) { + return cb.LineFromPosition(pos); +} + +int Document::LineEndPosition(int position) { + int line = LineFromPosition(position); + if (line == LinesTotal() - 1) { + position = LineStart(line + 1); + } else { + 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::VCHomePosition(int position) { + int line = LineFromPosition(position); + int startPosition = LineStart(line); + int endLine = LineStart(line + 1) - 1; + 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 = cb.SetLevel(line, level); + if (prev != level) { + DocModification mh(SC_MOD_CHANGEFOLD, LineStart(line), 0, 0, 0); + mh.line = line; + mh.foldLevelNow = level; + mh.foldLevelPrev = prev; + NotifyModified(mh); + } + return prev; +} + +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) && IsSubordinate(level, GetLevel(lineMaxSubord+1))) { + 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 ((lineMaxSubord > lineParent) && (GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG)) { + lineMaxSubord--; + } + } + } + return lineMaxSubord; +} + +int Document::GetFoldParent(int line) { + int level = GetLevel(line); + 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'); +} + +bool Document::IsDBCS(int pos) { +#if PLAT_WIN + if (dbcsCodePage) { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int startLine = pos; + while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') + startLine--; + while (startLine <= pos) { + if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) { + startLine++; + if (startLine >= pos) + return true; + } + startLine++; + } + } + return false; +#else + return false; +#endif +} + +// 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 value - should be fixed up after + if (pos < 0) + return pos; + if (pos > Length()) + return pos; + + // Position 0 and Length() can not be between any two characters + if (pos == 0) + return pos; + if (pos == Length()) + return pos; + + // 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 PLAT_WIN + if (dbcsCodePage) { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int startLine = pos; + while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') + startLine--; + bool atLeadByte = false; + while (startLine < pos) { + if (atLeadByte) + atLeadByte = false; + else if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) + atLeadByte = true; + else + atLeadByte = false; + startLine++; + //Platform::DebugPrintf("DBCS %s\n", atlead ? "D" : "-"); + } + + if (atLeadByte) { + // Position is between a lead byte and a trail byte + if (moveDir > 0) + return pos + 1; + else + return pos - 1; + } + } +#endif + + return pos; +} + +void Document::ModifiedAt(int pos) { + if (endStyled > pos) + endStyled = pos; +} + +// Document only modified by gateways DeleteChars, InsertStyledString, Undo, Redo, and SetStyleAt. +// SetStyleAt does not change the persistent state of a document + +// Unlike Undo, Redo, and InsertStyledString, the pos argument is a cell number not a char number +void Document::DeleteChars(int pos, int len) { + if (enteredCount == 0) { + enteredCount++; + if (cb.IsReadOnly()) + NotifyModifyAttempt(); + if (!cb.IsReadOnly()) { + int prevLinesTotal = LinesTotal(); + bool startSavePoint = cb.IsSavePoint(); + const char *text = cb.DeleteChars(pos*2, len * 2); + if (startSavePoint && cb.IsCollectingUndo()) + NotifySavePoint(!startSavePoint); + ModifiedAt(pos); + int modFlags = SC_MOD_DELETETEXT | SC_PERFORMED_USER; + DocModification mh(modFlags, pos, len, LinesTotal() - prevLinesTotal, text); + NotifyModified(mh); + } + enteredCount--; + } +} + +void Document::InsertStyledString(int position, char *s, int insertLength) { + if (enteredCount == 0) { + enteredCount++; + if (cb.IsReadOnly()) + NotifyModifyAttempt(); + if (!cb.IsReadOnly()) { + int prevLinesTotal = LinesTotal(); + bool startSavePoint = cb.IsSavePoint(); + const char *text = cb.InsertString(position, s, insertLength); + if (startSavePoint && cb.IsCollectingUndo()) + NotifySavePoint(!startSavePoint); + ModifiedAt(position / 2); + + int modFlags = SC_MOD_INSERTTEXT | SC_PERFORMED_USER; + DocModification mh(modFlags, position / 2, insertLength / 2, LinesTotal() - prevLinesTotal, text); + NotifyModified(mh); + } + enteredCount--; + } +} + +int Document::Undo() { + int newPos = 0; + if (enteredCount == 0) { + enteredCount++; + bool startSavePoint = cb.IsSavePoint(); + int steps = cb.StartUndo(); + for (int step=0; step= lineTop; line--) { + InsertChar(LineStart(line), '\t'); + } + } else { + // 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 ispc = 0; + while (ispc < tabInChars && cb.CharAt(LineStart(line) + ispc) == ' ') + ispc++; + int posStartLine = LineStart(line); + if (ispc == tabInChars) { + DeleteChars(posStartLine, ispc); + } else if (cb.CharAt(posStartLine + ispc) == '\t') { + DeleteChars(posStartLine, ispc + 1); + } else { // Hit a non-white + DeleteChars(posStartLine, ispc); + } + } + } +} + +void Document::ConvertLineEnds(int eolModeSet) { + BeginUndoAction(); + for (int pos = 0; pos < Length(); pos++) { + if (cb.CharAt(pos) == '\r') { + if (cb.CharAt(pos+1) == '\n') { + if (eolModeSet != SC_EOL_CRLF) { + DeleteChars(pos, 2); + if (eolModeSet == SC_EOL_CR) + InsertString(pos, "\r", 1); + else + InsertString(pos, "\n", 1); + } else { + pos++; + } + } else { + if (eolModeSet != SC_EOL_CR) { + DeleteChars(pos, 1); + if (eolModeSet == SC_EOL_CRLF) { + InsertString(pos, "\r\n", 2); + pos++; + } else { + InsertString(pos, "\n", 1); + } + } + } + } else if (cb.CharAt(pos) == '\n') { + if (eolModeSet != SC_EOL_LF) { + DeleteChars(pos, 1); + if (eolModeSet == SC_EOL_CRLF) { + InsertString(pos, "\r\n", 2); + pos++; + } else { + InsertString(pos, "\r", 1); + } + } + } + } + EndUndoAction(); +} + +bool Document::IsWordChar(unsigned char ch) { + return wordchars[ch]; +} + +int Document::ExtendWordSelect(int pos, int delta) { + if (delta < 0) { + while (pos > 0 && IsWordChar(cb.CharAt(pos - 1))) + pos--; + } else { + while (pos < (Length()) && IsWordChar(cb.CharAt(pos))) + pos++; + } + return pos; +} + +int Document::NextWordStart(int pos, int delta) { + if (delta < 0) { + while (pos > 0 && (cb.CharAt(pos - 1) == ' ' || cb.CharAt(pos - 1) == '\t')) + pos--; + if (isspace(cb.CharAt(pos - 1))) { // Back up to previous line + while (pos > 0 && isspace(cb.CharAt(pos - 1))) + pos--; + } else { + bool startAtWordChar = IsWordChar(cb.CharAt(pos - 1)); + while (pos > 0 && !isspace(cb.CharAt(pos - 1)) && (startAtWordChar == IsWordChar(cb.CharAt(pos - 1)))) + pos--; + } + } else { + bool startAtWordChar = IsWordChar(cb.CharAt(pos)); + while (pos < (Length()) && isspace(cb.CharAt(pos))) + pos++; + while (pos < (Length()) && !isspace(cb.CharAt(pos)) && (startAtWordChar == IsWordChar(cb.CharAt(pos)))) + pos++; + while (pos < (Length()) && (cb.CharAt(pos) == ' ' || cb.CharAt(pos) == '\t')) + pos++; + } + return pos; +} + +bool Document::IsWordAt(int start, int end) { + int lengthDoc = Length(); + if (start > 0) { + char ch = CharAt(start - 1); + if (IsWordChar(ch)) + return false; + } + if (end < lengthDoc - 1) { + char ch = CharAt(end); + if (IsWordChar(ch)) + return false; + } + return true; +} + +// 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 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 = strlen(s); + int endSearch = 0; + if (startPos <= endPos) { + endSearch = endPos - lengthFind + 1; + } else { + endSearch = endPos; + } + //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); + char firstChar = s[0]; + if (!caseSensitive) + firstChar = toupper(firstChar); + int pos = startPos; + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + char ch = CharAt(pos); + if (caseSensitive) { + if (ch == firstChar) { + bool found = true; + for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { + ch = CharAt(pos + posMatch); + if (ch != s[posMatch]) + found = false; + } + if (found) { + if ((!word) || IsWordAt(pos, pos + lengthFind)) + return pos; + } + } + } else { + if (toupper(ch) == firstChar) { + bool found = true; + for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { + ch = CharAt(pos + posMatch); + if (toupper(ch) != toupper(s[posMatch])) + found = false; + } + if (found) { + if ((!word) || IsWordAt(pos, pos + lengthFind)) + return pos; + } + } + } + pos += increment; + if (dbcsCodePage) { + // Ensure trying to match from start of character + pos = MovePositionOutsideChar(pos, increment, false); + } + } + //Platform::DebugPrintf("Not found\n"); + return - 1; +} + +int Document::LinesTotal() { + return cb.Lines(); +} + +void Document::SetWordChars(unsigned char *chars) { + int ch; + for (ch = 0; ch < 256; ch++) { + wordchars[ch] = false; + } + if (chars) { + while (*chars) { + wordchars[*chars] = true; + chars++; + } + } else { + for (ch = 0; ch < 256; ch++) { + wordchars[ch] = isalnum(ch) || ch == '_'; + } + } +} + +void Document::SetStylingBits(int bits) { + stylingBits = bits; + stylingBitsMask = 0; + for (int bit=0; bitNotifyModifyAttempt(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) { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyModified(this, mh, watchers[i].userData); + } +} diff --git a/contrib/src/stc/scintilla/src/Document.h b/contrib/src/stc/scintilla/src/Document.h new file mode 100644 index 0000000000..fba611c7f7 --- /dev/null +++ b/contrib/src/stc/scintilla/src/Document.h @@ -0,0 +1,222 @@ +// Scintilla source code edit control +// Document.h - text document that handles notifications, DBCS, styling, words and end of line +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef DOCUMENT_H +#define DOCUMENT_H + +// 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); + } + + bool Contains(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 { + +public: + // Used to pair watcher pointer with user data + class WatcherWithUserData { + public: + DocWatcher *watcher; + void *userData; + WatcherWithUserData() { + watcher = 0; + userData = 0; + } + }; + +private: + int refCount; + CellBuffer cb; + bool wordchars[256]; + int stylingPos; + int stylingMask; + int endStyled; + int enteredCount; + + WatcherWithUserData *watchers; + int lenWatchers; + +public: + int stylingBits; + int stylingBitsMask; + + int eolMode; + int dbcsCodePage; + int tabInChars; + + Document(); + virtual ~Document(); + + int AddRef(); + int Release(); + + int LineFromPosition(int pos); + int ClampPositionIntoDocument(int pos); + bool IsCrLf(int pos); + int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); + + // Gateways to modifying document + void DeleteChars(int pos, int len); + void InsertStyledString(int position, char *s, int insertLength); + int Undo(); + int Redo(); + bool CanUndo() { return cb.CanUndo(); } + bool CanRedo() { return cb.CanRedo(); } + void DeleteUndoHistory() { cb.DeleteUndoHistory(); } + undoCollectionType SetUndoCollection(undoCollectionType collectUndo) { + return cb.SetUndoCollection(collectUndo); + } + void AppendUndoStartAction() { cb.AppendUndoStartAction(); } + void BeginUndoAction() { cb.BeginUndoAction(); } + void EndUndoAction() { cb.EndUndoAction(); } + void SetSavePoint(); + bool IsSavePoint() { return cb.IsSavePoint(); } + void Indent(bool forwards, int lineBottom, int lineTop); + void ConvertLineEnds(int eolModeSet); + void SetReadOnly(bool set) { cb.SetReadOnly(set); } + + void InsertChar(int pos, char ch); + void InsertString(int position, const char *s); + void InsertString(int position, const char *s, int insertLength); + void DelChar(int pos); + int 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) { return cb.GetMark(line); } + int AddMark(int line, int markerNum) { return cb.AddMark(line, markerNum); } + void DeleteMark(int line, int markerNum) { cb.DeleteMark(line, markerNum); } + void DeleteMarkFromHandle(int markerHandle) { cb.DeleteMarkFromHandle(markerHandle); } + void DeleteAllMarks(int markerNum) { cb.DeleteAllMarks(markerNum); } + int LineFromHandle(int markerHandle) { return cb.LineFromHandle(markerHandle); } + int LineStart(int line); + int LineEndPosition(int position); + int VCHomePosition(int position); + + int SetLevel(int line, int level); + int GetLevel(int line) { return cb.GetLevel(line); } + int GetLastChild(int lineParent, int level=-1); + int GetFoldParent(int line); + + void Indent(bool forwards); + int ExtendWordSelect(int pos, int delta); + int NextWordStart(int pos, int delta); + int Length() { return cb.Length(); } + long FindText(int minPos, int maxPos, const char *s, bool caseSensitive, bool word); + long FindText(WORD iMessage,WPARAM wParam,LPARAM lParam); + int LinesTotal(); + + void SetWordChars(unsigned char *chars); + void SetStylingBits(int bits); + void StartStyling(int position, char mask); + void SetStyleFor(int length, char style); + void SetStyles(int length, char *styles); + int GetEndStyled() { return endStyled; } + + int SetLineState(int line, int state) { return cb.SetLineState(line, state); } + int GetLineState(int line) { return cb.GetLineState(line); } + int GetMaxLineState() { return cb.GetMaxLineState(); } + + bool AddWatcher(DocWatcher *watcher, void *userData); + bool RemoveWatcher(DocWatcher *watcher, void *userData); + const WatcherWithUserData *GetWatchers() const { return watchers; } + int GetLenWatchers() const { return lenWatchers; } + +private: + bool IsDBCS(int pos); + bool IsWordChar(unsigned char ch); + bool IsWordAt(int start, int end); + void ModifiedAt(int pos); + + 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; + + DocModification(int modificationType_, int position_=0, int length_=0, + int linesAdded_=0, const char *text_=0) : + modificationType(modificationType_), + position(position_), + length(length_), + linesAdded(linesAdded_), + text(text_), + line(0), + foldLevelNow(0), + foldLevelPrev(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; +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/Editor.cxx b/contrib/src/stc/scintilla/src/Editor.cxx new file mode 100644 index 0000000000..6508c95b1f --- /dev/null +++ b/contrib/src/stc/scintilla/src/Editor.cxx @@ -0,0 +1,3693 @@ +// Scintilla source code edit control +// Editor.cxx - main code for the edit control +// Copyright 1998-2000 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 "ContractionState.h" +#include "SVector.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "Document.h" +#include "Editor.h" + +Caret::Caret() : +active(true), on(true), period(500) {} + +Timer::Timer() : +ticking(false), ticksToWait(0), tickerID(0) {} + +Editor::Editor() { + ctrlID = 0; + + stylesValid = false; + + hideSelection = false; + inOverstrike = false; + + bufferedDraw = true; + + lastClickTime = 0; + ptMouseLast.x = 0; + ptMouseLast.y = 0; + firstExpose = true; + inDragDrop = false; + dropWentOutside = false; + posDrag = invalidPosition; + posDrop = invalidPosition; + selectionType = selChar; + + lastXChosen = 0; + lineAnchor = 0; + originalAnchorPos = 0; + + dragChars = 0; + lenDrag = 0; + dragIsRectangle = false; + selType = selStream; + xStartSelect = 0; + xEndSelect = 0; + + caretPolicy = CARET_SLOP; + caretSlop = 0; + + searchAnchor = 0; + + ucWheelScrollLines = 0; + cWheelDelta = 0; //wheel delta from roll + + xOffset = 0; + xCaretMargin = 50; + + currentPos = 0; + anchor = 0; + + topLine = 0; + posTopLine = 0; + + needUpdateUI = true; + braces[0]=invalidPosition; + braces[1]=invalidPosition; + bracesMatchStyle = STYLE_BRACEBAD; + + edgeState = EDGE_NONE; + theEdge = 0; + + paintState = notPainting; + + modEventMask = SC_MODEVENTMASKALL; + + pdoc = new Document(); + pdoc ->AddRef(); + pdoc->AddWatcher(this, 0); + +#ifdef MACRO_SUPPORT + recordingMacro = 0; +#endif + foldFlags = 0; +} + +Editor::~Editor() { + pdoc->RemoveWatcher(this, 0); + pdoc->Release(); + pdoc = 0; + DropGraphics(); + + delete []dragChars; + dragChars = 0; + lenDrag = 0; +} + +void Editor::Finalise() { +} + +void Editor::DropGraphics() { + pixmapLine.Release(); + pixmapSelMargin.Release(); + pixmapSelPattern.Release(); +} + +void Editor::InvalidateStyleData() { + stylesValid = false; + palette.Release(); + DropGraphics(); +} + +void Editor::InvalidateStyleRedraw() { + InvalidateStyleData(); + Redraw(); +} + +void Editor::RefreshColourPalette(Palette &pal, bool want) { + vs.RefreshColourPalette(pal, want); +} + +void Editor::RefreshStyleData() { + if (!stylesValid) { + stylesValid = true; + Surface surface; + surface.Init(); + vs.Refresh(surface); + RefreshColourPalette(palette, true); + palette.Allocate(wMain); + RefreshColourPalette(palette, false); + SetScrollBars(); + } +} + +PRectangle Editor::GetClientRectangle() { + return wDraw.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() - LinesOnScreen(); + if (retVal < 0) + return 0; + else + return retVal; +} + +bool IsControlCharacter(char ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +const char *ControlCharacterString(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"; + } +} + +Point Editor::LocationFromPosition(unsigned int pos) { + RefreshStyleData(); + int line = pdoc->LineFromPosition(pos); + int lineVisible = cs.DisplayFromDoc(line); + //Platform::DebugPrintf("line=%d\n", line); + Surface surface; + surface.Init(); + Point pt; + pt.y = (lineVisible - topLine) * vs.lineHeight; // + half a lineheight? + unsigned int posLineStart = pdoc->LineStart(line); + if ((pos - posLineStart) > LineLayout::maxLineLength) { + // very long line so put x at arbitrary large position + pt.x = 30000 + vs.fixedColumnWidth - xOffset; + } else { + LineLayout ll; + LayoutLine(line, &surface, vs, ll); + pt.x = ll.positions[pos - posLineStart] + vs.fixedColumnWidth - xOffset; + } + return pt; +} + +int Editor::XFromPosition(unsigned 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(topLine); +} + +int Editor::PositionFromLocation(Point pt) { + RefreshStyleData(); + pt.x = pt.x - vs.fixedColumnWidth + xOffset; + int line = cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); + if (pt.y < 0) { // Division rounds towards 0 + line = cs.DocFromDisplay((pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine); + } + if (line < 0) + return 0; + if (line >= pdoc->LinesTotal()) + return pdoc->Length(); +//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); + Surface surface; + surface.Init(); + unsigned int posLineStart = pdoc->LineStart(line); + + LineLayout ll; + LayoutLine(line, &surface, vs, ll); + for (int i = 0; i < ll.numCharsInLine; i++) { + if (pt.x < ((ll.positions[i] + ll.positions[i + 1]) / 2) || + ll.chars[i] == '\r' || ll.chars[i] == '\n') { + return i + posLineStart; + } + } + + return ll.numCharsInLine + posLineStart; +} + +int Editor::PositionFromLineX(int line, int x) { + RefreshStyleData(); + if (line >= pdoc->LinesTotal()) + return pdoc->Length(); + //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); + Surface surface; + surface.Init(); + unsigned int posLineStart = pdoc->LineStart(line); + + LineLayout ll; + LayoutLine(line, &surface, vs, ll); + for (int i = 0; i < ll.numCharsInLine; i++) { + if (x < ((ll.positions[i] + ll.positions[i + 1]) / 2) || + ll.chars[i] == '\r' || ll.chars[i] == '\n') { + return i + posLineStart; + } + } + + return ll.numCharsInLine + posLineStart; +} + +void Editor::RedrawRect(PRectangle rc) { + //Platform::DebugPrintf("Redraw %d %d - %d %d\n", rc.left, rc.top, rc.right, rc.bottom); + wDraw.InvalidateRectangle(rc); +} + +void Editor::Redraw() { + //Platform::DebugPrintf("Redraw all\n"); + wDraw.InvalidateAll(); +} + +void Editor::RedrawSelMargin() { + if (vs.maskInLine) { + Redraw(); + } else { + PRectangle rcSelMargin = GetClientRectangle(); + rcSelMargin.right = vs.fixedColumnWidth; + wDraw.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 maxLine = cs.DisplayFromDoc(pdoc->LineFromPosition(maxPos)); + 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(int line) { + if ((line == -1) || (selType == selStream)) { + return Platform::Minimum(currentPos, anchor); + } else { // selType == selRectangle + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + int lineStart = pdoc->LineFromPosition(selStart); + int lineEnd = pdoc->LineFromPosition(selEnd); + if (line < lineStart || line > lineEnd) { + return -1; + } else { + int minX = Platform::Minimum(xStartSelect, xEndSelect); + //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset); + return PositionFromLineX(line, minX); + } + } +} + +int Editor::SelectionEnd(int line) { + if ((line == -1) || (selType == selStream)) { + return Platform::Maximum(currentPos, anchor); + } else { // selType == selRectangle + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + int lineStart = pdoc->LineFromPosition(selStart); + int lineEnd = pdoc->LineFromPosition(selEnd); + if (line < lineStart || line > lineEnd) { + return -1; + } else { + int maxX = Platform::Maximum(xStartSelect, xEndSelect); + // measure line and return character closest to minx + return PositionFromLineX(line, maxX); + } + } +} + +void Editor::SetSelection(int currentPos_, int anchor_) { + currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); + anchor_ = pdoc->ClampPositionIntoDocument(anchor_); + if ((currentPos != currentPos_) || (anchor != anchor_)) { + int firstAffected = anchor; + if (firstAffected > currentPos) + firstAffected = currentPos; + if (firstAffected > anchor_) + firstAffected = anchor_; + if (firstAffected > currentPos_) + firstAffected = currentPos_; + int lastAffected = anchor; + if (lastAffected < currentPos) + lastAffected = currentPos; + if (lastAffected < anchor_) + lastAffected = anchor_; + if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted + lastAffected = (currentPos_ + 1); + currentPos = currentPos_; + anchor = anchor_; + needUpdateUI = true; + InvalidateRange(firstAffected, lastAffected); + } + ClaimSelection(); +} + +void Editor::SetSelection(int currentPos_) { + currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); + if (currentPos != currentPos_) { + int firstAffected = anchor; + if (firstAffected > currentPos) + firstAffected = currentPos; + if (firstAffected > currentPos_) + firstAffected = currentPos_; + int lastAffected = anchor; + if (lastAffected < currentPos) + lastAffected = currentPos; + if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted + lastAffected = (currentPos_ + 1); + currentPos = currentPos_; + needUpdateUI = true; + InvalidateRange(firstAffected, lastAffected); + } + ClaimSelection(); +} + +void Editor::SetEmptySelection(int currentPos_) { + SetSelection(currentPos_, currentPos_); +} + +int Editor::MovePositionTo(int newPos, bool extend) { + int delta = newPos - currentPos; + newPos = pdoc->ClampPositionIntoDocument(newPos); + newPos = pdoc->MovePositionOutsideChar(newPos, delta); + if (extend) { + SetSelection(newPos); + } else { + SetEmptySelection(newPos); + } + EnsureCaretVisible(); + ShowCaretAtCurrentPosition(); + return 0; +} + +int Editor::MovePositionSoVisible(int pos, int moveDir) { + pos = pdoc->ClampPositionIntoDocument(pos); + pos = pdoc->MovePositionOutsideChar(pos, moveDir); + int lineDoc = pdoc->LineFromPosition(pos); + if (cs.GetVisible(lineDoc)) { + return pos; + } else { + int lineDisplay = cs.DisplayFromDoc(lineDoc); + if (moveDir > 0) { + lineDisplay = Platform::Clamp(lineDisplay + 1, 0, cs.LinesDisplayed()); + return pdoc->LineStart(cs.DocFromDisplay(lineDisplay)); + } else { + // lineDisplay is already line before fold as lines in fold use display line of line before fold + lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); + return pdoc->LineEndPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay))); + } + } +} + +// Choose the x position that the caret will try to stick to as it is moves up and down +void Editor::SetLastXChosen() { + Point pt = LocationFromPosition(currentPos); + lastXChosen = pt.x; +} + +void Editor::ScrollTo(int line) { + 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. + if (abs(linesToMove) <= 10) { + ScrollText(linesToMove); + } else { + Redraw(); + } + 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); + xOffset = xPos; + if (xOffset < 0) + xOffset = 0; + SetHorizontalScrollPos(); + Redraw(); +} + +void Editor::EnsureCaretVisible(bool useMargin) { + //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset); + PRectangle rcClient = GetTextRectangle(); + int posCaret = currentPos; + if (posDrag >= 0) + posCaret = posDrag; + Point pt = LocationFromPosition(posCaret); + Point ptEOL = LocationFromPosition(pdoc->LineEndPosition(posCaret)); + Point ptBottomCaret = pt; + int lineCaret = cs.DisplayFromDoc(pdoc->LineFromPosition(posCaret)); + ptBottomCaret.y += vs.lineHeight - 1; + + // Ensure the caret is reasonably visible in context. + int xMargin = Platform::Clamp(xCaretMargin, 2, Platform::Maximum(rcClient.Width() - 10, 4) / 2); + if (!useMargin) + xMargin = 2; + + // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge + rcClient.left = rcClient.left + xMargin; + rcClient.right = rcClient.right - xMargin; + + if (!rcClient.Contains(pt) || !rcClient.Contains(ptBottomCaret) || (caretPolicy & CARET_STRICT)) { + //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right); + // It should be possible to scroll the window to show the caret, + // but this fails to remove the caret on GTK+ + if (caretPolicy & CARET_SLOP) { + if ((topLine > lineCaret) || ((caretPolicy & CARET_STRICT) && (topLine + caretSlop > lineCaret))) { + SetTopLine(Platform::Clamp(lineCaret - caretSlop, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } else if ((lineCaret > topLine + LinesOnScreen() - 1) || + ((caretPolicy & CARET_STRICT) && (lineCaret > topLine + LinesOnScreen() - 1 - caretSlop))) { + SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() + 1 + caretSlop, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + } else { + if ((topLine > lineCaret) || (lineCaret > topLine + LinesOnScreen() - 1) || (caretPolicy & CARET_STRICT)) { + SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() / 2 + 1, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + } + int xOffsetNew = xOffset; + if (pt.x < rcClient.left) { + xOffsetNew = xOffset - (rcClient.left - pt.x); + } else if (pt.x >= rcClient.right) { + xOffsetNew = xOffset + (pt.x - rcClient.right); + int xOffsetEOL = xOffset + (ptEOL.x - rcClient.right) - xMargin + 2; + //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL); + // Ensure don't scroll out into empty space + if (xOffsetNew > xOffsetEOL) + xOffsetNew = xOffsetEOL; + } + if (xOffsetNew < 0) + xOffsetNew = 0; + if (xOffset != xOffsetNew) { + xOffset = xOffsetNew; + SetHorizontalScrollPos(); + Redraw(); + } + } +} + +void Editor::ShowCaretAtCurrentPosition() { + if (!wMain.HasFocus()) { + caret.active = false; + caret.on = false; + return; + } + caret.active = true; + caret.on = true; + SetTicking(true); +} + +void Editor::DropCaret() { + caret.active = false; + InvalidateCaret(); +} + +void Editor::InvalidateCaret() { + if (posDrag >= 0) + InvalidateRange(posDrag, posDrag + 1); + else + InvalidateRange(currentPos, currentPos + 1); +} + +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].symbol) { + /* 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 + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); + } else { + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); + } + + int visibleLine = topLine; + int line = cs.DocFromDisplay(visibleLine); + int yposScreen = 0; + + while (line < pdoc->LinesTotal() && yposScreen < rcMargin.bottom) { + int marks = pdoc->GetMark(line); + if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { + if (cs.GetExpanded(line)) { + marks |= 1 << SC_MARKNUM_FOLDEROPEN; + } else { + marks |= 1 << SC_MARKNUM_FOLDER; + } + } + marks &= vs.ms[margin].mask; + PRectangle rcMarker = rcSelMargin; + rcMarker.top = yposScreen; + rcMarker.bottom = yposScreen + vs.lineHeight; + if (!vs.ms[margin].symbol) { + char number[100]; + number[0] = '\0'; + sprintf(number, "%d", line + 1); + if (foldFlags & 8) + sprintf(number, "%X", pdoc->GetLevel(line)); + int xpos = 0; + PRectangle rcNumber=rcMarker; + // Right justify + int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, strlen(number)); + xpos = rcNumber.right - width - 3; + rcNumber.left = xpos; + if ((visibleLine < cs.LinesDisplayed()) && cs.GetVisible(line)) { + surface->DrawText(rcNumber, vs.styles[STYLE_LINENUMBER].font, + rcNumber.top + vs.maxAscent, number, strlen(number), + vs.styles[STYLE_LINENUMBER].fore.allocated, + vs.styles[STYLE_LINENUMBER].back.allocated); + } + } + + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + rcMarker.top++; + rcMarker.bottom--; + vs.markers[markBit].Draw(surface, rcMarker); + } + marks >>= 1; + } + } + + visibleLine++; + line = cs.DocFromDisplay(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 ((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); +} + +void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll) { + int numCharsInLine = 0; + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; + char styleByte = 0; + int styleMask = pdoc->stylingBitsMask; + for (int charInDoc = posLineStart; + charInDoc < posLineEnd && numCharsInLine < LineLayout::maxLineLength - 1; + charInDoc++) { + char chDoc = pdoc->CharAt(charInDoc); + styleByte = pdoc->StyleAt(charInDoc); + if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) { + ll.chars[numCharsInLine] = chDoc; + ll.styles[numCharsInLine] = styleByte & styleMask; + ll.indicators[numCharsInLine] = styleByte & ~styleMask; + numCharsInLine++; + } + } + ll.chars[numCharsInLine] = 0; + ll.styles[numCharsInLine] = styleByte; // For eolFilled + ll.indicators[numCharsInLine] = 0; + + // Layout the line, determining the position of each character + int startseg = 0; + int startsegx = 0; + ll.positions[0] = 0; + unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars; + + for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { + if ((ll.styles[charInLine] != ll.styles[charInLine + 1]) || + IsControlCharacter(ll.chars[charInLine]) || IsControlCharacter(ll.chars[charInLine + 1])) { + ll.positions[startseg] = 0; + if (IsControlCharacter(ll.chars[charInLine])) { + if (ll.chars[charInLine] == '\t') { + ll.positions[charInLine + 1] = ((((startsegx + 2) / + tabWidth) + 1) * tabWidth) - startsegx; + } else { + const char *ctrlChar = ControlCharacterString(ll.chars[charInLine]); + // +3 For a blank on front and rounded edge each side: + ll.positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, ctrlChar, strlen(ctrlChar)) + 3; + } + } else { + surface->MeasureWidths(vstyle.styles[ll.styles[charInLine]].font, ll.chars + startseg, + charInLine - startseg + 1, ll.positions + startseg + 1); + } + for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { + ll.positions[posToIncrease] += startsegx; + } + startsegx = ll.positions[charInLine + 1]; + startseg = charInLine + 1; + } + } + ll.numCharsInLine = numCharsInLine; +} + +void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout &ll) { + + 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; + + int marks = 0; + Colour markBack = Colour(0, 0, 0); + if (vsDraw.maskInLine) { + marks = pdoc->GetMark(line) & vsDraw.maskInLine; + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + markBack = vsDraw.markers[markBit].back.allocated; + } + marks >>= 1; + } + } + marks = pdoc->GetMark(line) & vsDraw.maskInLine; + } + + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + + int selStart = SelectionStart(line); + int selEnd = SelectionEnd(line); + + int styleMask = pdoc->stylingBitsMask; + int startseg = 0; + for (int i = 0; i < ll.numCharsInLine; i++) { + + int iDoc = i + posLineStart; + // If there is the end of a style run for any reason + if ((ll.styles[i] != ll.styles[i + 1]) || + IsControlCharacter(ll.chars[i]) || IsControlCharacter(ll.chars[i + 1]) || + ((selStart != selEnd) && ((iDoc + 1 == selStart) || (iDoc + 1 == selEnd))) || + (i == (theEdge-1))) { + int styleMain = ll.styles[i]; + Colour textBack = vsDraw.styles[styleMain].back.allocated; + Colour textFore = vsDraw.styles[styleMain].fore.allocated; + Font &textFont = vsDraw.styles[styleMain].font; + bool inSelection = (iDoc >= selStart) && (iDoc < selEnd) && (selStart != selEnd); + if (inSelection && !hideSelection) { + if (vsDraw.selbackset) + textBack = vsDraw.selbackground.allocated; + if (vsDraw.selforeset) + textFore = vsDraw.selforeground.allocated; + } else { + if (marks) + textBack = markBack; + if ((edgeState == EDGE_BACKGROUND) && (i >= theEdge) && (ll.chars[i] != '\n') && (ll.chars[i] != '\r')) + textBack = vs.edgecolour.allocated; + } + // Manage tab display + if (ll.chars[i] == '\t') { + rcSegment.left = ll.positions[i] + xStart; + rcSegment.right = ll.positions[i + 1] + xStart; + surface->FillRectangle(rcSegment, textBack); + if (vsDraw.viewWhitespace) { + surface->PenColour(textFore); + PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, + rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); + DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); + } + // Manage control character display + } else if (IsControlCharacter(ll.chars[i])) { + const char *ctrlChar = ControlCharacterString(ll.chars[i]); + rcSegment.left = ll.positions[i] + xStart; + rcSegment.right = ll.positions[i + 1] + xStart; + surface->FillRectangle(rcSegment, textBack); + 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, ctrlChar, strlen(ctrlChar), + textBack, textFore); + // Manage normal display + } else { + rcSegment.left = ll.positions[startseg] + xStart; + rcSegment.right = ll.positions[i + 1] + xStart; + // Only try do 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) { + surface->DrawText(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll.chars + startseg, + i - startseg + 1, textFore, textBack); + if (vsDraw.viewWhitespace) { + for (int cpos = 0; cpos <= i - startseg; cpos++) { + if (ll.chars[cpos + startseg] == ' ') { + int xmid = (ll.positions[cpos + startseg] + ll.positions[cpos + startseg + 1]) / 2; + PRectangle rcDot(xmid + xStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); + rcDot.right = rcDot.left + 1; + rcDot.bottom = rcDot.top + 1; + surface->FillRectangle(rcDot, textFore); + } + } + } + } + } + startseg = i + 1; + } + } + + // Draw indicators + int indStart[INDIC_MAX + 1] = {0}; + for (int indica = 0; indica <= INDIC_MAX; indica++) + indStart[indica] = 0; + + for (int indicPos = 0; indicPos <= ll.numCharsInLine; indicPos++) { + if (ll.indicators[indicPos] != ll.indicators[indicPos + 1]) { + int mask = 1 << pdoc->stylingBits; + for (int indicnum = 0; mask <= 0x100; indicnum++) { + if ((ll.indicators[indicPos + 1] & mask) && !(ll.indicators[indicPos] & mask)) { + indStart[indicnum] = ll.positions[indicPos + 1]; + } + if (!(ll.indicators[indicPos + 1] & mask) && (ll.indicators[indicPos] & mask)) { + PRectangle rcIndic( + indStart[indicnum] + xStart, + rcLine.top + vsDraw.maxAscent, + ll.positions[indicPos + 1] + xStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[indicnum].Draw(surface, rcIndic); + } + mask = mask << 1; + } + } + } + // End of the drawing of the current line + + // Fill in a PRectangle representing the end of line characters + int xEol = ll.positions[ll.numCharsInLine]; + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + vsDraw.aveCharWidth + xStart; + bool eolInSelection = (posLineEnd > selStart) && (posLineEnd <= selEnd) && (selStart != selEnd); + if (eolInSelection && !hideSelection && vsDraw.selbackset && (line < pdoc->LinesTotal()-1)) { + surface->FillRectangle(rcSegment, vsDraw.selbackground.allocated); + } else if (marks) { + surface->FillRectangle(rcSegment, markBack); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated); + } + + rcSegment.left = xEol + vsDraw.aveCharWidth + xStart; + rcSegment.right = rcLine.right; + if (marks) { + surface->FillRectangle(rcSegment, markBack); + } 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 (edgeState == EDGE_LINE) { + int edgeX = theEdge * vsDraw.spaceWidth; + rcSegment.left = edgeX + xStart; + rcSegment.right = rcSegment.left + 1; + surface->FillRectangle(rcSegment, vs.edgecolour.allocated); + } +} + +void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { + //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + RefreshStyleData(); + + PRectangle rcClient = GetClientRectangle(); + //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", + // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); + + if (!pixmapSelPattern.Initialised()) { + pixmapSelPattern.InitPixMap(8, 8, surfaceWindow); + // This complex procedure is to reproduce the checker board 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, 8, 8); + if (vs.selbarlight.desired == Colour(0xff, 0xff, 0xff)) { + pixmapSelPattern.FillRectangle(rcPattern, vs.selbar.allocated); + pixmapSelPattern.PenColour(vs.selbarlight.allocated); + for (int stripe = 0; stripe < 8; stripe++) { + pixmapSelPattern.MoveTo(0, stripe * 2); + pixmapSelPattern.LineTo(8, stripe * 2 - 8); + } + } else { + // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. + pixmapSelPattern.FillRectangle(rcPattern, vs.selbarlight.allocated); + } + } + + if (bufferedDraw) { + if (!pixmapLine.Initialised()) { + pixmapLine.InitPixMap(rcClient.Width(), rcClient.Height(), + surfaceWindow); + pixmapSelMargin.InitPixMap(vs.fixedColumnWidth, + rcClient.Height(), surfaceWindow); + } + } + + surfaceWindow->SetPalette(&palette, true); + pixmapLine.SetPalette(&palette, !wMain.HasFocus()); + + //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n", + // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + + 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 statrting 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; + + if (endPosPaint > pdoc->GetEndStyled()) { + // Notify container to do some more styling + NotifyStyleNeeded(endPosPaint); + } + if (needUpdateUI) { + NotifyUpdateUI(); + needUpdateUI = false; + } + + 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 NotifyStyleNeeded or NotifyUpdateUI noticed that painting is needed + // outside the current painting rectangle + //Platform::DebugPrintf("Abandoning paint\n"); + return; + } + //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); + + Surface *surface = 0; + if (rcArea.right > vs.fixedColumnWidth) { + + if (bufferedDraw) { + surface = &pixmapLine; + } else { + surface = surfaceWindow; + } + + int visibleLine = topLine + screenLinePaintFirst; + int line = cs.DocFromDisplay(visibleLine); + + 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); + //GTimer *tim=g_timer_new(); + while (visibleLine <= cs.LinesDisplayed() && yposScreen < rcArea.bottom) { + //g_timer_start(tim); + //Platform::DebugPrintf("Painting line %d\n", line); + + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd); + + PRectangle rcLine = rcClient; + rcLine.top = ypos; + rcLine.bottom = ypos + vs.lineHeight; + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + LineLayout ll; + LayoutLine(line, surface, vs, ll); + + // Highlight the current braces if any + if ((braces[0] >= posLineStart) && (braces[0] < posLineEnd)) + ll.styles[braces[0] - posLineStart] = bracesMatchStyle; + if ((braces[1] >= posLineStart) && (braces[1] < posLineEnd)) + ll.styles[braces[1] - posLineStart] = bracesMatchStyle; + + // Draw the line + if (cs.GetVisible(line)) + DrawLine(surface, vs, line, xStart, rcLine, ll); + + if (foldFlags & 2) { + if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.bottom = rcFoldLine.top + 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } + + // Draw the Caret + if (line == lineCaret) { + int xposCaret = ll.positions[posCaret - posLineStart] + xStart; + int widthOverstrikeCaret = + ll.positions[posCaret - posLineStart + 1] - ll.positions[posCaret - posLineStart]; + if (posCaret == pdoc->Length()) // At end of document + widthOverstrikeCaret = vs.aveCharWidth; + if ((posCaret - posLineStart) >= ll.numCharsInLine) // At end of line + widthOverstrikeCaret = vs.aveCharWidth; + if (widthOverstrikeCaret < 3) // Make sure its visible + widthOverstrikeCaret = 3; + if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) { + PRectangle rcCaret = rcLine; + if (posDrag >= 0) { + rcCaret.left = xposCaret; + rcCaret.right = xposCaret + 1; + } else { + if (inOverstrike) { + rcCaret.top = rcCaret.bottom - 2; + rcCaret.left = xposCaret + 1; + rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; + } else { + rcCaret.left = xposCaret; + rcCaret.right = xposCaret + 1; + } + } + surface->FillRectangle(rcCaret, vs.caretcolour.allocated); + } + } + + if (cs.GetVisible(line)) { + if (bufferedDraw) { + Point from(vs.fixedColumnWidth, 0); + PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen, + rcClient.right, yposScreen + vs.lineHeight); + surfaceWindow->Copy(rcCopyArea, from, pixmapLine); + } + } + + if (!bufferedDraw) { + ypos += vs.lineHeight; + } + + yposScreen += vs.lineHeight; + visibleLine++; + line = cs.DocFromDisplay(visibleLine); + //gdk_flush(); + //g_timer_stop(tim); + //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0)); + } + //g_timer_destroy(tim); + 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 (edgeState == EDGE_LINE) { + int edgeX = theEdge * vs.spaceWidth; + rcBeyondEOF.left = edgeX + xStart; + rcBeyondEOF.right = rcBeyondEOF.left + 1; + surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated); + } + } + } +} + +// Space (3 space characters) between line numbers and text when printing. +#define lineNumberPrintSpace " " + +// 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, FORMATRANGE *pfr) { + if (!pfr) + return 0; + + Surface *surface = new Surface(); + surface->Init(pfr->hdc); + Surface *surfaceMeasure = new Surface(); + surfaceMeasure->Init(pfr->hdcTarget); + + 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].symbol) && (vsPrint.ms[margin].width > 0)) { + lineNumberIndex = margin; + } else { + vsPrint.ms[margin].width = 0; + } + } + vsPrint.showMarkedLines = false; + vsPrint.fixedColumnWidth = 0; + vsPrint.zoomLevel = 0; + // Don't show the selection when printing + vsPrint.selbackset = false; + vsPrint.selforeset = false; + // White background for the line numbers + vsPrint.styles[STYLE_LINENUMBER].back.desired = Colour(0xff,0xff,0xff); + + vsPrint.Refresh(*surfaceMeasure); + // Ensure colours are set up + vsPrint.RefreshColourPalette(palette, true); + vsPrint.RefreshColourPalette(palette, false); + // Determining width must hapen after fonts have been realised in Refresh + int lineNumberWidth = 0; + if (lineNumberIndex >= 0) { + lineNumberWidth = surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, + "9999" lineNumberPrintSpace, 4 + strlen(lineNumberPrintSpace)); + vsPrint.ms[lineNumberIndex].width = lineNumberWidth; + } + + 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 - 1); + 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); + + if (endPosPrint > pdoc->GetEndStyled()) { + // Notify container to do some more styling + NotifyStyleNeeded(endPosPrint); + } + int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth; + int ypos = pfr->rc.top; + int line = linePrintStart; + + if (draw) { // Otherwise just measuring + + while (line <= linePrintLast && ypos < pfr->rc.bottom) { + + PRectangle rcLine; + rcLine.left = pfr->rc.left + lineNumberWidth; + rcLine.top = ypos; + rcLine.right = pfr->rc.right; + rcLine.bottom = ypos + vsPrint.lineHeight; + + if (lineNumberWidth) { + char number[100]; + sprintf(number, "%d" lineNumberPrintSpace, line + 1); + PRectangle rcNumber = rcLine; + rcNumber.right = rcNumber.left + lineNumberWidth; + // Right justify + rcNumber.left += lineNumberWidth - + surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, number, strlen(number)); + surface->DrawText(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, + ypos + vsPrint.maxAscent, number, strlen(number), + vsPrint.styles[STYLE_LINENUMBER].fore.allocated, + vsPrint.styles[STYLE_LINENUMBER].back.allocated); + } + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + LineLayout ll; + LayoutLine(line, surfaceMeasure, vsPrint, ll); + + // Draw the line + DrawLine(surface, vsPrint, line, xStart, rcLine, ll); + + ypos += vsPrint.lineHeight; + line++; + } + } + + delete surface; + delete surfaceMeasure; + + return endPosPrint; +} + +void Editor::SetScrollBarsTo(PRectangle) { + RefreshStyleData(); + + int nMax = cs.LinesDisplayed(); + int nPage = cs.LinesDisplayed() - MaxScrollPos() + 1; + bool modified = ModifyScrollBars(nMax, nPage); + + // 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) + Redraw(); + //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); +} + +void Editor::SetScrollBars() { + PRectangle rsClient = GetClientRectangle(); + SetScrollBarsTo(rsClient); +} + +void Editor::AddChar(char ch) { + bool wasSelection = currentPos != anchor; + ClearSelection(); + if (inOverstrike && !wasSelection) { + if (currentPos < (pdoc->Length() - 1)) { + if ((pdoc->CharAt(currentPos) != '\r') && (pdoc->CharAt(currentPos) != '\n')) { + pdoc->DelChar(currentPos); + } + } + } + pdoc->InsertChar(currentPos, ch); + SetEmptySelection(currentPos + 1); + EnsureCaretVisible(); + SetLastXChosen(); + NotifyChar(ch); +} + +void Editor::ClearSelection() { + if (selType == selRectangle) { + pdoc->BeginUndoAction(); + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int startPos = SelectionStart(); + int line; + for (line=lineStart; line <= lineEnd; line++) { + startPos = SelectionStart(line); + unsigned int chars = SelectionEnd(line) - startPos; + if (0 != chars) { + pdoc->DeleteChars(startPos, chars); + } + } + SetEmptySelection(startPos); + selType = selStream; + pdoc->EndUndoAction(); + } else { + int startPos = SelectionStart(); + unsigned int chars = SelectionEnd() - startPos; + SetEmptySelection(startPos); + if (0 != chars) { + pdoc->DeleteChars(startPos, chars); + } + } +} + +void Editor::ClearAll() { + if (0 != pdoc->Length()) { + pdoc->DeleteChars(0, pdoc->Length()); + } + cs.Clear(); + anchor = 0; + currentPos = 0; + SetTopLine(0); + SetVerticalScrollPos(); +} + +void Editor::Cut() { + Copy(); + ClearSelection(); +} + +void Editor::PasteRectangular(int pos, const char *ptr, int len) { + currentPos = pos; + int insertPos = currentPos; + int xInsert = XFromPosition(currentPos); + int line = pdoc->LineFromPosition(currentPos); + bool prevCr = false; + for (int i=0; i= pdoc->LinesTotal()) { + if (pdoc->eolMode != SC_EOL_LF) + pdoc->InsertChar(pdoc->Length(), '\r'); + if (pdoc->eolMode != SC_EOL_CR) + pdoc->InsertChar(pdoc->Length(), '\n'); + } + currentPos = PositionFromLineX(line, xInsert); + prevCr = ptr[i] == '\r'; + } else { + pdoc->InsertString(currentPos, ptr+i, 1); + currentPos++; + insertPos = currentPos; + prevCr = false; + } + } + SetEmptySelection(insertPos); +} + +void Editor::Clear() { + if (currentPos == anchor) { + DelChar(); + } else { + ClearSelection(); + } + SetEmptySelection(currentPos); +} + +void Editor::SelectAll() { + SetSelection(0, pdoc->Length()); + Redraw(); +} + +void Editor::Undo() { + if (pdoc->CanUndo()) { + int newPos = pdoc->Undo(); + SetEmptySelection(newPos); + EnsureCaretVisible(); + } +} + +void Editor::Redo() { + if (pdoc->CanRedo()) { + int newPos = pdoc->Redo(); + SetEmptySelection(newPos); + EnsureCaretVisible(); + } +} + +void Editor::DelChar() { + pdoc->DelChar(currentPos); +} + +void Editor::DelCharBack() { + if (currentPos == anchor) { + int newPos = pdoc->DelCharBack(currentPos); + SetEmptySelection(newPos); + } else { + ClearSelection(); + SetEmptySelection(currentPos); + } +} + +void Editor::NotifyFocus(bool) { +} + +void Editor::NotifyStyleNeeded(int endStyleNeeded) { + SCNotification scn; + scn.nmhdr.code = SCN_STYLENEEDED; + scn.position = endStyleNeeded; + NotifyParent(scn); +} + +void Editor::NotifyChar(char ch) { + SCNotification scn; + scn.nmhdr.code = SCN_CHARADDED; + scn.ch = ch; + NotifyParent(scn); +#ifdef MACRO_SUPPORT + if (recordingMacro) { + char txt[2]; + txt[0] = ch; + txt[1] = '\0'; + NotifyMacroRecord(EM_REPLACESEL, 0, (LPARAM) txt); + } +#endif +} + +void Editor::NotifySavePoint(bool isSavePoint) { + SCNotification scn; + if (isSavePoint) { + scn.nmhdr.code = SCN_SAVEPOINTREACHED; + } else { + scn.nmhdr.code = SCN_SAVEPOINTLEFT; + } + NotifyParent(scn); +} + +void Editor::NotifyModifyAttempt() { + SCNotification scn; + scn.nmhdr.code = SCN_MODIFYATTEMPTRO; + NotifyParent(scn); +} + +void Editor::NotifyDoubleClick(Point, bool) { + SCNotification scn; + scn.nmhdr.code = SCN_DOUBLECLICK; + NotifyParent(scn); +} + +void Editor::NotifyUpdateUI() { + SCNotification scn; + scn.nmhdr.code = SCN_UPDATEUI; + 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; + 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; + scn.nmhdr.code = SCN_NEEDSHOWN; + scn.position = pos; + scn.length = len; + NotifyParent(scn); +} + +// Notifications from document +void Editor::NotifyModifyAttempt(Document*, void *) { + //Platform::DebugPrintf("** Modify Attempt\n"); + NotifyModifyAttempt(); +} + +void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) { + //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); + NotifySavePoint(atSavePoint); +} + +void Editor::NotifyModified(Document*, DocModification mh, void *) { + needUpdateUI = true; + if (paintState == painting) { + CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); + } else if (paintState == notPainting) { + if (mh.modificationType & SC_MOD_CHANGESTYLE) { + if (mh.position < pdoc->LineStart(topLine)) { + // Styling performed before this view + Redraw(); + } else { + InvalidateRange(mh.position, mh.position + mh.length); + } + } else { + // Move selection and brace highlights + if (mh.modificationType & SC_MOD_INSERTTEXT) { + if (currentPos > mh.position) { + currentPos += mh.length; + } + if (anchor > mh.position) { + anchor += mh.length; + } + if (braces[0] > mh.position) { + braces[0] += mh.length; + } + if (braces[1] > mh.position) { + braces[1] += mh.length; + } + } else { // SC_MOD_DELETETEXT + int endPos = mh.position + mh.length; + if (currentPos > mh.position) { + if (currentPos > endPos) { + currentPos -= mh.length; + } else { + currentPos = endPos; + } + } + if (anchor > mh.position) { + if (anchor > endPos) { + anchor -= mh.length; + } else { + anchor = endPos; + } + } + if (braces[0] > mh.position) { + if (braces[0] > endPos) { + braces[0] -= mh.length; + } else { + braces[0] = endPos; + } + } + if (braces[1] > mh.position) { + if (braces[1] > endPos) { + braces[1] -= mh.length; + } else { + braces[1] = endPos; + } + } + } + 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) { + NotifyNeedShown(mh.position, mh.length); + cs.InsertLines(lineOfPos, mh.linesAdded); + } else { + cs.DeleteLines(lineOfPos, -mh.linesAdded); + } + // Avoid scrolling of display if change before current display + if (mh.position < posTopLine) { + 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); + Redraw(); + } else { + //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, + // mh.position, mh.position + mh.length); + InvalidateRange(mh.position, mh.position + mh.length); + } + } + } // else paintState == paintAbandoned so no need to do anything + + if (mh.linesAdded != 0) { + SetScrollBars(); + } + + // If client wants to see this modification + if (mh.modificationType & modEventMask) { + if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) { + // Real modification made to text of document. + NotifyChange(); // Send EN_CHANGE + } + SCNotification scn; + 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; + NotifyParent(scn); + } +} + +void Editor::NotifyDeleted(Document *document, void *userData) { + /* Do nothing */ +} + +#ifdef MACRO_SUPPORT +void Editor::NotifyMacroRecord(UINT iMessage, WPARAM wParam, LPARAM lParam) { + + // Enumerates all macroable messages + switch (iMessage) { + case WM_CUT: + case WM_COPY: + case WM_PASTE: + case WM_CLEAR: + case EM_REPLACESEL: + case SCI_ADDTEXT: + case SCI_INSERTTEXT: + 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_LINEUP: + case SCI_LINEUPEXTEND: + 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_HOME: + case SCI_HOMEEXTEND: + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + case SCI_DOCUMENTSTART: + case SCI_DOCUMENTSTARTEXTEND: + case SCI_DOCUMENTEND: + case SCI_DOCUMENTENDEXTEND: + 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_DELWORDLEFT: + case SCI_DELWORDRIGHT: + break; + + // Filter out all others (display changes, etc) + default: +// printf("Filtered out %ld of macro recording\n", iMessage); + return; + } + + // Send notification + SCNotification scn; + scn.nmhdr.code = SCN_MACRORECORD; + scn.message = iMessage; + scn.wParam = wParam; + scn.lParam = lParam; + NotifyParent(scn); +} +#endif + +// Force scroll and keep position relative to top of window +void Editor::PageMove(int direction, bool extend) { + Point pt = LocationFromPosition(currentPos); + int topLineNew = Platform::Clamp( + topLine + direction * LinesToScroll(), 0, MaxScrollPos()); + int newPos = PositionFromLocation( + Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll()))); + if (topLineNew != topLine) { + SetTopLine(topLineNew); + MovePositionTo(newPos, extend); + Redraw(); + SetVerticalScrollPos(); + } else { + MovePositionTo(newPos, extend); + } +} + +int Editor::KeyCommand(UINT iMessage) { + Point pt = LocationFromPosition(currentPos); + + switch (iMessage) { + case SCI_LINEDOWN: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y + vs.lineHeight))); + break; + case SCI_LINEDOWNEXTEND: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y + vs.lineHeight)), true); + break; + case SCI_LINEUP: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y - vs.lineHeight))); + break; + case SCI_LINEUPEXTEND: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y - vs.lineHeight)), true); + break; + case SCI_CHARLEFT: + if (SelectionEmpty()) { + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1)); + } else { + MovePositionTo(SelectionStart()); + } + SetLastXChosen(); + break; + case SCI_CHARLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), true); + SetLastXChosen(); + break; + case SCI_CHARRIGHT: + if (SelectionEmpty()) { + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1)); + } else { + MovePositionTo(SelectionEnd()); + } + SetLastXChosen(); + break; + case SCI_CHARRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), true); + SetLastXChosen(); + break; + case SCI_WORDLEFT: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1)); + SetLastXChosen(); + break; + case SCI_WORDLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), true); + SetLastXChosen(); + break; + case SCI_WORDRIGHT: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1)); + SetLastXChosen(); + break; + case SCI_WORDRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), true); + SetLastXChosen(); + break; + case SCI_HOME: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos))); + SetLastXChosen(); + break; + case SCI_HOMEEXTEND: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), true); + SetLastXChosen(); + break; + case SCI_LINEEND: + MovePositionTo(pdoc->LineEndPosition(currentPos)); + SetLastXChosen(); + break; + case SCI_LINEENDEXTEND: + MovePositionTo(pdoc->LineEndPosition(currentPos), true); + SetLastXChosen(); + break; + case SCI_DOCUMENTSTART: + MovePositionTo(0); + SetLastXChosen(); + break; + case SCI_DOCUMENTSTARTEXTEND: + MovePositionTo(0, true); + SetLastXChosen(); + break; + case SCI_DOCUMENTEND: + MovePositionTo(pdoc->Length()); + SetLastXChosen(); + break; + case SCI_DOCUMENTENDEXTEND: + MovePositionTo(pdoc->Length(), true); + SetLastXChosen(); + break; + case SCI_PAGEUP: + PageMove( -1); + break; + case SCI_PAGEUPEXTEND: + PageMove( -1, true); + break; + case SCI_PAGEDOWN: + PageMove(1); + break; + case SCI_PAGEDOWNEXTEND: + PageMove(1, true); + break; + case SCI_EDITTOGGLEOVERTYPE: + inOverstrike = !inOverstrike; + DropCaret(); + ShowCaretAtCurrentPosition(); + break; + case SCI_CANCEL: // Cancel any modes - handled in subclass + // Also unselect text + SetEmptySelection(currentPos); + break; + case SCI_DELETEBACK: + DelCharBack(); + EnsureCaretVisible(); + break; + case SCI_TAB: + Indent(true); + break; + case SCI_BACKTAB: + Indent(false); + break; + case SCI_NEWLINE: + ClearSelection(); + if (pdoc->eolMode == SC_EOL_CRLF) { + pdoc->InsertString(currentPos, "\r\n"); + SetEmptySelection(currentPos + 2); + NotifyChar('\r'); + NotifyChar('\n'); + } else if (pdoc->eolMode == SC_EOL_CR) { + pdoc->InsertChar(currentPos, '\r'); + SetEmptySelection(currentPos + 1); + NotifyChar('\r'); + } else if (pdoc->eolMode == SC_EOL_LF) { + pdoc->InsertChar(currentPos, '\n'); + SetEmptySelection(currentPos + 1); + NotifyChar('\n'); + } + SetLastXChosen(); + EnsureCaretVisible(); + break; + case SCI_FORMFEED: + AddChar('\f'); + break; + case SCI_VCHOME: + MovePositionTo(pdoc->VCHomePosition(currentPos)); + SetLastXChosen(); + break; + case SCI_VCHOMEEXTEND: + MovePositionTo(pdoc->VCHomePosition(currentPos), true); + SetLastXChosen(); + break; + case SCI_ZOOMIN: + if (vs.zoomLevel < 20) + vs.zoomLevel++; + InvalidateStyleRedraw(); + break; + case SCI_ZOOMOUT: + if (vs.zoomLevel > -10) + vs.zoomLevel--; + InvalidateStyleRedraw(); + break; + case SCI_DELWORDLEFT: { + int startWord = pdoc->NextWordStart(currentPos, -1); + pdoc->DeleteChars(startWord, currentPos - startWord); + MovePositionTo(startWord); + } + break; + case SCI_DELWORDRIGHT: { + int endWord = pdoc->NextWordStart(currentPos, 1); + pdoc->DeleteChars(currentPos, endWord - currentPos); + } + break; + } + return 0; +} + +int Editor::KeyDefault(int, int) { + return 0; +} + +int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt) { + int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + int msg = kmap.Find(key, modifiers); + if (msg) + return WndProc(msg, 0, 0); + else + return KeyDefault(key, modifiers); +} + +void Editor::SetWhitespaceVisible(bool view) { + vs.viewWhitespace = view; +} + +bool 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) { + ClearSelection(); + pdoc->InsertChar(currentPos, '\t'); + //pdoc->InsertChar(currentPos++, '\t'); + SetEmptySelection(currentPos + 1); + } 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)); + } + } +} + +long Editor::FindText(UINT iMessage, WPARAM wParam, LPARAM lParam) { + FINDTEXTEX *ft = reinterpret_cast(lParam); + int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, + wParam & FR_MATCHCASE, wParam & FR_WHOLEWORD); + if (pos != -1) { + if (iMessage == EM_FINDTEXTEX) { + ft->chrgText.cpMin = pos; + ft->chrgText.cpMax = pos + strlen(ft->lpstrText); + } + } + 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 SearchAnchor first. +// Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV. +// wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD. +// lParam contains the text to search for. +long Editor::SearchText(UINT iMessage, WPARAM wParam, LPARAM lParam) { + const char *txt = reinterpret_cast(lParam); + int pos; + + if (iMessage == SCI_SEARCHNEXT) { + pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, + wParam & FR_MATCHCASE, + wParam & FR_WHOLEWORD); + } else { + pos = pdoc->FindText(searchAnchor, 0, txt, + wParam & FR_MATCHCASE, + wParam & FR_WHOLEWORD); + } + + if (pos != -1) { + SetSelection(pos, pos + strlen(txt)); + } + + 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; +} + +int Editor::SelectionRangeLength() { + if (selType == selRectangle) { + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int totalSize = 0; + for (int line=lineStart; line <= lineEnd; line++) { + totalSize += SelectionEnd(line) - SelectionStart(line) + 1; + if (pdoc->eolMode == SC_EOL_CRLF) + totalSize++; + } + return totalSize; + } else { + return SelectionEnd() - SelectionStart(); + } +} + +char *Editor::CopySelectionRange() { + if (selType == selRectangle) { + char *text = 0; + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int totalSize = SelectionRangeLength(); + if (totalSize > 0) { + text = new char[totalSize + 1]; + if (text) { + int j = 0; + for (int line=lineStart; line <= lineEnd; line++) { + for (int i=SelectionStart(line);iCharAt(i); + } + if (pdoc->eolMode != SC_EOL_LF) + text[j++] = '\r'; + if (pdoc->eolMode != SC_EOL_CR) + text[j++] = '\n'; + } + text[totalSize] = '\0'; + } + } + return text; + } else { + return CopyRange(SelectionStart(), SelectionEnd()); + } +} + +void Editor::CopySelectionIntoDrag() { + delete []dragChars; + dragChars = 0; + lenDrag = SelectionRangeLength(); + dragChars = CopySelectionRange(); + dragIsRectangle = selType == selRectangle; + if (!dragChars) { + lenDrag = 0; + } +} + +void Editor::SetDragPosition(int newPos) { + if (newPos >= 0) { + newPos = pdoc->MovePositionOutsideChar(newPos, 1); + posDrop = newPos; + } + if (posDrag != newPos) { + caret.on = true; + SetTicking(true); + InvalidateCaret(); + posDrag = newPos; + InvalidateCaret(); + } +} + +void Editor::StartDrag() { + // Always handled by subclasses + //SetMouseCapture(true); + //wDraw.SetCursor(Window::cursorArrow); +} + +void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) { + //Platform::DebugPrintf("DropAt %d\n", inDragDrop); + if (inDragDrop) + dropWentOutside = false; + + int positionWasInSelection = PositionInSelection(position); + + if ((!inDragDrop) || !(0 == positionWasInSelection)) { + + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + + pdoc->BeginUndoAction(); + + int positionAfterDeletion = position; + if (inDragDrop && moving) { + // Remove dragged out text + if (rectangular) { + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + for (int line=lineStart; line <= lineEnd; line++) { + int startPos = SelectionStart(line); + int endPos = SelectionEnd(line); + if (position >= startPos) { + if (position > endPos) { + positionAfterDeletion -= endPos - startPos; + } else { + positionAfterDeletion -= position - startPos; + } + } + } + } else { + if (position > selStart) { + positionAfterDeletion -= selEnd - selStart; + } + } + ClearSelection(); + } + position = positionAfterDeletion; + + if (rectangular) { + PasteRectangular(position, value, strlen(value)); + pdoc->EndUndoAction(); + // Should try to select new rectangle but it may not be a rectangle now so just select the drop position + SetSelection(position, position); + } else { + position = pdoc->MovePositionOutsideChar(position, currentPos - position); + pdoc->InsertString(position, value); + pdoc->EndUndoAction(); + SetSelection(position + strlen(value), position); + } + } else if (inDragDrop) { + SetSelection(position, position); + } +} + +static int BeforeInOrAfter(int val, int minim, int maxim) { + if (val < minim) + return -1; + else if (val > maxim) + return 1; + else + return 0; +} + +int Editor::PositionInSelection(int pos) { + pos = pdoc->MovePositionOutsideChar(pos, currentPos - pos); + if (selType == selRectangle) { + if (pos < SelectionStart()) + return -1; + if (pos > SelectionEnd()) + return 1; + int linePos = pdoc->LineFromPosition(pos); + return BeforeInOrAfter(pos, SelectionStart(linePos), SelectionEnd(linePos)); + } else { + if (currentPos > anchor) { + return BeforeInOrAfter(pos, anchor, currentPos); + } else if (currentPos < anchor) { + return BeforeInOrAfter(pos, currentPos, anchor); + } + } + return 1; +} + +bool Editor::PointInSelection(Point pt) { + // TODO: fix up for rectangular selection + int pos = PositionFromLocation(pt); + if (0 == PositionInSelection(pos)) { + if (pos == SelectionStart()) { + // see if just before selection + Point locStart = LocationFromPosition(pos); + if (pt.x < locStart.x) + return false; + } + if (pos == SelectionEnd()) { + // 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::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt); + ptMouseLast = pt; + int newPos = PositionFromLocation(pt); + newPos = pdoc->MovePositionOutsideChar(newPos, currentPos - newPos); + inDragDrop = false; + + bool processed = NotifyMarginClick(pt, shift, ctrl, alt); + if (processed) + return; + + if (shift) { + 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 (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); + } else { // Single click + if (PointInSelMargin(pt)) { + if (ctrl) { + SelectAll(); + lastClickTime = curTime; + return; + } + lineAnchor = LineFromLocation(pt); + // While experimenting with folding turn off line selection + if (!shift) { + // Single click in margin: select whole line + SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor)); + } else { + // Single shift+click in margin: select from anchor to beginning of clicked line + SetSelection(pdoc->LineStart(lineAnchor), anchor); + } + SetDragPosition(invalidPosition); + SetMouseCapture(true); + selectionType = selLine; + } else { + if (!shift) { + inDragDrop = PointInSelection(pt); + } + if (inDragDrop) { + SetMouseCapture(false); + SetDragPosition(newPos); + CopySelectionIntoDrag(); + StartDrag(); + } else { + selType = alt ? selRectangle : selStream; + xStartSelect = pt.x - vs.fixedColumnWidth + xOffset; + xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + SetDragPosition(invalidPosition); + SetMouseCapture(true); + if (!shift) + SetEmptySelection(newPos); + selectionType = selChar; + originalAnchorPos = currentPos; + } + } + } + lastClickTime = curTime; + lastXChosen = pt.x; + ShowCaretAtCurrentPosition(); +} + +void Editor::ButtonMove(Point pt) { + //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); + if (HaveMouseCapture()) { + xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + ptMouseLast = pt; + int movePos = PositionFromLocation(pt); + movePos = pdoc->MovePositionOutsideChar(movePos, currentPos - movePos); + if (posDrag >= 0) { + SetDragPosition(movePos); + } else { + if (selectionType == selChar) { + SetSelection(movePos); + } else if (selectionType == selWord) { + // Continue selecting by word + if (currentPos > 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); + if (lineAnchor < lineMove) { + SetSelection(pdoc->LineStart(lineMove + 1), + pdoc->LineStart(lineAnchor)); + } else { + SetSelection(pdoc->LineStart(lineMove), + pdoc->LineStart(lineAnchor + 1)); + } + } + } + EnsureCaretVisible(false); + } else { + if (vs.fixedColumnWidth > 0) { // There is a margin + if (PointInSelMargin(pt)) { + wDraw.SetCursor(Window::cursorReverseArrow); + return; // No need to test for selection + } + } + // Display regular (drag) cursor over selection + if (PointInSelection(pt)) + wDraw.SetCursor(Window::cursorArrow); + else + wDraw.SetCursor(Window::cursorText); + } + +} + +void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { + //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture()); + if (HaveMouseCapture()) { + if (PointInSelMargin(pt)) { + wDraw.SetCursor(Window::cursorReverseArrow); + } else { + wDraw.SetCursor(Window::cursorText); + } + xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + ptMouseLast = pt; + SetMouseCapture(false); + int newPos = PositionFromLocation(pt); + newPos = pdoc->MovePositionOutsideChar(newPos, currentPos - newPos); + if (inDragDrop) { + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + if (selStart < selEnd) { + if (dragChars && lenDrag) { + if (ctrl) { + pdoc->InsertString(newPos, dragChars, lenDrag); + SetSelection(newPos, newPos + lenDrag); + } else if (newPos < selStart) { + pdoc->DeleteChars(selStart, lenDrag); + pdoc->InsertString(newPos, dragChars, lenDrag); + SetSelection(newPos, newPos + lenDrag); + } else if (newPos > selEnd) { + pdoc->DeleteChars(selStart, lenDrag); + newPos -= lenDrag; + pdoc->InsertString(newPos, dragChars, lenDrag); + SetSelection(newPos, newPos + lenDrag); + } else { + SetEmptySelection(newPos); + } + delete []dragChars; + dragChars = 0; + lenDrag = 0; + } + selectionType = selChar; + } + } else { + if (selectionType == selChar) { + SetSelection(newPos); + } + } + lastClickTime = curTime; + lastClick = pt; + lastXChosen = pt.x; + inDragDrop = false; + 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; + InvalidateCaret(); + } + } +} + +static bool IsIn(int a, int minimum, int maximum) { + return (a >= minimum) && (a <= maximum); +} + +static bool IsOverlap(int mina, int maxa, int minb, int maxb) { + return + IsIn(mina, minb, maxb) || + IsIn(maxa, minb, maxb) || + IsIn(minb, mina, maxa) || + IsIn(maxb, mina, maxa); +} + +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 rcText = GetTextRectangle(); + // Determine number of lines displayed including a possible partially displayed last line + int linesDisplayed = (rcText.bottom - rcText.top - 1) / vs.lineHeight + 1; + int bottomLine = topLine + linesDisplayed - 1; + + int lineRangeStart = cs.DisplayFromDoc(pdoc->LineFromPosition(r.start)); + int lineRangeEnd = cs.DisplayFromDoc(pdoc->LineFromPosition(r.end)); + if (!IsOverlap(topLine, bottomLine, lineRangeStart, lineRangeEnd)) { + //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n", + // lineRangeStart, lineRangeEnd, topLine, bottomLine); + return; + } + + // Assert rcPaint contained within or equal to rcText + if (rcPaint.top > rcText.top) { + // does range intersect rcText.top .. rcPaint.top + int paintTopLine = ((rcPaint.top - rcText.top-1) / vs.lineHeight) + topLine; + // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle + if (IsOverlap(topLine, paintTopLine, lineRangeStart, lineRangeEnd)) { + //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n", + // lineRangeStart, lineRangeEnd, topLine, paintTopLine); + paintState = paintAbandoned; + return; + } + } + if (rcPaint.bottom < rcText.bottom) { + // does range intersect rcPaint.bottom .. rcText.bottom + int paintBottomLine = ((rcPaint.bottom - rcText.top-1) / vs.lineHeight + 1) + topLine; + // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle + if (IsOverlap(paintBottomLine, bottomLine, lineRangeStart, lineRangeEnd)) { + //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n", + // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine); + paintState = paintAbandoned; + return; + } + } + } +} + +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 +// TODO: may need to make DBCS safe +// so should be moved into Document +int Editor::BraceMatch(int position, int maxReStyle) { + char chBrace = pdoc->CharAt(position); + char chSeek = BraceOpposite(chBrace); + if (!chSeek) + return - 1; + char styBrace = pdoc->StyleAt(position) & pdoc->stylingBitsMask; + int direction = -1; + if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') + direction = 1; + int depth = 1; + position = position + direction; + while ((position >= 0) && (position < pdoc->Length())) { + char chAtPos = pdoc->CharAt(position); + char styAtPos = pdoc->StyleAt(position) & pdoc->stylingBitsMask; + if ((position > pdoc->GetEndStyled()) || (styAtPos == styBrace)) { + if (chAtPos == chBrace) + depth++; + if (chAtPos == chSeek) + depth--; + if (depth == 0) + return position; + } + position = position + direction; + } + return - 1; +} + +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::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(); + pdoc->AddWatcher(this, 0); + Redraw(); + SetScrollBars(); +} + +// 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 (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { + if (cs.GetExpanded(line)) { + int lineMaxSubord = pdoc->GetLastChild(line); + cs.SetExpanded(line, 0); + if (lineMaxSubord > line) { + cs.SetVisible(line+1, lineMaxSubord, false); + SetScrollBars(); + Redraw(); + } + } else { + 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 line) { + if (!cs.GetVisible(line)) { + int lineParent = pdoc->GetFoldParent(line); + if (lineParent >= 0) { + if (line != lineParent) + EnsureLineVisible(lineParent); + if (!cs.GetExpanded(lineParent)) { + cs.SetExpanded(lineParent, 1); + Expand(lineParent, true); + } + } + SetScrollBars(); + Redraw(); + } +} + +LRESULT Editor::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { + //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); + + // Optional macro recording hook +#ifdef MACRO_SUPPORT + if (recordingMacro) + NotifyMacroRecord(iMessage, wParam, lParam); +#endif + + switch (iMessage) { + + case WM_GETTEXT: + { + if (lParam == 0) + return 0; + char *ptr = reinterpret_cast(lParam); + unsigned int iChar = 0; + for (; iChar < wParam-1; iChar++) + ptr[iChar] = pdoc->CharAt(iChar); + ptr[iChar] = '\0'; + return iChar; + } + + case WM_SETTEXT: + { + if (lParam == 0) + return FALSE; + pdoc->DeleteChars(0, pdoc->Length()); + SetEmptySelection(0); + pdoc->InsertString(0, reinterpret_cast(lParam)); + return TRUE; + } + + case WM_GETTEXTLENGTH: + return pdoc->Length(); + + case WM_NOTIFY: + //Platform::DebugPrintf("S notify %d %d\n", wParam, lParam); + break; + + case WM_CUT: + Cut(); + SetLastXChosen(); + break; + + case WM_COPY: + Copy(); + break; + + case WM_PASTE: + Paste(); + SetLastXChosen(); + break; + + case WM_CLEAR: + Clear(); + SetLastXChosen(); + break; + + case WM_UNDO: + Undo(); + SetLastXChosen(); + break; + + // Edit control mesages + + // Not supported (no-ops): + // EM_GETWORDBREAKPROC + // EM_GETWORDBREAKPROCEX + // EM_SETWORDBREAKPROC + // EM_SETWORDBREAKPROCEX + // EM_GETWORDWRAPMODE + // EM_SETWORDWRAPMODE + // EM_LIMITTEXT + // EM_EXLIMITTEXT + // EM_SETRECT + // EM_SETRECTNP + // EM_FMTLINES + // EM_GETHANDLE + // EM_SETHANDLE + // EM_GETPASSWORDCHAR + // EM_SETPASSWORDCHAR + // EM_SETTABSTOPS + // EM_FINDWORDBREAK + // EM_GETCHARFORMAT + // EM_SETCHARFORMAT + // EM_GETOLEINTERFACE + // EM_SETOLEINTERFACE + // EM_SETOLECALLBACK + // EM_GETPARAFORMAT + // EM_SETPARAFORMAT + // EM_PASTESPECIAL + // EM_REQUESTRESIZE + // EM_GETBKGNDCOLOR + // EM_SETBKGNDCOLOR + // EM_STREAMIN + // EM_STREAMOUT + // EM_GETIMECOLOR + // EM_SETIMECOLOR + // EM_GETIMEOPTIONS + // EM_SETIMEOPTIONS + // EM_GETOPTIONS + // EM_SETOPTIONS + // EM_GETPUNCTUATION + // EM_SETPUNCTUATION + // EM_GETTHUMB + + // Not supported but should be: + // EM_GETEVENTMASK + // EM_SETEVENTMASK + // For printing: + // EM_DISPLAYBAND + // EM_SETTARGETDEVICE + + case EM_CANUNDO: + return pdoc->CanUndo() ? TRUE : FALSE; + + case EM_UNDO: + Undo(); + break; + + case EM_EMPTYUNDOBUFFER: + pdoc->DeleteUndoHistory(); + return 0; + + case EM_GETFIRSTVISIBLELINE: + return topLine; + + case EM_GETLINE: { + if (lParam == 0) + return 0; + int lineStart = pdoc->LineStart(wParam); + int lineEnd = pdoc->LineStart(wParam + 1); + char *ptr = reinterpret_cast(lParam); + WORD *pBufSize = reinterpret_cast(lParam); + if (*pBufSize < lineEnd - lineStart) { + ptr[0] = '\0'; // If no characters copied have to put a NUL into buffer + return 0; + } + int iPlace = 0; + for (int iChar = lineStart; iChar < lineEnd; iChar++) + ptr[iPlace++] = pdoc->CharAt(iChar); + return iPlace; + } + + case EM_GETLINECOUNT: + if (pdoc->LinesTotal() == 0) + return 1; + else + return pdoc->LinesTotal(); + + case EM_GETMODIFY: + return !pdoc->IsSavePoint(); + + case EM_SETMODIFY: + // Not really supported now that there is the save point stuff + //pdoc->isModified = wParam; + //return pdoc->isModified; + return false; + + case EM_GETRECT: + if (lParam == 0) + return 0; + *(reinterpret_cast(lParam)) = GetClientRectangle(); + break; + + case EM_GETSEL: + if (wParam) + *reinterpret_cast(wParam) = SelectionStart(); + if (lParam) + *reinterpret_cast(lParam) = SelectionEnd(); + return MAKELONG(SelectionStart(), SelectionEnd()); + + case EM_EXGETSEL: { + if (lParam == 0) + return 0; + CHARRANGE *pCR = reinterpret_cast(lParam); + pCR->cpMin = SelectionStart(); + pCR->cpMax = SelectionEnd(); + } + break; + + case EM_SETSEL: { + int nStart = static_cast(wParam); + int nEnd = static_cast(lParam); + if (nEnd < 0) + nEnd = pdoc->Length(); + if (nStart < 0) + nStart = nEnd; // Remove selection + SetSelection(nEnd, nStart); + EnsureCaretVisible(); + } + break; + + case EM_EXSETSEL: { + if (lParam == 0) + return 0; + CHARRANGE *pCR = reinterpret_cast(lParam); + if (pCR->cpMax == -1) { + SetSelection(pCR->cpMin, pdoc->Length()); + } else { + SetSelection(pCR->cpMin, pCR->cpMax); + } + EnsureCaretVisible(); + return pdoc->LineFromPosition(SelectionStart()); + } + + case EM_GETSELTEXT: { + if (lParam == 0) + return 0; + char *ptr = reinterpret_cast(lParam); + int selSize = SelectionRangeLength(); + char *text = CopySelectionRange(); + int iChar = 0; + if (text) { + for (; iChar < selSize; iChar++) + ptr[iChar] = text[iChar]; + ptr[iChar] = '\0'; + delete []text; + } + return iChar; + } + + case EM_GETWORDBREAKPROC: + return 0; + + case EM_SETWORDBREAKPROC: + break; + + case EM_LIMITTEXT: + // wParam holds the number of characters control should be limited to + break; + + case EM_GETLIMITTEXT: + return 0xffffffff; + + case EM_GETOLEINTERFACE: + return 0; + + case EM_LINEFROMCHAR: + if (static_cast(wParam) < 0) + wParam = SelectionStart(); + return pdoc->LineFromPosition(wParam); + + case EM_EXLINEFROMCHAR: + if (static_cast(lParam) < 0) + lParam = SelectionStart(); // Not specified, but probably OK + return pdoc->LineFromPosition(lParam); + + case EM_LINEINDEX: + 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); + + case EM_LINELENGTH: + { + if (static_cast(wParam) < 0) // Who use this anyway? + return 0; // Should be... Too complex to describe here, see MS specs! + if (static_cast(wParam) > pdoc->Length()) // Useful test, anyway... + return 0; + int line = pdoc->LineFromPosition(wParam); + int charsOnLine = 0; + for (int pos = pdoc->LineStart(line); pos < pdoc->LineStart(line + 1); pos++) { + if ((pdoc->CharAt(pos) != '\r') && (pdoc->CharAt(pos) != '\n')) + charsOnLine++; + } + return charsOnLine; + } + + // 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 EM_REPLACESEL: { + if (lParam == 0) + return 0; + pdoc->BeginUndoAction(); + ClearSelection(); + char *replacement = reinterpret_cast(lParam); + pdoc->InsertString(currentPos, replacement); + pdoc->EndUndoAction(); + SetEmptySelection(currentPos + strlen(replacement)); + EnsureCaretVisible(); + } + break; + + case EM_LINESCROLL: + ScrollTo(topLine + lParam); + HorizontalScrollTo(xOffset + wParam * vs.spaceWidth); + return TRUE; + + case EM_SCROLLCARET: + EnsureCaretVisible(); + break; + + case EM_SETREADONLY: + pdoc->SetReadOnly(wParam); + return TRUE; + + case EM_SETRECT: + break; + + case EM_CANPASTE: + return 1; + + case EM_CHARFROMPOS: { + if (lParam == 0) + return 0; + Point *ppt = reinterpret_cast(lParam); + int pos = PositionFromLocation(*ppt); + int line = pdoc->LineFromPosition(pos); + return MAKELONG(pos, line); + } + + case EM_POSFROMCHAR: { + // The MS specs for this have changed 3 times: using the RichEdit 3 version + if (wParam == 0) + return 0; + Point *ppt = reinterpret_cast(wParam); + if (lParam < 0) { + *ppt = Point(0, 0); + } else { + *ppt = LocationFromPosition(lParam); + } + return 0; + } + + case EM_FINDTEXT: + return FindText(iMessage, wParam, lParam); + + case EM_FINDTEXTEX: + return FindText(iMessage, wParam, lParam); + + case EM_GETTEXTRANGE: { + if (lParam == 0) + return 0; + TEXTRANGE *tr = reinterpret_cast(lParam); + int cpMax = tr->chrg.cpMax; + if (cpMax == -1) + 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 EM_SELECTIONTYPE: + if (currentPos == anchor) + return SEL_EMPTY; + else + return SEL_TEXT; + + case EM_HIDESELECTION: + hideSelection = wParam; + Redraw(); + break; + + case EM_FORMATRANGE: + return FormatRange(wParam, reinterpret_cast(lParam)); + + case EM_GETMARGINS: + return MAKELONG(vs.leftMarginWidth, vs.rightMarginWidth); + + case EM_SETMARGINS: + if (wParam & EC_LEFTMARGIN) { + vs.leftMarginWidth = LOWORD(lParam); + } + if (wParam & EC_RIGHTMARGIN) { + vs.rightMarginWidth = HIWORD(lParam); + } + if (wParam == EC_USEFONTINFO) { + vs.leftMarginWidth = vs.aveCharWidth / 2; + vs.rightMarginWidth = vs.aveCharWidth / 2; + } + InvalidateStyleRedraw(); + break; + + // Control specific mesages + + case SCI_ADDTEXT: { + if (lParam == 0) + return 0; + pdoc->InsertString(CurrentPosition(), reinterpret_cast(lParam), wParam); + SetEmptySelection(currentPos + wParam); + return 0; + } + + case SCI_ADDSTYLEDTEXT: { + if (lParam == 0) + return 0; + pdoc->InsertStyledString(CurrentPosition() * 2, reinterpret_cast(lParam), wParam); + SetEmptySelection(currentPos + wParam / 2); + return 0; + } + + case SCI_INSERTTEXT: { + if (lParam == 0) + return 0; + int insertPos = wParam; + if (static_cast(wParam) == -1) + insertPos = CurrentPosition(); + int newCurrent = CurrentPosition(); + int newAnchor = anchor; + char *sz = reinterpret_cast(lParam); + pdoc->InsertString(insertPos, sz); + if (newCurrent > insertPos) + newCurrent += strlen(sz); + if (newAnchor > insertPos) + newAnchor += strlen(sz); + SetEmptySelection(newCurrent); + return 0; + } + + case SCI_CLEARALL: + ClearAll(); + return 0; + + case SCI_SETUNDOCOLLECTION: + pdoc->SetUndoCollection(static_cast(wParam)); + return 0; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_APPENDUNDOSTARTACTION: + pdoc->AppendUndoStartAction(); + return 0; +#endif + + 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: { + if (lParam == 0) + return 0; + pdoc->SetWordChars(reinterpret_cast(lParam)); + } + break; + + case SCI_GETLENGTH: + return pdoc->Length(); + + case SCI_GETCHARAT: + return pdoc->CharAt(wParam); + + case SCI_GETCURRENTPOS: + return currentPos; + + case SCI_GETANCHOR: + return anchor; + + 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(); + NotifySavePoint(true); + 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() ? TRUE : FALSE; + + 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 = wParam; + Redraw(); + break; + + case SCI_GOTOLINE: + GoToLine(wParam); + break; + + case SCI_GOTOPOS: + SetEmptySelection(wParam); + EnsureCaretVisible(); + Redraw(); + break; + + case SCI_SETANCHOR: + SetSelection(currentPos, wParam); + break; + + case SCI_GETCURLINE: { + if (lParam == 0) + return 0; + int lineCurrentPos = pdoc->LineFromPosition(currentPos); + int lineStart = pdoc->LineStart(lineCurrentPos); + unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1); + char *ptr = reinterpret_cast(lParam); + unsigned int iPlace = 0; + for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam; 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, lParam); + break; + + case SCI_SETSTYLING: + pdoc->SetStyleFor(wParam, lParam); + break; + + case SCI_SETSTYLINGEX: // Specify a complete styling buffer + if (lParam == 0) + return 0; + pdoc->SetStyles(wParam, reinterpret_cast(lParam)); + break; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETMARGINWIDTH: + if (wParam < 100) { + vs.ms[1].width = wParam; + } + InvalidateStyleRedraw(); + break; +#endif + + case SCI_SETBUFFEREDDRAW: + bufferedDraw = wParam; + break; + + case SCI_SETTABWIDTH: + if (wParam > 0) + pdoc->tabInChars = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETCODEPAGE: + pdoc->dbcsCodePage = wParam; + break; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETLINENUMBERWIDTH: + if (wParam < 200) { + vs.ms[0].width = wParam; + } + InvalidateStyleRedraw(); + break; +#endif + + case SCI_SETUSEPALETTE: + palette.allowRealization = wParam; + InvalidateStyleRedraw(); + break; + + // Marker definition and setting + case SCI_MARKERDEFINE: + if (wParam <= MARKER_MAX) + vs.markers[wParam].markType = lParam; + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERSETFORE: + if (wParam <= MARKER_MAX) + vs.markers[wParam].fore.desired = Colour(lParam); + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERSETBACK: + if (wParam <= MARKER_MAX) + vs.markers[wParam].back.desired = Colour(lParam); + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERADD: { + int markerID = pdoc->AddMark(wParam, lParam); + RedrawSelMargin(); + return markerID; + } + + case SCI_MARKERDELETE: + pdoc->DeleteMark(wParam, lParam); + RedrawSelMargin(); + break; + + case SCI_MARKERDELETEALL: + pdoc->DeleteAllMarks(static_cast(wParam)); + RedrawSelMargin(); + 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_SETMARGINTYPEN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].symbol = (lParam == SC_MARGIN_SYMBOL); + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINTYPEN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].symbol ? SC_MARGIN_SYMBOL : SC_MARGIN_NUMBER; + else + return 0; + + case SCI_SETMARGINWIDTHN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].width = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINWIDTHN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].width; + else + return 0; + + case SCI_SETMARGINMASKN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].mask = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINMASKN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].mask; + else + return 0; + + case SCI_SETMARGINSENSITIVEN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].sensitive = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINSENSITIVEN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].sensitive ? 1 : 0; + else + return 0; + + case SCI_STYLECLEARALL: + vs.ClearStyles(); + InvalidateStyleRedraw(); + break; + + case SCI_STYLESETFORE: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].fore.desired = Colour(lParam); + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETBACK: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].back.desired = Colour(lParam); + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETBOLD: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].bold = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETITALIC: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].italic = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETEOLFILLED: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].eolFilled = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETSIZE: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].size = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETFONT: + if (lParam == 0) + return 0; + if (wParam <= STYLE_MAX) { + strcpy(vs.styles[wParam].fontName, reinterpret_cast(lParam)); + InvalidateStyleRedraw(); + } + break; + + case SCI_STYLERESETDEFAULT: + vs.ResetDefaultStyle(); + InvalidateStyleRedraw(); + break; + + case SCI_SETSTYLEBITS: + 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(); + + // Folding messages + + case SCI_VISIBLEFROMDOCLINE: + return cs.DisplayFromDoc(wParam); + + case SCI_DOCLINEFROMVISIBLE: + return cs.DocFromDisplay(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: + cs.SetVisible(wParam, lParam, false); + SetScrollBars(); + Redraw(); + break; + + case SCI_GETLINEVISIBLE: + return cs.GetVisible(wParam); + + case SCI_SETFOLDEXPANDED: + if (cs.SetExpanded(wParam, lParam)) { + 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); + break; + + case SCI_SEARCHANCHOR: + SearchAnchor(); + break; + + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + return SearchText(iMessage, wParam, lParam); + break; + + case SCI_SETCARETPOLICY: + caretPolicy = wParam; + caretSlop = lParam; + break; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETFORE: + vs.styles[STYLE_DEFAULT].fore.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETBACK: + vs.styles[STYLE_DEFAULT].back.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETBOLD: + vs.styles[STYLE_DEFAULT].bold = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETITALIC: + vs.styles[STYLE_DEFAULT].italic = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETSIZE: + vs.styles[STYLE_DEFAULT].size = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETFONT: + if (wParam == 0) + return 0; + strcpy(vs.styles[STYLE_DEFAULT].fontName, reinterpret_cast(wParam)); + InvalidateStyleRedraw(); + break; +#endif + + case SCI_SETSELFORE: + vs.selforeset = wParam; + vs.selforeground.desired = Colour(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETSELBACK: + vs.selbackset = wParam; + vs.selbackground.desired = Colour(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETCARETFORE: + vs.caretcolour.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_ASSIGNCMDKEY: + kmap.AssignCmdKey(LOWORD(wParam), HIWORD(wParam), lParam); + break; + + case SCI_CLEARCMDKEY: + kmap.AssignCmdKey(LOWORD(wParam), HIWORD(wParam), WM_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 = Colour(lParam); + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETFORE: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0; + + case SCI_LINEDOWN: + case SCI_LINEDOWNEXTEND: + case SCI_LINEUP: + case SCI_LINEUPEXTEND: + 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_HOME: + case SCI_HOMEEXTEND: + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + case SCI_DOCUMENTSTART: + case SCI_DOCUMENTSTARTEXTEND: + case SCI_DOCUMENTEND: + case SCI_DOCUMENTENDEXTEND: + 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_ZOOMIN: + case SCI_ZOOMOUT: + case SCI_DELWORDLEFT: + case SCI_DELWORDRIGHT: + 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 BraceMatch(wParam, lParam); + + case SCI_GETVIEWEOL: + return vs.viewEOL; + + case SCI_SETVIEWEOL: + vs.viewEOL = wParam; + Redraw(); + break; + + case SCI_GETEDGECOLUMN: + return theEdge; + + case SCI_SETEDGECOLUMN: + theEdge = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEDGEMODE: + return edgeState; + + case SCI_SETEDGEMODE: + edgeState = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEDGECOLOUR: + return vs.edgecolour.desired.AsLong(); + + case SCI_SETEDGECOLOUR: + vs.edgecolour.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_GETDOCPOINTER: + return reinterpret_cast(pdoc); + + case SCI_SETDOCPOINTER: + SetDocPointer(reinterpret_cast(lParam)); + return 0; + + case SCI_SETMODEVENTMASK: + modEventMask = wParam; + return 0; + + case SCI_CONVERTEOLS: + pdoc->ConvertLineEnds(wParam); + SetSelection(currentPos, anchor); // Ensure selection inside document + return 0; + +#ifdef MACRO_SUPPORT + case SCI_STARTRECORD: + recordingMacro = 1; + return 0; + + case SCI_STOPRECORD: + recordingMacro = 0; + return 0; +#endif + + default: + return DefWndProc(iMessage, wParam, lParam); + } + //Platform::DebugPrintf("end wnd proc\n"); + return 0l; +} diff --git a/contrib/src/stc/scintilla/src/Editor.h b/contrib/src/stc/scintilla/src/Editor.h new file mode 100644 index 0000000000..4ff334767a --- /dev/null +++ b/contrib/src/stc/scintilla/src/Editor.h @@ -0,0 +1,281 @@ +// Scintilla source code edit control +// Editor.h - defines the main editor class +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITOR_H +#define EDITOR_H + +class Caret { +public: + bool active; + bool on; + int period; + + Caret(); +}; + +class Timer { + +public: + bool ticking; + int ticksToWait; + enum {tickSize = 100}; + int tickerID; + + Timer(); +}; + +class LineLayout { +public: + // Drawing is only performed for maxLineLength characters on each line. + enum {maxLineLength = 4000}; + int numCharsInLine; + char chars[maxLineLength]; + char styles[maxLineLength]; + char indicators[maxLineLength]; + int positions[maxLineLength]; +}; + +class Editor : public DocWatcher { +protected: // ScintillaBase subclass needs access to much of Editor + + // On GTK+, Scintilla is a container widget holding two scroll bars and a drawing area + // whereas on Windows there is just one window with both scroll bars turned on. + // Therefore, on GTK+ the following are separate windows but only one window on Windows. + Window wMain; // The Scintilla parent window + Window wDraw; // The text drawing area + + // 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; + + bool hideSelection; + bool inOverstrike; + + // 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; + + int xOffset; // Horizontal scrolled amount in pixels + int xCaretMargin; // Ensure this many pixels visible on both sides of caret + + Surface pixmapLine; + Surface pixmapSelMargin; + Surface pixmapSelPattern; + // Intellimouse support - currently only implemented for Windows + unsigned int ucWheelScrollLines; + short cWheelDelta; //wheel delta from roll + + KeyMap kmap; + + Caret caret; + Timer timer; + + Point lastClick; + unsigned int lastClickTime; + enum { selChar, selWord, selLine } selectionType; + Point ptMouseLast; + bool firstExpose; + bool inDragDrop; + bool dropWentOutside; + int posDrag; + int posDrop; + int lastXChosen; + int lineAnchor; + int originalAnchorPos; + int currentPos; + int anchor; + int topLine; + int posTopLine; + + bool needUpdateUI; + Position braces[2]; + int bracesMatchStyle; + + int edgeState; + int theEdge; + + enum { notPainting, painting, paintAbandoned } paintState; + PRectangle rcPaint; + bool paintingAllText; + + int modEventMask; + + char *dragChars; + int lenDrag; + bool dragIsRectangle; + enum { selStream, selRectangle, selRectangleFixed } selType; + int xStartSelect; + int xEndSelect; + + int caretPolicy; + int caretSlop; + + int searchAnchor; + +#ifdef MACRO_SUPPORT + int recordingMacro; +#endif + + int foldFlags; + ContractionState cs; + + 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(); + + PRectangle GetClientRectangle(); + PRectangle GetTextRectangle(); + + int LinesOnScreen(); + int LinesToScroll(); + int MaxScrollPos(); + Point LocationFromPosition(unsigned int pos); + int XFromPosition(unsigned int pos); + int PositionFromLocation(Point pt); + int PositionFromLineX(int line, int x); + int LineFromLocation(Point pt); + void SetTopLine(int topLineNew); + + void RedrawRect(PRectangle rc); + void Redraw(); + void RedrawSelMargin(); + PRectangle RectangleFromRange(int start, int end); + void InvalidateRange(int start, int end); + + int CurrentPosition(); + bool SelectionEmpty(); + int SelectionStart(int line=-1); + int SelectionEnd(int line=-1); + void SetSelection(int currentPos_, int anchor_); + void SetSelection(int currentPos_); + void SetEmptySelection(int currentPos_); + int MovePositionTo(int newPos, bool extend = false); + int MovePositionSoVisible(int pos, int moveDir); + void SetLastXChosen(); + + void ScrollTo(int line); + virtual void ScrollText(int linesToMove); + void HorizontalScrollTo(int xPos); + void EnsureCaretVisible(bool useMargin=true); + void ShowCaretAtCurrentPosition(); + void DropCaret(); + void InvalidateCaret(); + + void PaintSelMargin(Surface *surface, PRectangle &rc); + void LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll); + void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout &ll); + void Paint(Surface *surfaceWindow, PRectangle rcArea); + long FormatRange(bool draw, FORMATRANGE *pfr); + + virtual void SetVerticalScrollPos() = 0; + virtual void SetHorizontalScrollPos() = 0; + virtual bool ModifyScrollBars(int nMax, int nPage) = 0; + void SetScrollBarsTo(PRectangle rsClient); + void SetScrollBars(); + + virtual void AddChar(char ch); + void ClearSelection(); + void ClearAll(); + void Cut(); + void PasteRectangular(int pos, const char *ptr, int len); + virtual void Copy() = 0; + virtual void Paste() = 0; + void Clear(); + void SelectAll(); + void Undo(); + void Redo(); + void DelChar(); + void DelCharBack(); + virtual void ClaimSelection() = 0; + + virtual void NotifyChange() = 0; + virtual void NotifyFocus(bool focus); + virtual void NotifyParent(SCNotification scn) = 0; + virtual void NotifyStyleNeeded(int endStyleNeeded); + void NotifyChar(char ch); + void NotifySavePoint(bool isSavePoint); + void NotifyModifyAttempt(); + virtual void NotifyDoubleClick(Point pt, bool shift); + void NotifyUpdateUI(); + bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt); + void NotifyNeedShown(int pos, int len); + + void NotifyModifyAttempt(Document *document, void *userData); + void NotifySavePoint(Document *document, void *userData, bool atSavePoint); + void NotifyModified(Document *document, DocModification mh, void *userData); + void NotifyDeleted(Document *document, void *userData); + +#ifdef MACRO_SUPPORT + void NotifyMacroRecord(UINT iMessage, WPARAM wParam, LPARAM lParam); +#endif + + void PageMove(int direction, bool extend=false); + virtual int KeyCommand(UINT iMessage); + virtual int KeyDefault(int /* key */, int /*modifiers*/); + int KeyDown(int key, bool shift, bool ctrl, bool alt); + + bool GetWhitespaceVisible(); + void SetWhitespaceVisible(bool view); + + void Indent(bool forwards); + + long FindText(UINT iMessage,WPARAM wParam,LPARAM lParam); + void SearchAnchor(); + long SearchText(UINT iMessage,WPARAM wParam,LPARAM lParam); + void GoToLine(int lineNo); + + char *CopyRange(int start, int end); + int SelectionRangeLength(); + char *CopySelectionRange(); + void CopySelectionIntoDrag(); + void SetDragPosition(int newPos); + 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); + 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(); + virtual void SetTicking(bool on) = 0; + virtual void SetMouseCapture(bool on) = 0; + virtual bool HaveMouseCapture() = 0; + + void CheckForChangeOutsidePaint(Range r); + int BraceMatch(int position, int maxReStyle); + void SetBraceHighlight(Position pos0, Position pos1, int matchStyle); + + void SetDocPointer(Document *document); + + void Expand(int &line, bool doExpand); + void ToggleContraction(int line); + void EnsureLineVisible(int line); + + virtual LRESULT DefWndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) = 0; + +public: + // Public so scintilla_send_message can use it + virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); + // Public so scintilla_set_id can use it + int ctrlID; +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/Indicator.cxx b/contrib/src/stc/scintilla/src/Indicator.cxx new file mode 100644 index 0000000000..fb6ad09157 --- /dev/null +++ b/contrib/src/stc/scintilla/src/Indicator.cxx @@ -0,0 +1,45 @@ +// Scintilla source code edit control +// Indicator.cxx - defines the style of indicators which are text decorations such as underlining +// Copyright 1998-2000 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" + +void Indicator::Draw(Surface *surface, PRectangle &rc) { + 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 { // Either INDIC_PLAIN or unknown + surface->MoveTo(rc.left, ymid); + surface->LineTo(rc.right, ymid); + } +} + diff --git a/contrib/src/stc/scintilla/src/Indicator.h b/contrib/src/stc/scintilla/src/Indicator.h new file mode 100644 index 0000000000..2472cedc14 --- /dev/null +++ b/contrib/src/stc/scintilla/src/Indicator.h @@ -0,0 +1,18 @@ +// Scintilla source code edit control +// Indicator.h - defines the style of indicators which are text decorations such as underlining +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef INDICATOR_H +#define INDICATOR_H + +class Indicator { +public: + int style; + ColourPair fore; + Indicator() : style(INDIC_PLAIN), fore(Colour(0,0,0)) { + } + void Draw(Surface *surface, PRectangle &rc); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/KeyMap.cxx b/contrib/src/stc/scintilla/src/KeyMap.cxx new file mode 100644 index 0000000000..f339cd2750 --- /dev/null +++ b/contrib/src/stc/scintilla/src/KeyMap.cxx @@ -0,0 +1,111 @@ +// Scintilla source code edit control +// KeyMap.cxx - defines a mapping between keystrokes and commands +// Copyright 1998-2000 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" + +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, UINT msg) { + if ((len+1) >= alloc) { + KeyToCommand *ktcNew = new KeyToCommand[alloc + 5]; + if (!ktcNew) + return; + for (int k=0;k +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef KEYTOCOMMAND_H +#define KEYTOCOMMAND_H + +#define SCI_NORM 0 +#define SCI_SHIFT SHIFT_PRESSED +#define SCI_CTRL LEFT_CTRL_PRESSED +#define SCI_ALT LEFT_ALT_PRESSED +#define SCI_CSHIFT (SCI_CTRL | SCI_SHIFT) + +class KeyToCommand { +public: + int key; + int modifiers; + UINT msg; +}; + +class KeyMap { + KeyToCommand *kmap; + int len; + int alloc; + static KeyToCommand MapDefault[]; +public: + KeyMap(); + ~KeyMap(); + void Clear(); + void AssignCmdKey(int key, int modifiers, UINT msg); + UINT Find(int key, int modifiers); // 0 returned on failure +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/KeyWords.cxx b/contrib/src/stc/scintilla/src/KeyWords.cxx new file mode 100644 index 0000000000..20f6762470 --- /dev/null +++ b/contrib/src/stc/scintilla/src/KeyWords.cxx @@ -0,0 +1,2217 @@ +// SciTE - Scintilla based Text Editor +// KeyWords.cxx - colourise for particular languages +// Copyright 1998-2000 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" + +inline bool IsLeadByte(int codePage, char ch) { +#if PLAT_GTK + // TODO: support DBCS under GTK+ + return false; +#elif PLAT_WIN + return codePage && IsDBCSLeadByteEx(codePage, ch); +#elif PLAT_WX + return false; +#endif +} + +inline bool iswordchar(char ch) { + return isalnum(ch) || ch == '.' || ch == '_'; +} + +inline bool iswordstart(char ch) { + return isalnum(ch) || ch == '_'; +} + +enum { wsSpace = 1, wsTab = 2, wsSpaceTab = 4, wsInconsistent=8}; + +static int IndentAmount(StylingContext &styler, int line, int *flags) { + int end = styler.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 = styler.LineStart(line); + char ch = styler[pos]; + int indent = 0; + bool inPrevPrefix = line > 0; + int posPrev = inPrevPrefix ? styler.LineStart(line-1) : 0; + while ((ch == ' ' || ch == '\t') && (pos < end)) { + if (inPrevPrefix) { + char chPrev = styler[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 = styler[++pos]; + } + + *flags = spaceFlags; + indent += SC_FOLDLEVELBASE; + if (isspace(ch)) // Completely empty line + return indent | SC_FOLDLEVELWHITEFLAG; + else + return indent; +} + +inline bool isoperator(char ch) { + if (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; +} + +static void classifyWordCpp(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_C_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_C_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_C_WORD; + } + styler.ColourSegment(start, end, chAttr); +} + +static void ColouriseCppDoc(int codePage, int startPos, int length, + int initStyle, WordList &keywords, StylingContext &styler) { + + bool fold = styler.GetPropSet().GetInt("fold"); + int lineCurrent = styler.GetLine(startPos); + int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; + int levelCurrent = levelPrev; + + int state = initStyle; + char chPrev = ' '; + char chNext = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + int visChars = 0; + for (unsigned int i = startPos; i <= lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if ((fold) && ((ch == '\r' && chNext != '\n') || (ch == '\n'))) { + int lev = levelPrev; + if (visChars == 0) + lev |= SC_FOLDLEVELWHITEFLAG; + if ((levelCurrent > levelPrev) && (visChars > 0)) + lev |= SC_FOLDLEVELHEADERFLAG; + styler.SetLevel(lineCurrent, lev); + lineCurrent++; + visChars = 0; + levelPrev = levelCurrent; + } + if (!isspace(ch)) + visChars++; + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_C_STRINGEOL) { + if (ch != '\r' && ch != '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } + if (state == SCE_C_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_WORD; + startSeg = i; + } else if (ch == '/' && chNext == '*') { + styler.ColourSegment(startSeg, i - 1, state); + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_C_COMMENTDOC; + else + state = SCE_C_COMMENT; + startSeg = i; + } else if (ch == '/' && chNext == '/') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRING; + startSeg = i; + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_CHARACTER; + startSeg = i; + } else if (ch == '#') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_PREPROCESSOR; + startSeg = i; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_C_OPERATOR); + startSeg = i + 1; + if ((ch == '{') || (ch == '}')) { + levelCurrent += (ch == '{') ? 1 : -1; + } + } + } else if (state == SCE_C_WORD) { + if (!iswordchar(ch)) { + classifyWordCpp(startSeg, i - 1, keywords, styler); + state = SCE_C_DEFAULT; + startSeg = i; + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_C_COMMENTDOC; + else + state = SCE_C_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } else if (ch == '\'') { + state = SCE_C_CHARACTER; + } else if (ch == '#') { + state = SCE_C_PREPROCESSOR; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + if ((ch == '{') || (ch == '}')) { + levelCurrent += (ch == '{') ? 1 : -1; + } + } + } + } else { + if (state == SCE_C_PREPROCESSOR) { + if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_COMMENT) { + if (ch == '/' && chPrev == '*' && ( + (i > startSeg + 2) || ((initStyle == SCE_C_COMMENT) && (startSeg == startPos)))) { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_C_COMMENTDOC) { + if (ch == '/' && chPrev == '*' && ( + (i > startSeg + 3) || ((initStyle == SCE_C_COMMENTDOC) && (startSeg == startPos)))) { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_C_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_STRING) { + if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRINGEOL; + startSeg = i; + } else if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_C_CHARACTER) { + if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRINGEOL; + startSeg = i; + } else if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } + if (state == SCE_C_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_C_COMMENTDOC; + else + state = SCE_C_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } else if (ch == '\'') { + state = SCE_C_CHARACTER; + } else if (ch == '#') { + state = SCE_C_PREPROCESSOR; + } else if (iswordstart(ch)) { + state = SCE_C_WORD; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + if ((ch == '{') || (ch == '}')) { + levelCurrent += (ch == '{') ? 1 : -1; + } + } + } + } + chPrev = ch; + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc - 1, state); + // Fill in the real level of the next line, keeping the current flags as they will be filled in later + if (fold) { + int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; + //styler.SetLevel(lineCurrent, levelCurrent | flagsNext); + styler.SetLevel(lineCurrent, levelPrev | flagsNext); + + } +} + +inline bool isPerlOperator(char ch) { + if (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 == '.' || ch == '~') + return true; + return false; +} + +static int classifyWordPerl(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_PL_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_PL_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_PL_WORD; + } + styler.ColourSegment(start, end, chAttr); + return chAttr; +} + +static bool isEndVar(char ch) { + return !isalnum(ch) && ch != '#' && ch != '$' && + ch != '_' && ch != '\''; +} + +static bool isMatch(StylingContext &styler, int lengthDoc, int pos, const char *val) { + if ((pos + static_cast(strlen(val))) >= lengthDoc) { + return false; + } + while (*val) { + if (*val != styler[pos++]) { + return false; + } + val++; + } + return true; +} + +static bool isOKQuote(char ch) { + if (isalnum(ch)) + return false; + if (isspace(ch)) + return false; + if (iscntrl(ch)) + return false; + return true; +} + +static char opposite(char ch) { + if (ch == '(') + return ')'; + if (ch == '[') + return ']'; + if (ch == '{') + return '}'; + if (ch == '<') + return '>'; + return ch; +} + +static void ColourisePerlDoc(int codePage, int startPos, int length, int initStyle, + WordList &keywords, StylingContext &styler) { + char sooked[100]; + int quotes = 0; + char quoteDown = 'd'; + char quoteUp = 'd'; + int quoteRep = 1; + int sookedpos = 0; + bool preferRE = true; + sooked[sookedpos] = '\0'; + int state = initStyle; + int lengthDoc = startPos + length; + // If in a long distance lexical state, seek to the beginning to find quote characters + if (state == SCE_PL_HERE || state == SCE_PL_REGEX || + state == SCE_PL_REGSUBST || state == SCE_PL_LONGQUOTE) { + while ((startPos > 1) && (styler.StyleAt(startPos - 1) == state)) { + startPos--; + } + state = SCE_PL_DEFAULT; + } + styler.StartAt(startPos); + char chPrev = ' '; + char chNext = styler[startPos]; + int startSeg = startPos; + for (int i = startPos; i <= lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + char chNext2 = styler.SafeGetCharAt(i + 2); + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_PL_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + if (ch == 's' && !isalnum(chNext)) { + state = SCE_PL_REGSUBST; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 2; + startSeg = i; + } else if (ch == 'm' && !isalnum(chNext)) { + state = SCE_PL_REGEX; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 1; + startSeg = i; + } else if (ch == 't' && chNext == 'r' && !isalnum(chNext2)) { + state = SCE_PL_REGSUBST; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 2; + startSeg = i; + i++; + chNext = chNext2; + } else if (ch == 'q' && (chNext == 'q' || chNext == 'r' || chNext == 'w' || chNext == 'x') && !isalnum(chNext2)) { + state = SCE_PL_LONGQUOTE; + startSeg = i; + i++; + chNext = chNext2; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 1; + } else { + state = SCE_PL_WORD; + startSeg = i; + preferRE = false; + } + } else if (ch == '#') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_STRING; + startSeg = i; + } else if (ch == '\'') { + if (chPrev == '&') { + // Archaic call + styler.ColourSegment(i, i, state); + startSeg = i + 1; + } else { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_CHARACTER; + startSeg = i; + } + } else if (ch == '`') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_BACKTICKS; + startSeg = i; + } else if (ch == '$') { + preferRE = false; + styler.ColourSegment(startSeg, i - 1, state); + if (isalnum(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { + state = SCE_PL_SCALAR; + startSeg = i; + } else if (chNext != '{' && chNext != '[') { + styler.ColourSegment(i - 1, i, SCE_PL_SCALAR); + i++; + startSeg = i + 1; + ch = ' '; + chNext = ' '; + } else { + styler.ColourSegment(i, i, SCE_PL_SCALAR); + startSeg = i + 1; + } + } else if (ch == '@') { + preferRE = false; + styler.ColourSegment(startSeg, i - 1, state); + if (isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { + state = SCE_PL_ARRAY; + startSeg = i; + } else if (chNext != '{' && chNext != '[') { + styler.ColourSegment(i - 1, i, SCE_PL_ARRAY); + i++; + startSeg = i + 1; + ch = ' '; + } else { + styler.ColourSegment(i, i, SCE_PL_ARRAY); + startSeg = i + 1; + } + } else if (ch == '%') { + preferRE = false; + styler.ColourSegment(startSeg, i - 1, state); + if (isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { + state = SCE_PL_HASH; + startSeg = i; + } else if (chNext != '{' && chNext != '[') { + styler.ColourSegment(i - 1, i, SCE_PL_HASH); + i++; + startSeg = i + 1; + ch = ' '; + } else { + styler.ColourSegment(i, i, SCE_PL_HASH); + startSeg = i + 1; + } + } else if (ch == '*') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_SYMBOLTABLE; + startSeg = i; + } else if (ch == '/' && preferRE) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_REGEX; + quoteUp = '/'; + quoteDown = '/'; + quotes = 1; + quoteRep = 1; + startSeg = i; + } else if (ch == '<' && chNext == '<') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_HERE; + startSeg = i; + i++; + ch = chNext; + chNext = chNext2; + quotes = 0; + sookedpos = 0; + sooked[sookedpos] = '\0'; + } else if (ch == '=' && isalpha(chNext)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_POD; + startSeg = i; + quotes = 0; + sookedpos = 0; + sooked[sookedpos] = '\0'; + } else if (isPerlOperator(ch)) { + if (ch == ')' || ch == ']') + preferRE = false; + else + preferRE = true; + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_PL_OPERATOR); + startSeg = i + 1; + } + } else if (state == SCE_PL_WORD) { + if (!iswordchar(ch) && ch != '\'') { // Archaic Perl has quotes inside names + if (isMatch(styler, lengthDoc, startSeg, "__DATA__")) { + styler.ColourSegment(startSeg, i, SCE_PL_DATASECTION); + state = SCE_PL_DATASECTION; + } else if (isMatch(styler, lengthDoc, startSeg, "__END__")) { + styler.ColourSegment(startSeg, i, SCE_PL_DATASECTION); + state = SCE_PL_DATASECTION; + } else { + if (classifyWordPerl(startSeg, i - 1, keywords, styler) == SCE_PL_WORD) + preferRE = true; + state = SCE_PL_DEFAULT; + startSeg = i; + if (ch == '#') { + state = SCE_PL_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_PL_STRING; + } else if (ch == '\'') { + state = SCE_PL_CHARACTER; + } else if (ch == '<' && chNext == '<') { + state = SCE_PL_HERE; + quotes = 0; + startSeg = i; + sookedpos = 0; + sooked[sookedpos] = '\0'; + } else if (isPerlOperator(ch)) { + if (ch == ')' || ch == ']') + preferRE = false; + else + preferRE = true; + styler.ColourSegment(startSeg, i, SCE_PL_OPERATOR); + state = SCE_PL_DEFAULT; + startSeg = i + 1; + } + } + } + } else { + if (state == SCE_PL_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_DEFAULT; + startSeg = i; + } + } else if (state == SCE_PL_HERE) { + if (isalnum(ch) && quotes < 2) { + sooked[sookedpos++] = ch; + sooked[sookedpos] = '\0'; + if (quotes == 0) + quotes = 1; + } else { + quotes++; + } + + if (quotes > 1 && isMatch(styler, lengthDoc, i, sooked)) { + styler.ColourSegment(startSeg, i + sookedpos - 1, SCE_PL_HERE); + state = SCE_PL_DEFAULT; + i += sookedpos; + startSeg = i; + chNext = ' '; + } + } else if (state == SCE_PL_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_PL_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_PL_CHARACTER) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_PL_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_PL_BACKTICKS) { + if (ch == '`') { + styler.ColourSegment(startSeg, i, state); + state = SCE_PL_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_PL_POD) { + if (ch == '=') { + if (isMatch(styler, lengthDoc, i, "=cut")) { + styler.ColourSegment(startSeg, i - 1 + 4, state); + i += 4; + startSeg = i; + state = SCE_PL_DEFAULT; + chNext = ' '; + ch = ' '; + } + } + } else if (state == SCE_PL_SCALAR) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_ARRAY) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_HASH) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_SYMBOLTABLE) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_REF) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_REGEX) { + if (!quoteUp && !isspace(ch)) { + quoteUp = ch; + quoteDown = opposite(ch); + quotes++; + } else { + if (ch == quoteDown && chPrev != '\\') { + quotes--; + if (quotes == 0) { + quoteRep--; + if (quoteUp == quoteDown) { + quotes++; + } + } + if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + } else if (ch == quoteUp && chPrev != '\\') { + quotes++; + } else if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + } + } else if (state == SCE_PL_REGSUBST) { + if (!quoteUp && !isspace(ch)) { + quoteUp = ch; + quoteDown = opposite(ch); + quotes++; + } else { + if (ch == quoteDown && chPrev != '\\') { + quotes--; + if (quotes == 0) { + quoteRep--; + } + if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + if (quoteUp == quoteDown) { + quotes++; + } + } else if (ch == quoteUp && chPrev != '\\') { + quotes++; + } else if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + } + } else if (state == SCE_PL_LONGQUOTE) { + if (!quoteDown && !isspace(ch)) { + quoteUp = ch; + quoteDown = opposite(quoteUp); + quotes++; + } else if (ch == quoteDown) { + quotes--; + if (quotes == 0) { + quoteRep--; + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + if (quoteUp == quoteDown) { + quotes++; + } + } + } else if (ch == quoteUp) { + quotes++; + } + } + + if (state == SCE_PL_DEFAULT) { // One of the above succeeded + if (ch == '#') { + state = SCE_PL_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_PL_STRING; + } else if (ch == '\'') { + state = SCE_PL_CHARACTER; + } else if (iswordstart(ch)) { + state = SCE_PL_WORD; + preferRE = false; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_PL_OPERATOR); + startSeg = i + 1; + } + } + } + chPrev = ch; + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc, state); +} + + +static int classifyWordVB(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } + char chAttr = SCE_C_DEFAULT; + if (wordIsNumber) + chAttr = SCE_C_NUMBER; + else { + if (keywords.InList(s)) { + chAttr = SCE_C_WORD; + if (strcmp(s, "rem") == 0) + chAttr = SCE_C_COMMENTLINE; + } + } + styler.ColourSegment(start, end, chAttr); + if (chAttr == SCE_C_COMMENTLINE) + return SCE_C_COMMENTLINE; + else + return SCE_C_DEFAULT; +} + +static void ColouriseVBDoc(int codePage, int startPos, int length, int initStyle, + WordList &keywords, StylingContext &styler) { + int state = initStyle; + char chNext = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + for (int i = startPos; i < lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + i += 1; + continue; + } + + if (state == SCE_C_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_WORD; + startSeg = i; + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRING; + startSeg = i; + } + } else if (state == SCE_C_WORD) { + if (!iswordchar(ch)) { + state = classifyWordVB(startSeg, i - 1, keywords, styler); + if (state == SCE_C_DEFAULT) { + startSeg = i; + if (ch == '\'') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } + } + } + } else { + if (state == SCE_C_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_STRING) { + // VB doubles quotes to preserve them + if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } + if (state == SCE_C_DEFAULT) { // One of the above succeeded + if (ch == '\'') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } else if (iswordstart(ch)) { + state = SCE_C_WORD; + } + } + } + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc, state); +} + +static void classifyWordPy(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler, char *prevWord) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_P_IDENTIFIER; + if (0 == strcmp(prevWord, "class")) + chAttr = SCE_P_CLASSNAME; + else if (0 == strcmp(prevWord, "def")) + chAttr = SCE_P_DEFNAME; + else if (wordIsNumber) + chAttr = SCE_P_NUMBER; + else if (keywords.InList(s)) + chAttr = SCE_P_WORD; + styler.ColourSegment(start, end, chAttr); + strcpy(prevWord, s); +} + +static void ColourisePyDoc(int codePage, int startPos, int length, int initStyle, WordList &keywords, StylingContext &styler) { + //Platform::DebugPrintf("Python coloured\n"); + bool fold = styler.GetPropSet().GetInt("fold"); + int whingeLevel = styler.GetPropSet().GetInt("tab.timmy.whinge.level"); + char prevWord[200]; + prevWord[0] = '\0'; + if (length == 0) + return ; + int lineCurrent = styler.GetLine(startPos); + int spaceFlags = 0; + // TODO: Need to check previous line for indentation for both folding and bad indentation + int indentCurrent = IndentAmount(styler, lineCurrent, &spaceFlags); + + int state = initStyle & 31; + char chPrev = ' '; + char chPrev2 = ' '; + char chNext = styler[startPos]; + char chNext2 = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + bool atStartLine = true; + for (int i = startPos; i <= lengthDoc; i++) { + + if (atStartLine) { + if (whingeLevel == 1) { + styler.SetFlags((spaceFlags & wsInconsistent) ? 64 : 0, state); + } else if (whingeLevel == 2) { + styler.SetFlags((spaceFlags & wsSpaceTab) ? 64 : 0, state); + } else if (whingeLevel == 3) { + styler.SetFlags((spaceFlags & wsSpace) ? 64 : 0, state); + } else if (whingeLevel == 4) { + styler.SetFlags((spaceFlags & wsTab) ? 64 : 0, state); + } + atStartLine = false; + } + + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + chNext2 = styler.SafeGetCharAt(i + 2); + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + if ((state == SCE_P_DEFAULT) || (state == SCE_P_TRIPLE) || (state == SCE_P_TRIPLEDOUBLE)) { + // Perform colourisation of white space and triple quoted strings at end of each line to allow + // tab marking to work inside white space and triple quoted strings + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + } + + int lev = indentCurrent; + int indentNext = IndentAmount(styler, lineCurrent + 1, &spaceFlags); + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { + // Only non whitespace lines can be headers + if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + } + indentCurrent = indentNext; + if (fold) { + styler.SetLevel(lineCurrent, lev); + } + lineCurrent++; + atStartLine = true; + } + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + chPrev2 = ' '; + i += 1; + continue; + } + + if (state == SCE_P_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_P_WORD; + startSeg = i; + } else if (ch == '#') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_P_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_P_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_STRING; + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_P_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_P_OPERATOR); + startSeg = i + 1; + } + } else if (state == SCE_P_WORD) { + if (!iswordchar(ch)) { + classifyWordPy(startSeg, i - 1, keywords, styler, prevWord); + state = SCE_P_DEFAULT; + startSeg = i; + if (ch == '#') { + state = SCE_P_COMMENTLINE; + } else if (ch == '\"') { + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_P_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_STRING; + } + } else if (ch == '\'') { + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_P_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_P_OPERATOR); + startSeg = i + 1; + } + } + } else { + if (state == SCE_P_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_P_DEFAULT; + startSeg = i; + } + } else if (state == SCE_P_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_P_CHARACTER) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_P_TRIPLE) { + if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_P_TRIPLEDOUBLE) { + if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } + } + chPrev2 = chPrev; + chPrev = ch; + } + if (startSeg <= lengthDoc) { + if (state == SCE_P_DEFAULT) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_WORD) { + classifyWordPy(startSeg, lengthDoc, keywords, styler, prevWord); + } else if (state == SCE_P_COMMENTLINE) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_STRING) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_CHARACTER) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_TRIPLE) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_TRIPLEDOUBLE) { + styler.ColourSegment(startSeg, lengthDoc, state); + } + } +} + +static void ColouriseBatchLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + if (0 == strncmp(lineBuffer, "REM", 3)) { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (0 == strncmp(lineBuffer, "rem", 3)) { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (0 == strncmp(lineBuffer, "SET", 3)) { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if (0 == strncmp(lineBuffer, "set", 3)) { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if (lineBuffer[0] == ':') { + styler.ColourSegment(0, lengthLine - 1, 3); + } else { + styler.ColourSegment(0, lengthLine - 1, 0); + } +} + +static void ColouriseBatchDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i < startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + ColouriseBatchLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColouriseBatchLine(lineBuffer, linePos, styler); +} + +enum { eScriptNone, eScriptJS, eScriptVBS, eScriptPython }; +static int segIsScriptingIndicator(StylingContext &styler, unsigned int start, unsigned int end, int prevValue) { + char s[100]; + s[0] = '\0'; + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } +Platform::DebugPrintf("Scripting indicator [%s]\n", s); + if (strstr(s, "vbs")) + return eScriptVBS; + if (strstr(s, "pyth")) + return eScriptPython; + if (strstr(s, "javas")) + return eScriptJS; + if (strstr(s, "jscr")) + return eScriptJS; + + return prevValue; +} + +static void classifyAttribHTML(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.') || + (styler[start] == '-') || (styler[start] == '#'); + char chAttr = SCE_H_ATTRIBUTEUNKNOWN; + if (wordIsNumber) { + chAttr = SCE_H_NUMBER; + } else { + char s[100]; + s[0] = '\0'; + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } + if (keywords.InList(s)) + chAttr = SCE_H_ATTRIBUTE; + } + styler.ColourTo(end, chAttr); +} + +static int classifyTagHTML(unsigned int start, unsigned int end, + WordList &keywords, StylingContext &styler) { + char s[100]; + // Copy after the '<' + unsigned int i = 0; + for (int cPos=start; cPos <= end && i < 30; cPos++) { + char ch = styler[cPos]; + if (ch != '<') + s[i++] = tolower(ch); + } + s[i] = '\0'; + char chAttr = SCE_H_TAGUNKNOWN; + if (s[0] == '!' && s[1] == '-' && s[2] == '-') { //Comment + chAttr = SCE_H_COMMENT; + } else if (s[0] == '/') { // Closing tag + if (keywords.InList(s + 1)) + chAttr = SCE_H_TAG; + } else { + if (keywords.InList(s)) { + chAttr = SCE_H_TAG; + if (0 == strcmp(s, "script")) + chAttr = SCE_H_SCRIPT; + } + } + styler.ColourTo(end, chAttr); + return chAttr; +} + +static void classifyWordHTJS(unsigned int start, unsigned int end, + WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_HJ_WORD; + if (wordIsNumber) + chAttr = SCE_HJ_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_HJ_KEYWORD; + } + styler.ColourTo(end, chAttr); +} + +static int classifyWordHTVB(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } + char chAttr = SCE_HB_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_HB_NUMBER; + else { + if (keywords.InList(s)) { + chAttr = SCE_HB_WORD; + if (strcmp(s, "rem") == 0) + chAttr = SCE_HB_COMMENTLINE; + } + } + styler.ColourTo(end, chAttr); + if (chAttr == SCE_HB_COMMENTLINE) + return SCE_HB_COMMENTLINE; + else + return SCE_HB_DEFAULT; +} + +static void classifyWordHTPy(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler, char *prevWord) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_HP_IDENTIFIER; + if (0 == strcmp(prevWord, "class")) + chAttr = SCE_HP_CLASSNAME; + else if (0 == strcmp(prevWord, "def")) + chAttr = SCE_HP_DEFNAME; + else if (wordIsNumber) + chAttr = SCE_HP_NUMBER; + else if (keywords.InList(s)) + chAttr = SCE_HP_WORD; + styler.ColourTo(end, chAttr); + strcpy(prevWord, s); +} + +inline bool ishtmlwordchar(char ch) { + return isalnum(ch) || ch == '.' || ch == '-' || ch == '_' || ch == ':' || ch == '!' || ch == '#'; +} + +static bool InTagState(int state) { + return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN || + state == SCE_H_SCRIPT || + state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN || + state == SCE_H_NUMBER || state == SCE_H_OTHER || + state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING; +} + +static bool isLineEnd(char ch) { + return ch == '\r' || ch == '\n'; +} + +static void ColouriseHyperTextDoc(int codePage, int startPos, int length, + int initStyle, WordList &keywords, WordList &keywords2, WordList &keywords3, WordList &keywords4, + StylingContext &styler) { + + styler.StartAt(startPos, 63); + bool lastTagWasScript = false; + char prevWord[200]; + prevWord[0] = '\0'; + int scriptLanguage = eScriptJS; + int state = initStyle; + // If inside a tag, it may be a script tage, so reread from the start to ensure any language tas are seen + if (InTagState(state)) { + while ((startPos > 1) && (InTagState(styler.StyleAt(startPos - 1)))) { + startPos--; + } + state = SCE_H_DEFAULT; + } + styler.StartAt(startPos, 63); + + int lineState = eScriptVBS; + int lineCurrent = styler.GetLine(startPos); + if (lineCurrent > 0) + lineState = styler.GetLineState(lineCurrent); + int defaultScript = lineState &0xff; + int beforeASP = (lineState >> 8) &0xff; + int inASP = (lineState >> 16) &0xff; + + char chPrev = ' '; + char chPrev2 = ' '; + styler.StartSegment(startPos); + int lengthDoc = startPos + length; + for (int i = startPos; i <= lengthDoc; i++) { + char ch = styler[i]; + char chNext = styler.SafeGetCharAt(i + 1); + char chNext2 = styler.SafeGetCharAt(i + 2); + + if (IsLeadByte(codePage, ch)) { // dbcs + chPrev2 = ' '; + chPrev = ' '; + i += 1; + continue; + } + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + // New line -> record any line state onto /next/ line + lineCurrent++; + styler.SetLineState(lineCurrent, + defaultScript | (beforeASP << 8) | (inASP << 16)); + } + + // Handle ASP even within other constructs as it is a preprocessor + if ((ch == '<') && (chNext == '%')) { + beforeASP = state; + styler.ColourTo(i - 1, state); + if (chNext2 == '@') { + styler.ColourTo(i + 2, SCE_H_ASP); + state = SCE_H_ASPAT; + i+=2; + } else { + if (defaultScript == eScriptVBS) + state = SCE_HB_START; + else if (defaultScript == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + if (chNext2 == '=') { + styler.ColourTo(i + 2, SCE_H_ASP); + i+=2; + } else { + styler.ColourTo(i + 1, SCE_H_ASP); + i++; + } + } + inASP = 1; + continue; + } + if (inASP && (ch == '%') && (chNext == '>')) { + if (state == SCE_H_ASPAT) + defaultScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i-1, defaultScript); + // Bounce out of any ASP mode + styler.ColourTo(i - 1, state); + //if (state == SCE_H_ASPAT) + // styler.ColourTo(i+1, SCE_H_ASPAT); + //else + styler.ColourTo(i+1, SCE_H_ASP); + i++; + state = beforeASP; + beforeASP = SCE_H_DEFAULT; + inASP = 0; + continue; + } + + if (state == SCE_H_DEFAULT) { + if (ch == '<') { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + if (chNext == '?') { + styler.ColourTo(i + 1, SCE_H_XMLSTART); + i++; + ch = chNext; + } + } else if (ch == '&') { + styler.ColourTo(i - 1, SCE_H_DEFAULT); + state = SCE_H_ENTITY; + } + } else if (state == SCE_H_COMMENT) { + if ((ch == '>') && (chPrev == '-')) { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_ENTITY) { + if (ch == ';') { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_TAGUNKNOWN) { + if (!ishtmlwordchar(ch) && ch != '/' && ch != '-') { + int eClass = classifyTagHTML(styler.GetStartSegment(), i - 1, keywords, styler); + lastTagWasScript = eClass == SCE_H_SCRIPT; + if (lastTagWasScript) { + scriptLanguage = eScriptJS; + eClass = SCE_H_TAG; + } + if (ch == '>') { + styler.ColourTo(i, SCE_H_TAG); + if (lastTagWasScript) { + if (scriptLanguage == eScriptVBS) + state = SCE_HB_START; + else if (scriptLanguage == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + } else { + state = SCE_H_DEFAULT; + } + } else { + if (eClass == SCE_H_COMMENT) { + state = SCE_H_COMMENT; + } else { + state = SCE_H_OTHER; + } + } + } + } else if (state == SCE_H_ATTRIBUTE) { + if (!ishtmlwordchar(ch) && ch != '/' && ch != '-') { + if (lastTagWasScript) + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i-1, scriptLanguage); + classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler); + if (ch == '>') { + styler.ColourTo(i, SCE_H_TAG); + if (lastTagWasScript) { + if (scriptLanguage == eScriptVBS) + state = SCE_HB_START; + else if (scriptLanguage == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + } else { + state = SCE_H_DEFAULT; + } + } else { + state = SCE_H_OTHER; + } + } + } else if (state == SCE_H_ASP) { + if ((ch == '>') && (chPrev == '%')) { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_ASPAT) { + if ((ch == '>') && (chPrev == '%')) { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_OTHER) { + if (ch == '>') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_H_TAG); + if (lastTagWasScript) { + if (scriptLanguage == eScriptVBS) + state = SCE_HB_START; + else if (scriptLanguage == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + } else { + state = SCE_H_DEFAULT; + } + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + state = SCE_H_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + state = SCE_H_SINGLESTRING; + } else if (ch == '/' && chNext == '>') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } else if (ch == '?' && chNext == '>') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_XMLEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } else if (ishtmlwordchar(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_H_ATTRIBUTE; + } + } else if (state == SCE_H_DOUBLESTRING) { + if (ch == '\"') { + if (lastTagWasScript) + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); + styler.ColourTo(i, SCE_H_DOUBLESTRING); + state = SCE_H_OTHER; + } + } else if (state == SCE_H_SINGLESTRING) { + if (ch == '\'') { + if (lastTagWasScript) + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); + styler.ColourTo(i, SCE_H_SINGLESTRING); + state = SCE_H_OTHER; + } + } else if (state == SCE_HJ_DEFAULT || state == SCE_HJ_START) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HJ_WORD; + } else if (ch == '/' && chNext == '*') { + styler.ColourTo(i - 1, state); + if (chNext2 == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_SINGLESTRING; + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_COMMENTLINE; + } else if (isoperator(ch)) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_HJ_SYMBOLS); + state = SCE_HJ_DEFAULT; + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HJ_START) { + styler.ColourTo(i - 1, state); + state = SCE_HJ_DEFAULT; + } + } + } else if (state == SCE_HJ_WORD) { + if (!iswordchar(ch)) { + classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler); + //styler.ColourTo(i - 1, eHTJSKeyword); + state = SCE_HJ_DEFAULT; + if (ch == '/' && chNext == '*') { + if (chNext2 == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + state = SCE_HJ_SINGLESTRING; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HJ_SYMBOLS); + state = SCE_HJ_DEFAULT; + } + } + } else if (state == SCE_HJ_COMMENT) { + if (ch == '/' && chPrev == '*') { + state = SCE_HJ_DEFAULT; + styler.ColourTo(i, SCE_HJ_COMMENT); + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } + } else if (state == SCE_HJ_COMMENTDOC) { + if (ch == '/' && chPrev == '*') { + state = SCE_HJ_DEFAULT; + styler.ColourTo(i, SCE_HJ_COMMENTDOC); + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } + } else if (state == SCE_HJ_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, SCE_HJ_COMMENTLINE); + state = SCE_HJ_DEFAULT; + } else if ((ch == '<') && (chNext == '/')) { + // Common to hide end script tag in comment + styler.ColourTo(i - 1, SCE_HJ_COMMENTLINE); + state = SCE_H_TAGUNKNOWN; + } + } else if (state == SCE_HJ_DOUBLESTRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + } + } else if (ch == '\"') { + styler.ColourTo(i, SCE_HJ_DOUBLESTRING); + state = SCE_HJ_DEFAULT; + i++; + ch = chNext; + } else if (isLineEnd(ch)) { + styler.ColourTo(i-1, state); + state = SCE_HJ_STRINGEOL; + } + } else if (state == SCE_HJ_SINGLESTRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + } + } else if (ch == '\'') { + styler.ColourTo(i, SCE_HJ_SINGLESTRING); + state = SCE_HJ_DEFAULT; + i++; + ch = chNext; + } else if (isLineEnd(ch)) { + styler.ColourTo(i-1, state); + state = SCE_HJ_STRINGEOL; + } + } else if (state == SCE_HJ_STRINGEOL) { + if (!isLineEnd(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HJ_DEFAULT; + } + } else if (state == SCE_HB_DEFAULT || state == SCE_HB_START) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HB_WORD; + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + state = SCE_HB_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + state = SCE_HB_STRING; + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, state); + state = SCE_HB_COMMENTLINE; + } else if (isoperator(ch)) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_HB_DEFAULT); + state = SCE_HB_DEFAULT; + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HB_START) { + styler.ColourTo(i - 1, state); + state = SCE_HB_DEFAULT; + } + } + } else if (state == SCE_HB_WORD) { + if (!iswordchar(ch)) { + state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler); + if (state == SCE_HB_DEFAULT) { + if (ch == '\"') { + state = SCE_HB_STRING; + } else if (ch == '\'') { + state = SCE_HB_COMMENTLINE; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HB_DEFAULT); + state = SCE_HB_DEFAULT; + } + } + } + } else if (state == SCE_HB_STRING) { + if (ch == '\"') { + styler.ColourTo(i, state); + state = SCE_HB_DEFAULT; + i++; + ch = chNext; + } else if (ch == '\r' || ch == '\n') { + styler.ColourTo(i-1, state); + state = SCE_HB_STRINGEOL; + } + } else if (state == SCE_HB_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, state); + state = SCE_HB_DEFAULT; + } else if ((ch == '<') && (chNext == '/')) { + // Common to hide end script tag in comment + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } + } else if (state == SCE_HB_STRINGEOL) { + if (!isLineEnd(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HB_DEFAULT; + } + } else if (state == SCE_HP_DEFAULT || state == SCE_HP_START) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HP_WORD; + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, state); + state = SCE_HP_COMMENTLINE; + } else if (ch == '#') { + styler.ColourTo(i - 1, state); + state = SCE_HP_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_HP_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_STRING; + } + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_HP_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_HP_OPERATOR); + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HP_START) { + styler.ColourTo(i - 1, state); + state = SCE_HP_DEFAULT; + } + } + } else if (state == SCE_HP_WORD) { + if (!iswordchar(ch)) { + classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord); + state = SCE_HP_DEFAULT; + if (ch == '#') { + state = SCE_HP_COMMENTLINE; + } else if (ch == '\"') { + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_HP_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_STRING; + } + } else if (ch == '\'') { + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_HP_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HP_OPERATOR); + } + } + } else { + if (state == SCE_HP_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_CHARACTER) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_TRIPLE) { + if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_TRIPLEDOUBLE) { + if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } + } + if (state == SCE_HB_DEFAULT) { // One of the above succeeded + if (ch == '\"') { + state = SCE_HB_STRING; + } else if (ch == '\'') { + state = SCE_HB_COMMENTLINE; + } else if (iswordstart(ch)) { + state = SCE_HB_WORD; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HB_DEFAULT); + } + } + if (state == SCE_HJ_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + state = SCE_HJ_SINGLESTRING; + } else if (iswordstart(ch)) { + state = SCE_HJ_WORD; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HJ_SYMBOLS); + } + } + chPrev2 = chPrev; + chPrev = ch; + } + styler.ColourTo(lengthDoc - 1, state); +} + +static void ColourisePropsLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + int i = 0; + while (isspace(lineBuffer[i]) && (i < lengthLine)) // Skip initial spaces + i++; + if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (lineBuffer[i] == '[') { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if (lineBuffer[i] == '@') { + styler.ColourSegment(0, i, 4); + if (lineBuffer[++i] == '=') + styler.ColourSegment(i, i, 3); + if (++i < lengthLine) + styler.ColourSegment(i, lengthLine - 1, 0); + } else { + while (lineBuffer[i] != '=' && (i < lengthLine)) // Search the '=' character + i++; + if (lineBuffer[i] == '=') { + styler.ColourSegment(0, i - 1, 0); + styler.ColourSegment(i, i, 3); + if (++i < lengthLine) + styler.ColourSegment(i, lengthLine - 1, 0); + } else + styler.ColourSegment(0, lengthLine - 1, 0); + } +} + +static void ColourisePropsDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i <= startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + lineBuffer[linePos] = '\0'; + ColourisePropsLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColourisePropsLine(lineBuffer, linePos, styler); +} + +static void ColouriseMakeLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + int i = 0; + while (isspace(lineBuffer[i]) && (i < lengthLine)) + i++; + if (lineBuffer[i] == '#' || lineBuffer[i] == '!') { + styler.ColourSegment(0, lengthLine - 1, 1); + } else { + styler.ColourSegment(0, lengthLine - 1, 0); + } +} + +static void ColouriseMakeDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i <= startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + ColouriseMakeLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColouriseMakeLine(lineBuffer, linePos, styler); +} + +static void ColouriseErrorListLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + if (lineBuffer[0] == '>') { + // Command or return status + styler.ColourSegment(0, lengthLine - 1, 4); + } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (0 == strncmp(lineBuffer, "Error ", strlen("Error "))) { + // Borland error message + styler.ColourSegment(0, lengthLine - 1, 5); + } else if (0 == strncmp(lineBuffer, "Warning ", strlen("Warning "))) { + // Borland warning message + styler.ColourSegment(0, lengthLine - 1, 5); + } else { + // Look for ::message + // Look for (line)message + // Look for (line,pos)message + int state = 0; + for (int i = 0; i < lengthLine; i++) { + if (state == 0 && lineBuffer[i] == ':' && isdigit(lineBuffer[i + 1])) { + state = 1; + } else if (state == 0 && lineBuffer[i] == '(') { + state = 10; + } else if (state == 1 && isdigit(lineBuffer[i])) { + state = 2; + } else if (state == 2 && lineBuffer[i] == ':') { + state = 3; + break; + } else if (state == 2 && !isdigit(lineBuffer[i])) { + state = 99; + } else if (state == 10 && isdigit(lineBuffer[i])) { + state = 11; + } else if (state == 11 && lineBuffer[i] == ',') { + state = 14; + } else if (state == 11 && lineBuffer[i] == ')') { + state = 12; + break; + } else if (state == 12 && lineBuffer[i] == ':') { + state = 13; + } else if (state == 14 && lineBuffer[i] == ')') { + state = 15; + break; + } else if (((state == 11) || (state == 14)) && !((lineBuffer[i] == ' ') || isdigit(lineBuffer[i]))) { + state = 99; + } + } + if (state == 3) { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if ((state == 14) || (state == 15)) { + styler.ColourSegment(0, lengthLine - 1, 3); + } else { + styler.ColourSegment(0, lengthLine - 1, 0); + } + } +} + +static void ColouriseErrorListDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i <= startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + ColouriseErrorListLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColouriseErrorListLine(lineBuffer, linePos, styler); +} + +static void classifyWordSQL(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = toupper(styler[start + i]); + s[i + 1] = '\0'; + } + char chAttr = SCE_C_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_C_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_C_WORD; + } + styler.ColourSegment(start, end, chAttr); +} + +static void ColouriseSQLDoc(int codePage, int startPos, int length, + int initStyle, WordList &keywords, StylingContext &styler) { + + bool fold = styler.GetPropSet().GetInt("fold"); + int lineCurrent = styler.GetLine(startPos); + int spaceFlags = 0; + int indentCurrent = 0; + + int state = initStyle; + char chPrev = ' '; + char chNext = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + bool prevCr = false; + for (int i = startPos; i <= lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + indentCurrent = IndentAmount(styler, lineCurrent, &spaceFlags); + int lev = indentCurrent; + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { + // Only non whitespace lines can be headers + int indentNext = IndentAmount(styler, lineCurrent + 1, &spaceFlags); + if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + } + if (fold) { + styler.SetLevel(lineCurrent, lev); + } + } + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_C_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_WORD; + startSeg = i; + } else if (ch == '/' && chNext == '*') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENT; + startSeg = i; + } else if (ch == '-' && chNext == '-') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENTLINE; + startSeg = i; + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRING; + startSeg = i; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_C_OPERATOR); + startSeg = i + 1; + } + } else if (state == SCE_C_WORD) { + if (!iswordchar(ch)) { + classifyWordSQL(startSeg, i - 1, keywords, styler); + state = SCE_C_DEFAULT; + startSeg = i; + if (ch == '/' && chNext == '*') { + state = SCE_C_COMMENT; + } else if (ch == '-' && chNext == '-') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\'') { + state = SCE_C_STRING; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + } + } + } else { + if (state == SCE_C_COMMENT) { + if (ch == '/' && chPrev == '*' && ( + (i > startSeg + 2) || ((initStyle == SCE_C_COMMENT) && (startSeg == startPos)))) { + state = SCE_C_DEFAULT; + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + } + } else if (state == SCE_C_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_STRING) { + if (ch == '\'') { + if ( chNext == '\'' ) { + i++; + } else { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + startSeg = i; + } + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } + if (state == SCE_C_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + state = SCE_C_COMMENT; + } else if (ch == '-' && chNext == '-') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\'') { + state = SCE_C_STRING; + } else if (iswordstart(ch)) { + state = SCE_C_WORD; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + } + } + } + chPrev = ch; + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc - 1, state); +} + +void ColouriseDoc(int codePage, int startPos, int lengthDoc, int initStyle, + int language, WordList *keywordlists[], StylingContext &styler) { + //Platform::DebugPrintf("ColouriseDoc <%s>\n", language); + if (language == SCLEX_PYTHON) { + // Python uses a different mask because bad indentation is marked by oring with 32 + styler.StartAt(startPos, 127); + ColourisePyDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_PERL) { + // Lexer for perl often has to backtrack to start of current style to determine + // which characters are being used as quotes, how deeply nested is the + // start position and what the termination string is for here documents + ColourisePerlDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if ((language == SCLEX_HTML) || (language == SCLEX_XML)) { + // Lexer for HTML requires more lexical states (6 bits worth) than most lexers + ColouriseHyperTextDoc(codePage, startPos, lengthDoc, initStyle, + *keywordlists[0], *keywordlists[1], *keywordlists[2], *keywordlists[3], styler); + } else { + styler.StartAt(startPos); + if (language == SCLEX_CPP) { + ColouriseCppDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_SQL) { + ColouriseSQLDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_VB) { + ColouriseVBDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_PROPERTIES) { + ColourisePropsDoc(startPos, lengthDoc, initStyle, styler); + } else if (language == SCLEX_ERRORLIST) { + ColouriseErrorListDoc(startPos, lengthDoc, initStyle, styler); + } else if (language == SCLEX_MAKEFILE) { + ColouriseMakeDoc(startPos, lengthDoc, initStyle, styler); + } else if (language == SCLEX_BATCH) { + ColouriseBatchDoc(startPos, lengthDoc, initStyle, styler); + } else { + // Null language means all style bytes are 0 so just mark the end - no need to fill in. + styler.StartAt(startPos + lengthDoc - 1); + styler.ColourSegment(0, 0, 0); + } + } +} diff --git a/contrib/src/stc/scintilla/src/LineMarker.cxx b/contrib/src/stc/scintilla/src/LineMarker.cxx new file mode 100644 index 0000000000..9afccb8227 --- /dev/null +++ b/contrib/src/stc/scintilla/src/LineMarker.cxx @@ -0,0 +1,125 @@ +// Scintilla source code edit control +// LineMarker.cxx - defines the look of a line marker in the margin +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include "Platform.h" + +#include "Scintilla.h" +#include "LineMarker.h" + +void LineMarker::Draw(Surface *surface, PRectangle &rc) { + 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; + 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) { + int armSize = dimOn2-2; + Point xpts[] = { + Point(centreX - armSize, centreY), + Point(centreX, centreY), + Point(centreX, centreY - armSize), + Point(centreX, centreY - armSize), + Point(centreX, centreY), + Point(centreX + armSize, centreY), + Point(centreX + armSize, centreY), + Point(centreX, centreY), + Point(centreX, centreY + armSize), + Point(centreX, centreY + armSize), + Point(centreX, centreY), + Point(centreX - armSize, centreY), + }; + 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) { + int armSize = dimOn2-2; + Point pts[] = { + Point(centreX - armSize, centreY - 1), + Point(centreX + armSize, centreY -1), + Point(centreX + armSize, centreY +1), + Point(centreX - armSize, centreY + 1), + }; + Point xpts[] = { + Point(centreX - armSize, centreY), + Point(centreX + armSize, centreY), + Point(centreX + armSize, centreY), + Point(centreX - armSize, centreY), + }; + 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) { + // An invisible marker so don't draw anything + } else { // 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); + } +} diff --git a/contrib/src/stc/scintilla/src/LineMarker.h b/contrib/src/stc/scintilla/src/LineMarker.h new file mode 100644 index 0000000000..f22241bb19 --- /dev/null +++ b/contrib/src/stc/scintilla/src/LineMarker.h @@ -0,0 +1,22 @@ +// Scintilla source code edit control +// LineMarker.h - defines the look of a line marker in the margin +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef LINEMARKER_H +#define LINEMARKER_H + +class LineMarker { +public: + int markType; + ColourPair fore; + ColourPair back; + LineMarker() { + markType = SC_MARK_CIRCLE; + fore = Colour(0,0,0); + back = Colour(0xff,0xff,0xff); + } + void Draw(Surface *surface, PRectangle &rc); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/PropSet.cxx b/contrib/src/stc/scintilla/src/PropSet.cxx new file mode 100644 index 0000000000..7e2a906a47 --- /dev/null +++ b/contrib/src/stc/scintilla/src/PropSet.cxx @@ -0,0 +1,399 @@ +// SciTE - Scintilla based Text Editor +// PropSet.cxx - a java style properties file module +// Copyright 1998-2000 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 + +#include "Platform.h" + +#include "PropSet.h" + +bool EqualCaseInsensitive(const char *a, const char *b) { +#if PLAT_GTK + return 0 == strcasecmp(a, b); +#elif PLAT_WIN + return 0 == stricmp(a, b); +#elif PLAT_WX + return 0 == wxStricmp(a, b); +#endif +} + +// Get a line of input. If end of line escaped with '\\' then continue reading. +static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) { + bool continuation = true; + while ((len > 1) && lenData > 0) { + char ch = *fpc; + fpc++; + lenData--; + if ((ch == '\r') || (ch == '\n')) { + if (!continuation) { + if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) { + // munch the second half of a crlf + fpc++; + lenData--; + } + *s++ = '\0'; + return true; + } + } else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) { + continuation = true; + } else { + continuation = false; + *s++ = ch; + len--; + } + } + return false; +} + +PropSet::PropSet() { + superPS = 0; + size = 10; + used = 0; + vals = new char * [size]; +} + +PropSet::~PropSet() { + superPS = 0; + Clear(); + delete []vals; +} + +void PropSet::EnsureCanAddEntry() { + if (used >= size - 2) { + int newsize = size + 10; + char **newvals = new char * [newsize]; + + for (int i = 0; i < used; i++) { + newvals[i] = vals[i]; + } + delete []vals; + vals = newvals; + size = newsize; + } +} + +void PropSet::Set(const char *key, const char *val) { + EnsureCanAddEntry(); + for (int i = 0; i < used; i += 2) { + if (EqualCaseInsensitive(vals[i], key)) { + // Replace current value + delete [](vals[i + 1]); + vals[i + 1] = StringDup(val); + return; + } + } + // Not found + vals[used++] = StringDup(key); + vals[used++] = StringDup(val); +} + +void PropSet::Set(char *keyval) { + char *eqat = strchr(keyval, '='); + if (eqat) { + *eqat = '\0'; + Set(keyval, eqat + 1); + *eqat = '='; + } +} + +SString PropSet::Get(const char *key) { + for (int i = 0; i < used; i += 2) { + if (EqualCaseInsensitive(vals[i], key)) { + return vals[i + 1]; + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->Get(key); + } else { + return ""; + } +} + +int PropSet::GetInt(const char *key, int defaultValue) { + SString val = Get(key); + if (val.length()) + return Get(key).value(); + else + return defaultValue; +} + +bool isprefix(const char *target, const char *prefix) { + while (*target && *prefix) { + if (toupper(*target) != toupper(*prefix)) + return false; + target++; + prefix++; + } + if (*prefix) + return false; + else + return true; +} + +bool issuffix(const char *target, const char *suffix) { + int lentarget = strlen(target); + int lensuffix = strlen(suffix); + if (lensuffix > lentarget) + return false; + for (int i = lensuffix - 1; i >= 0; i--) { + if (toupper(target[i + lentarget - lensuffix]) != toupper(suffix[i])) + return false; + } + return true; +} + +SString PropSet::GetWild(const char *keybase, const char *filename) { + for (int i = 0; i < used; i += 2) { + if (isprefix(vals[i], keybase)) { + char *orgkeyfile = vals[i] + strlen(keybase); + char *keyfile = NULL; + + if (strstr(orgkeyfile, "$(") == orgkeyfile) { + char *cpendvar = strchr(orgkeyfile, ')'); + if (cpendvar) { + int lenvar = cpendvar - orgkeyfile - 2; // Subtract the $() + char *var = static_cast(malloc(lenvar + 1)); + strncpy(var, orgkeyfile + 2, lenvar); + var[lenvar] = '\0'; + SString s = Get(var); + free(var); + keyfile = strdup(s.c_str()); + } + } + char *keyptr = keyfile; + + if (keyfile == NULL) + keyfile = orgkeyfile; + + for (; ; ) { + char *del = strchr(keyfile, ';'); + if (del == NULL) + del = keyfile + strlen(keyfile); + char delchr = *del; + *del = '\0'; + if (*keyfile == '*') { + if (issuffix(filename, keyfile + 1)) { + *del = delchr; + free(keyptr); + return vals[i + 1]; + } + } else if (EqualCaseInsensitive(keyfile, filename)) { + *del = delchr; + free(keyptr); + return vals[i + 1]; + } + if (delchr == '\0') + break; + *del = delchr; + keyfile = del + 1; + } + free(keyptr); + + if (EqualCaseInsensitive(vals[i], keybase)) { + return vals[i + 1]; + } + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->GetWild(keybase, filename); + } else { + return ""; + } +} + +SString PropSet::GetNewExpand(const char *keybase, const char *filename) { + char *base = StringDup(GetWild(keybase, filename).c_str()); + char *cpvar = strstr(base, "$("); + while (cpvar) { + char *cpendvar = strchr(cpvar, ')'); + if (cpendvar) { + int lenvar = cpendvar - cpvar - 2; // Subtract the $() + char *var = new char[lenvar + 1]; + strncpy(var, cpvar + 2, lenvar); + var[lenvar] = '\0'; + SString val = GetWild(var, filename); + int newlenbase = strlen(base) + val.length() - lenvar; + char *newbase = new char[newlenbase]; + strncpy(newbase, base, cpvar - base); + strcpy(newbase + (cpvar - base), val.c_str()); + strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1); + delete []var; + delete []base; + base = newbase; + } + cpvar = strstr(base, "$("); + } + SString sret = base; + delete []base; + return sret; +} + +void PropSet::Clear() { + for (int i = 0; i < used; i++) { + delete [](vals[i]); + vals[i] = 0; + } + used = 0; +} + +void PropSet::ReadFromMemory(const char *data, int len) { + if (len > 0) { + const char *pd = data; + char linebuf[60000]; + while (GetFullLine(pd, len, linebuf, sizeof(linebuf))) { + if (isalpha(linebuf[0])) + Set(linebuf); + } + } +} + +void PropSet::Read(const char *filename) { + //printf("Opening properties <%s>\n", filename); + Clear(); + char propsData[60000]; + FILE *rcfile = fopen(filename, "rb"); + if (rcfile) { + int lenFile = fread(propsData, 1, sizeof(propsData), rcfile); + fclose(rcfile); + ReadFromMemory(propsData, lenFile); + } else { + //printf("Could not open <%s>\n", filename); + } +} + +static bool iswordsep(char ch, bool onlyLineEnds) { + if (!isspace(ch)) + return false; + if (!onlyLineEnds) + return true; + return ch == '\r' || ch == '\n'; +} + +// Creates an array that points into each word in the string and puts \0 terminators +// after each word. +static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) { + char prev = '\n'; + int words = 0; + for (int j = 0; wordlist[j]; j++) { + if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds)) + words++; + prev = wordlist[j]; + } + char **keywords = new char * [words + 1]; + if (keywords) { + words = 0; + prev = '\0'; + int len = strlen(wordlist); + for (int k = 0; k < len; k++) { + if (!iswordsep(wordlist[k], onlyLineEnds)) { + if (!prev) { + keywords[words] = &wordlist[k]; + words++; + } + } else { + wordlist[k] = '\0'; + } + prev = wordlist[k]; + } + keywords[words] = &wordlist[len]; + } + return keywords; +} + +void WordList::Clear() { + if (words) { + delete []words; + delete []list; + } + words = 0; + list = 0; + len = 0; +} + +void WordList::Set(const char *s) { + len = 0; + list = StringDup(s); + words = ArrayFromWordList(list, onlyLineEnds); +} + +char *WordList::Allocate(int size) { + list = new char[size + 1]; + list[size] = '\0'; + return list; +} + +void WordList::SetFromAllocated() { + len = 0; + words = ArrayFromWordList(list, onlyLineEnds); +} + +// Shell sort based upon public domain C implementation by Raymond Gardner 1991 +// Used here because of problems with mingw qsort. +static void SortWordList(char **words, unsigned int len) { + unsigned int gap = len / 2; + + while (gap > 0) { + unsigned int i = gap; + while (i < len) { + unsigned int j = i; + char **a = words + j; + do { + j -= gap; + char **b = a; + a -= gap; + if (strcmp(*a, *b) > 0) { + char *tmp = *a; + *a = *b; + *b = tmp; + } else { + break; + } + } while (j >= gap); + i++; + } + gap = gap / 2; + } +} + +bool WordList::InList(const char *s) { + if (0 == words) + return false; + if (len == 0) { + for (int i = 0; words[i][0]; i++) + len++; + SortWordList(words, len); + for (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) { + 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++; + } + } + return false; +} diff --git a/contrib/src/stc/scintilla/src/SVector.h b/contrib/src/stc/scintilla/src/SVector.h new file mode 100644 index 0000000000..7bc948738a --- /dev/null +++ b/contrib/src/stc/scintilla/src/SVector.h @@ -0,0 +1,110 @@ +// Scintilla source code edit control +// SVector.h - a simple expandable vector +// Copyright 1998-1999 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SVECTOR_H +#define SVECTOR_H + +// A simple expandable vector. +// T must support assignment. +// 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. +template +class SVector { + T *v; + unsigned int size; // Number of elements allocated + unsigned int len; // Number of elements in vector + bool allocFailure; // A memory allocation call has failed + + // Internally allocate more elements than the user wants to avoid + // thrashng the memory allocator + void SizeTo(int newSize) { + if (newSize < sizeIncrement) + newSize += sizeIncrement; + else + newSize = (newSize * 3) / 2; + T* newv = new T[newSize]; + if (!newv) { + allocFailure = true; + return; + } + size = newSize; + for (int i=0; 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]; + } + void Free() { + delete []v; + v = 0; + size = 0; + len = 0; + } + void SetLength(int newLen) { + if (newLength > len) { + if (newLength >= size) { + SizeTo(newLength); + } + } + len = newLen; + } + int Length() const { + return len; + } +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/ScintillaBase.cxx b/contrib/src/stc/scintilla/src/ScintillaBase.cxx new file mode 100644 index 0000000000..eb68904b79 --- /dev/null +++ b/contrib/src/stc/scintilla/src/ScintillaBase.cxx @@ -0,0 +1,399 @@ +// Scintilla source code edit control +// ScintillaBase.cxx - an enhanced subclass of Editor with calltips, autocomplete and context menu +// Copyright 1998-2000 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" +#ifdef SCI_LEXER +#include "SciLexer.h" +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#endif +#include "ContractionState.h" +#include "SVector.h" +#include "CellBuffer.h" +#include "CallTip.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "AutoComplete.h" +#include "Document.h" +#include "Editor.h" +#include "ScintillaBase.h" + +ScintillaBase::ScintillaBase() { +#ifdef SCI_LEXER + lexLanguage = SCLEX_CONTAINER; + for (int wl=0;wl= rcClient.right - widthLB) { + HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB); + Redraw(); + pt = LocationFromPosition(currentPos); + } + PRectangle rcac; + rcac.left = pt.x - 5; + if (pt.y >= rcClient.bottom - heightLB && // Wont fit below. + pt.y >= (rcClient.bottom + rcClient.top) / 2) { // and there is more room above. + rcac.top = pt.y - heightLB; + if (rcac.top < 0) { + heightLB += rcac.top; + rcac.top = 0; + } + } else { + rcac.top = pt.y + vs.lineHeight; + } + rcac.right = rcac.left + widthLB; + rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcClient.bottom); + ac.lb.SetPositionRelative(rcac, wMain); + ac.lb.SetFont(vs.styles[0].font); + + int maxStrLen = 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.GetPosition(); + int heightAlloced = rcList.bottom - rcList.top; + // Make an allowance for large strings in list + rcList.left = pt.x - 5; + rcList.right = rcList.left + Platform::Maximum(widthLB, maxStrLen * 8 + 16); + if (pt.y >= rcClient.bottom - heightLB && // Wont fit below. + pt.y >= (rcClient.bottom + rcClient.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); + //lbAutoComplete.SetPosition(rcList); + ac.Show(); +} + +void ScintillaBase::AutoCompleteCancel() { + ac.Cancel(); +} + +void ScintillaBase::AutoCompleteMove(int delta) { + ac.Move(delta); +} + +void ScintillaBase::AutoCompleteChanged(char ch) { + if (currentPos <= ac.posStart) { + ac.Cancel(); + } else if (ac.IsStopChar(ch)) { + ac.Cancel(); + } else { + char wordCurrent[1000]; + int i; + int startWord = ac.posStart - ac.startLen; + for (i = startWord; i < currentPos; i++) + wordCurrent[i - startWord] = pdoc->CharAt(i); + wordCurrent[i - startWord] = '\0'; + ac.Select(wordCurrent); + } +} + +void ScintillaBase::AutoCompleteCompleted() { + int item = ac.lb.GetSelection(); + char selected[200]; + if (item != -1) { + ac.lb.GetValue(item, selected, sizeof(selected)); + } + ac.Cancel(); + if (currentPos != ac.posStart) { + pdoc->DeleteChars(ac.posStart, currentPos - ac.posStart); + } + SetEmptySelection(ac.posStart); + if (item != -1) { + pdoc->InsertString(currentPos, selected + ac.startLen); + SetEmptySelection(currentPos + strlen(selected + ac.startLen)); + } +} + +void ScintillaBase::ContextMenu(Point pt) { + popup.CreatePopUp(); + AddToPopUp("Undo", idcmdUndo, pdoc->CanUndo()); + AddToPopUp("Redo", idcmdRedo, pdoc->CanRedo()); + AddToPopUp(""); + AddToPopUp("Cut", idcmdCut, currentPos != anchor); + AddToPopUp("Copy", idcmdCopy, currentPos != anchor); + AddToPopUp("Paste", idcmdPaste, WndProc(EM_CANPASTE, 0, 0)); + AddToPopUp("Delete", idcmdDelete, currentPos != anchor); + AddToPopUp(""); + AddToPopUp("Select All", idcmdSelectAll); + popup.Show(pt, wMain); +} + +void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + AutoCompleteCancel(); + ct.CallTipCancel(); + Editor::ButtonDown(pt, curTime, shift, ctrl, alt); +} + +#ifdef SCI_LEXER +void ScintillaBase::Colourise(int start, int end) { + int lengthDoc = Platform::SendScintilla(wMain.GetID(), SCI_GETLENGTH, 0, 0); + if (end == -1) + end = lengthDoc; + int len = end - start; + + PropSet props; + + StylingContext styler(wMain.GetID(), props); + + int styleStart = 0; + if (start > 0) + styleStart = styler.StyleAt(start - 1); + + ColouriseDoc(pdoc->dbcsCodePage, start, len, styleStart, lexLanguage, keyWordLists, styler); + styler.Flush(); +} +#endif + +void ScintillaBase::NotifyStyleNeeded(int endStyleNeeded) { +#ifdef SCI_LEXER + if (lexLanguage != SCLEX_CONTAINER) { + int endStyled = Platform::SendScintilla(wMain.GetID(), SCI_GETENDSTYLED, 0, 0); + int lineEndStyled = Platform::SendScintilla(wMain.GetID(), EM_LINEFROMCHAR, endStyled, 0); + endStyled = Platform::SendScintilla(wMain.GetID(), EM_LINEINDEX, lineEndStyled, 0); + Colourise(endStyled, endStyleNeeded); + return; + } +#endif + Editor::NotifyStyleNeeded(endStyleNeeded); +} + +LRESULT ScintillaBase::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { + switch (iMessage) { + case SCI_AUTOCSHOW: + AutoCompleteStart(wParam, reinterpret_cast(lParam)); + break; + + case SCI_AUTOCCANCEL: + AutoCompleteCancel(); + break; + + case SCI_AUTOCACTIVE: + return ac.Active(); + + case SCI_AUTOCPOSSTART: + return ac.posStart; + + case SCI_AUTOCCOMPLETE: + AutoCompleteCompleted(); + break; + + case SCI_AUTOCSTOPS: + ac.SetStopChars(reinterpret_cast(lParam)); + break; + + case SCI_CALLTIPSHOW: { + AutoCompleteCancel(); + if (!ct.wCallTip.Created()) { + PRectangle rc = ct.CallTipStart(currentPos, LocationFromPosition(wParam), + reinterpret_cast(lParam), + vs.styles[0].fontName, vs.styles[0].size); + // 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, wDraw); + ct.wCallTip.Show(); + } + } + 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 = Colour(wParam); + InvalidateStyleRedraw(); + break; + +#ifdef SCI_LEXER + case SCI_SETLEXER: + lexLanguage = wParam; + break; + + case SCI_GETLEXER: + return lexLanguage; + + case SCI_COLOURISE: + Colourise(wParam, lParam); + break; + + case SCI_SETPROPERTY: + props.Set(reinterpret_cast(wParam), + reinterpret_cast(lParam)); + break; + + case SCI_SETKEYWORDS: + if ((wParam >= 0) && (wParam < numWordLists)) { + keyWordLists[wParam]->Clear(); + keyWordLists[wParam]->Set(reinterpret_cast(lParam)); + } + break; +#endif + + default: + return Editor::WndProc(iMessage, wParam, lParam); + } + return 0l; +} diff --git a/contrib/src/stc/scintilla/src/ScintillaBase.h b/contrib/src/stc/scintilla/src/ScintillaBase.h new file mode 100644 index 0000000000..e9f8f28d03 --- /dev/null +++ b/contrib/src/stc/scintilla/src/ScintillaBase.h @@ -0,0 +1,68 @@ +// Scintilla source code edit control +// ScintillaBase.h - defines an enhanced subclass of Editor with calltips, autocomplete and context menu +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCINTILLABASE_H +#define SCINTILLABASE_H + +class ScintillaBase : public Editor { +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 + }; + + Menu popup; + AutoComplete ac; + + CallTip ct; + +#ifdef SCI_LEXER + int lexLanguage; + PropSet props; + enum {numWordLists=5}; + WordList *keyWordLists[numWordLists]; + 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 AddChar(char ch); + void Command(int cmdId); + virtual int KeyCommand(UINT iMessage); + + void AutoCompleteStart(int lenEntered, const char *list); + void AutoCompleteCancel(); + void AutoCompleteMove(int delta); + void AutoCompleteChanged(char ch=0); + void AutoCompleteCompleted(); + + 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 NotifyStyleNeeded(int endStyleNeeded); +public: + // Public so scintilla_send_message can use it + virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/Style.cxx b/contrib/src/stc/scintilla/src/Style.cxx new file mode 100644 index 0000000000..56312314ff --- /dev/null +++ b/contrib/src/stc/scintilla/src/Style.cxx @@ -0,0 +1,63 @@ +// Scintilla source code edit control +// Style.cxx - defines the font and colour style for a class of text +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "Style.h" + +Style::Style() { + Clear(); +} + +Style::~Style() { + font.Release(); +} + +Style &Style::operator=(const Style &source) { + if (this == &source) + return *this; + Clear(); + fore.desired = source.fore.desired; + back.desired = source.back.desired; + bold = source.bold; + italic = source.italic; + size = source.size; + strcpy(fontName, source.fontName); + eolFilled = source.eolFilled; + return *this; +} + +void Style::Clear(Colour fore_, Colour back_, int size_, const char *fontName_, + bool bold_, bool italic_, bool eolFilled_) { + fore.desired = fore_; + back.desired = back_; + bold = bold_; + italic = italic_; + size = size_; + strcpy(fontName, fontName_); + eolFilled = eolFilled_; + font.Release(); +} + +void Style::Realise(Surface &surface, int zoomLevel) { + int sizeZoomed = size + zoomLevel; + if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2; + + int deviceHeight = (sizeZoomed * surface.LogPixelsY()) / 72; + font.Create(fontName, deviceHeight, bold, italic); + + 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/contrib/src/stc/scintilla/src/Style.h b/contrib/src/stc/scintilla/src/Style.h new file mode 100644 index 0000000000..916b646315 --- /dev/null +++ b/contrib/src/stc/scintilla/src/Style.h @@ -0,0 +1,37 @@ +// Scintilla source code edit control +// Style.h - defines the font and colour style for a class of text +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef STYLE_H +#define STYLE_H + +class Style { +public: + ColourPair fore; + ColourPair back; + bool bold; + bool italic; + int size; + char fontName[100]; + bool eolFilled; + + Font font; + unsigned int lineHeight; + unsigned int ascent; + unsigned int descent; + unsigned int externalLeading; + unsigned int aveCharWidth; + unsigned int spaceWidth; + + Style(); + ~Style(); + Style &operator=(const Style &source); + void Clear(Colour fore_=Colour(0,0,0), Colour back_=Colour(0xff,0xff,0xff), + int size_=Platform::DefaultFontSize(), + const char *fontName_=Platform::DefaultFont(), + bool bold_=false, bool italic_=false, bool eolFilled_=false); + void Realise(Surface &surface, int zoomLevel); +}; + +#endif diff --git a/contrib/src/stc/scintilla/src/ViewStyle.cxx b/contrib/src/stc/scintilla/src/ViewStyle.cxx new file mode 100644 index 0000000000..001ecdb319 --- /dev/null +++ b/contrib/src/stc/scintilla/src/ViewStyle.cxx @@ -0,0 +1,183 @@ +// Scintilla source code edit control +// ViewStyle.cxx - store information on how the document is to be viewed +// Copyright 1998-2000 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 "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" + +MarginStyle::MarginStyle() : + symbol(false), width(16), mask(0xffffffff), sensitive(false) { +} + +ViewStyle::ViewStyle() { + Init(); +} + +ViewStyle::ViewStyle(const ViewStyle &source) { + Init(); + for (int sty=0;sty<=STYLE_MAX;sty++) { + styles[sty] = source.styles[sty]; + } + for (int mrk=0;mrk<=MARKER_MAX;mrk++) { + markers[mrk] = source.markers[mrk]; + } + for (int ind=0;ind<=INDIC_MAX;ind++) { + indicators[ind] = source.indicators[ind]; + } + + selforeset = source.selforeset; + selforeground.desired = source.selforeground.desired; + selbackset = source.selbackset; + selbackground.desired = source.selbackground.desired; + selbar.desired = source.selbar.desired; + selbarlight.desired = source.selbarlight.desired; + caretcolour.desired = source.caretcolour.desired; + edgecolour.desired = source.edgecolour.desired; + leftMarginWidth = source.leftMarginWidth; + rightMarginWidth = source.rightMarginWidth; + for (int i=0;i < margins; i++) { + ms[i] = source.ms[i]; + } + symbolMargin = source.symbolMargin; + maskInLine = source.maskInLine; + fixedColumnWidth = source.fixedColumnWidth; + zoomLevel = source.zoomLevel; + viewWhitespace = source.viewWhitespace; + viewEOL = source.viewEOL; + showMarkedLines = source.showMarkedLines; +} + +ViewStyle::~ViewStyle() { +} + +void ViewStyle::Init() { + indicators[0].style = INDIC_SQUIGGLE; + indicators[0].fore = Colour(0, 0x7f, 0); + indicators[1].style = INDIC_TT; + indicators[1].fore = Colour(0, 0, 0xff); + indicators[2].style = INDIC_PLAIN; + indicators[2].fore = Colour(0xff, 0, 0); + + lineHeight = 1; + maxAscent = 1; + maxDescent = 1; + aveCharWidth = 8; + spaceWidth = 8; + + selforeset = false; + selforeground.desired = Colour(0xff, 0, 0); + selbackset = true; + selbackground.desired = Colour(0xc0, 0xc0, 0xc0); + selbar.desired = Platform::Chrome(); + selbarlight.desired = Platform::ChromeHighlight(); + styles[STYLE_LINENUMBER].fore.desired = Colour(0, 0, 0); + styles[STYLE_LINENUMBER].back.desired = Platform::Chrome(); + //caretcolour.desired = Colour(0xff, 0, 0); + caretcolour.desired = Colour(0, 0, 0); + edgecolour.desired = Colour(0xc0, 0xc0, 0xc0); + + leftMarginWidth = 1; + rightMarginWidth = 1; + ms[0].symbol = false; + ms[0].width = 0; + ms[0].mask = 0; + ms[1].symbol = true; + ms[1].width = 16; + ms[1].mask = ~SC_MASK_FOLDERS; + ms[2].symbol = true; + ms[2].width = 14; // Nice width for arrows + ms[2].mask = SC_MASK_FOLDERS; + ms[2].width = 0; // Nice width for arrows + ms[2].mask = 0; + fixedColumnWidth = leftMarginWidth; + symbolMargin = false; + maskInLine = 0xffffffff; + for (int margin=0; margin < margins; margin++) { + fixedColumnWidth += ms[margin].width; + symbolMargin = symbolMargin || ms[margin].symbol; + if (ms[margin].width > 0) + maskInLine &= ~ms[margin].mask; + } + zoomLevel = 0; + viewWhitespace = false; + viewEOL = false; + showMarkedLines = true; +} + +void ViewStyle::RefreshColourPalette(Palette &pal, bool want) { + unsigned int i; + for (i=0;i<(sizeof(styles)/sizeof(styles[0]));i++) { + pal.WantFind(styles[i].fore, want); + pal.WantFind(styles[i].back, want); + } + for (i=0;i<(sizeof(indicators)/sizeof(indicators[0]));i++) { + pal.WantFind(indicators[i].fore, want); + } + for (i=0;i<(sizeof(markers)/sizeof(markers[0]));i++) { + pal.WantFind(markers[i].fore, want); + pal.WantFind(markers[i].back, want); + } + pal.WantFind(selforeground, want); + pal.WantFind(selbackground, want); + pal.WantFind(selbar, want); + pal.WantFind(selbarlight, want); + pal.WantFind(caretcolour, want); + pal.WantFind(edgecolour, want); +} + +void ViewStyle::Refresh(Surface &surface) { + selbar.desired = Platform::Chrome(); + selbarlight.desired = Platform::ChromeHighlight(); + maxAscent = 1; + maxDescent = 1; + for (unsigned int i=0;i<(sizeof(styles)/sizeof(styles[0]));i++) { + styles[i].Realise(surface, zoomLevel); + if (maxAscent < styles[i].ascent) + maxAscent = styles[i].ascent; + if (maxDescent < styles[i].descent) + maxDescent = styles[i].descent; + } + + lineHeight = maxAscent + maxDescent; + aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth; + spaceWidth = styles[STYLE_DEFAULT].spaceWidth; + + fixedColumnWidth = leftMarginWidth; + symbolMargin = false; + maskInLine = 0xffffffff; + for (int margin=0; margin < margins; margin++) { + fixedColumnWidth += ms[margin].width; + symbolMargin = symbolMargin || ms[margin].symbol; + if (ms[margin].width > 0) + maskInLine &= ~ms[margin].mask; + } +} + +void ViewStyle::ResetDefaultStyle() { + styles[STYLE_DEFAULT].Clear(); +} + +void ViewStyle::ClearStyles() { + // Reset all styles to be like the default style + for (int i=0; i<=STYLE_MAX; i++) { + if (i != STYLE_DEFAULT) { + styles[i].Clear( + styles[STYLE_DEFAULT].fore.desired, + styles[STYLE_DEFAULT].back.desired, + styles[STYLE_DEFAULT].size, + styles[STYLE_DEFAULT].fontName, + styles[STYLE_DEFAULT].bold, + styles[STYLE_DEFAULT].italic); + } + } + styles[STYLE_LINENUMBER].back.desired = Platform::Chrome(); +} + diff --git a/contrib/src/stc/scintilla/src/ViewStyle.h b/contrib/src/stc/scintilla/src/ViewStyle.h new file mode 100644 index 0000000000..944872095a --- /dev/null +++ b/contrib/src/stc/scintilla/src/ViewStyle.h @@ -0,0 +1,59 @@ +// Scintilla source code edit control +// ViewStyle.h - store information on how the document is to be viewed +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef VIEWSTYLE_H +#define VIEWSTYLE_H + +class MarginStyle { +public: + bool symbol; + int width; + int mask; + bool sensitive; + MarginStyle(); +}; + +class ViewStyle { +public: + Style styles[STYLE_MAX + 1]; + 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 selbar; + ColourPair selbarlight; + // Margins are ordered: Line Numbers, Selection Margin, Spacing Margin + int leftMarginWidth; // Spacing margin on left of text + int rightMarginWidth; // Spacing margin on left of text + enum { margins=3 }; + 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; + bool viewWhitespace; + bool viewEOL; + bool showMarkedLines; + ColourPair caretcolour; + ColourPair edgecolour; + + ViewStyle(); + ViewStyle(const ViewStyle &source); + ~ViewStyle(); + void Init(); + void RefreshColourPalette(Palette &pal, bool want); + void Refresh(Surface &surface); + void ResetDefaultStyle(); + void ClearStyles(); +}; + +#endif diff --git a/contrib/src/stc/stc.cpp b/contrib/src/stc/stc.cpp new file mode 100644 index 0000000000..d4b02e8e6d --- /dev/null +++ b/contrib/src/stc/stc.cpp @@ -0,0 +1,1386 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: stc.cpp +// Purpose: A wxWindows implementation of Scintilla. This class is the +// one meant to be used directly by wx applications. It does not +// derive directly from the Scintilla classes, but instead +// delegates most things to the real Scintilla class. +// This allows the use of Scintilla without polluting the +// namespace with all the classes and itentifiers from Scintilla. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#include "wx/stc/stc.h" +#include "ScintillaWX.h" + +#include + +//---------------------------------------------------------------------- + +const wxChar* wxSTCNameStr = "stcwindow"; + +BEGIN_EVENT_TABLE(wxStyledTextCtrl, wxControl) + EVT_PAINT (wxStyledTextCtrl::OnPaint) + EVT_SCROLLWIN (wxStyledTextCtrl::OnScrollWin) + EVT_SIZE (wxStyledTextCtrl::OnSize) + EVT_LEFT_DOWN (wxStyledTextCtrl::OnMouseLeftDown) + EVT_MOTION (wxStyledTextCtrl::OnMouseMove) + EVT_LEFT_UP (wxStyledTextCtrl::OnMouseLeftUp) + EVT_RIGHT_UP (wxStyledTextCtrl::OnMouseRightUp) + EVT_CHAR (wxStyledTextCtrl::OnChar) + EVT_KILL_FOCUS (wxStyledTextCtrl::OnLoseFocus) + EVT_SET_FOCUS (wxStyledTextCtrl::OnGainFocus) + EVT_SYS_COLOUR_CHANGED (wxStyledTextCtrl::OnSysColourChanged) + EVT_ERASE_BACKGROUND (wxStyledTextCtrl::OnEraseBackground) + EVT_MENU_RANGE (-1, -1, wxStyledTextCtrl::OnMenu) +END_EVENT_TABLE() + +//---------------------------------------------------------------------- +// Constructor and Destructor + +wxStyledTextCtrl::wxStyledTextCtrl(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) : + wxControl(parent, id, pos, size, + style | wxVSCROLL | wxHSCROLL | wxWANTS_CHARS, + wxDefaultValidator, name) +{ + m_swx = new ScintillaWX(this); + // m_keywords = new WordList; + m_stopWatch.Start(); + m_readOnly = false; + m_undoType = wxSTC_UndoCollectAutoStart; +} + + +wxStyledTextCtrl::~wxStyledTextCtrl() { + delete m_swx; + // delete m_keywords; +} + + +//---------------------------------------------------------------------- + +inline long wxStyledTextCtrl::SendMsg(int msg, long wp, long lp) { + + return m_swx->WndProc(msg, wp, lp); +} + + +//---------------------------------------------------------------------- +// Text retrieval and modification + +wxString wxStyledTextCtrl::GetText() { + wxString text; + int len = GetTextLength(); + char* buff = text.GetWriteBuf(len); + + SendMsg(WM_GETTEXT, len, (long)buff); + text.UngetWriteBuf(); + return text; +} + + +bool wxStyledTextCtrl::SetText(const wxString& text) { + return SendMsg(WM_SETTEXT, 0, (long)text.c_str()) != 0; +} + + +wxString wxStyledTextCtrl::GetLine(int line) { + wxString text; + int len = GetLineLength(line); + char* buff = text.GetWriteBuf(len+1); + + *((WORD*)buff) = len+1; + SendMsg(EM_GETLINE, line, (long)buff); + text.UngetWriteBuf(); + return text; +} + + +void wxStyledTextCtrl::ReplaceSelection(const wxString& text) { + SendMsg(EM_REPLACESEL, 0, (long)text.c_str()); +} + + +void wxStyledTextCtrl::SetReadOnly(bool readOnly) { + SendMsg(EM_SETREADONLY, (long)readOnly); + m_readOnly = readOnly; +} + + +bool wxStyledTextCtrl::GetReadOnly() { + // TODO: need support in Scintilla to do this right, + // until then we'll track it ourselves + return m_readOnly; +} + + +void wxStyledTextCtrl::GetTextRange(int startPos, int endPos, char* buff) { + TEXTRANGE tr; + tr.lpstrText = buff; + tr.chrg.cpMin = startPos; + tr.chrg.cpMax = endPos; + SendMsg(EM_GETTEXTRANGE, 0, (long)&tr); +} + + +wxString wxStyledTextCtrl::GetTextRange(int startPos, int endPos) { + wxString text; + int len = endPos - startPos; + char* buff = text.GetWriteBuf(len); + GetTextRange(startPos, endPos, buff); + text.UngetWriteBuf(); + return text; +} + + +void wxStyledTextCtrl::GetStyledTextRange(int startPos, int endPos, char* buff) { + TEXTRANGE tr; + tr.lpstrText = buff; + tr.chrg.cpMin = startPos; + tr.chrg.cpMax = endPos; + SendMsg(SCI_GETSTYLEDTEXT, 0, (long)&tr); +} + + +wxString wxStyledTextCtrl::GetStyledTextRange(int startPos, int endPos) { + wxString text; + int len = endPos - startPos; + char* buff = text.GetWriteBuf(len*2); + GetStyledTextRange(startPos, endPos, buff); + text.UngetWriteBuf(len*2); + return text; +} + + +void wxStyledTextCtrl::AddText(const wxString& text) { + SendMsg(SCI_ADDTEXT, text.Len(), (long)text.c_str()); +} + + +void wxStyledTextCtrl::AddStyledText(const wxString& text) { + SendMsg(SCI_ADDSTYLEDTEXT, text.Len(), (long)text.c_str()); +} + + +void wxStyledTextCtrl::InsertText(int pos, const wxString& text) { + SendMsg(SCI_INSERTTEXT, pos, (long)text.c_str()); +} + + +void wxStyledTextCtrl::ClearAll() { + SendMsg(SCI_CLEARALL); +} + + +char wxStyledTextCtrl::GetCharAt(int pos) { + return SendMsg(SCI_GETCHARAT, pos); +} + + +char wxStyledTextCtrl::GetStyleAt(int pos) { + return SendMsg(SCI_GETSTYLEAT, pos); +} + + +void wxStyledTextCtrl::SetStyleBits(int bits) { + SendMsg(SCI_SETSTYLEBITS, bits); +} + + +int wxStyledTextCtrl::GetStyleBits() { + return SendMsg(SCI_GETSTYLEBITS); +} + + +//---------------------------------------------------------------------- +// Clipboard + + +void wxStyledTextCtrl::Cut() { + SendMsg(WM_CUT); +} + + +void wxStyledTextCtrl::Copy() { + SendMsg(WM_COPY); +} + + +void wxStyledTextCtrl::Paste() { + SendMsg(WM_PASTE); +} + + +bool wxStyledTextCtrl::CanPaste() { + return SendMsg(EM_CANPASTE) != 0; +} + + +void wxStyledTextCtrl::ClearClipbrd() { + SendMsg(WM_CLEAR); +} + + + +//---------------------------------------------------------------------- +// Undo and Redo + +void wxStyledTextCtrl::Undo() { + SendMsg(WM_UNDO); +} + + +bool wxStyledTextCtrl::CanUndo() { + return SendMsg(EM_CANUNDO) != 0; +} + + +void wxStyledTextCtrl::EmptyUndoBuffer() { + SendMsg(EM_EMPTYUNDOBUFFER); +} + + +void wxStyledTextCtrl::Redo() { + SendMsg(SCI_REDO); +} + + +bool wxStyledTextCtrl::CanRedo() { + return SendMsg(SCI_CANREDO) != 0; +} + + +void wxStyledTextCtrl::SetUndoCollection(wxSTC_UndoType type) { + SendMsg(SCI_SETUNDOCOLLECTION, type); + m_undoType = type; +} + + +wxSTC_UndoType wxStyledTextCtrl::GetUndoCollection() { + // TODO: need support in Scintilla to do this right, + // until then we'll track it ourselves + return m_undoType; +} + + +void wxStyledTextCtrl::BeginUndoAction() { + SendMsg(SCI_BEGINUNDOACTION); +} + + +void wxStyledTextCtrl::EndUndoAction() { + SendMsg(SCI_ENDUNDOACTION); +} + + + + +//---------------------------------------------------------------------- +// Selection and information + + +void wxStyledTextCtrl::GetSelection(int* startPos, int* endPos) { + SendMsg(EM_GETSEL, (long)startPos, (long)endPos); +} + + +void wxStyledTextCtrl::SetSelection(int startPos, int endPos) { + SendMsg(EM_SETSEL, startPos, endPos); +} + + +wxString wxStyledTextCtrl::GetSelectedText() { + wxString text; + int start; + int end; + + GetSelection(&start, &end); + int len = end - start; + char* buff = text.GetWriteBuf(len); + + SendMsg(EM_GETSELTEXT, 0, (long)buff); + text.UngetWriteBuf(); + return text; +} + + +void wxStyledTextCtrl::HideSelection(bool hide) { + SendMsg(EM_HIDESELECTION, hide); +} + + +bool wxStyledTextCtrl::GetHideSelection() { + return m_swx->GetHideSelection(); +} + + +int wxStyledTextCtrl::GetTextLength() { + return SendMsg(WM_GETTEXTLENGTH); +} + + +int wxStyledTextCtrl::GetFirstVisibleLine() { + return SendMsg(EM_GETFIRSTVISIBLELINE); +} + + +int wxStyledTextCtrl::GetLineCount() { + return SendMsg(EM_GETLINECOUNT); +} + + +bool wxStyledTextCtrl::GetModified() { + return SendMsg(EM_GETMODIFY) != 0; +} + + +wxRect wxStyledTextCtrl::GetRect() { + PRectangle pr; + SendMsg(EM_GETRECT, 0, (long)&pr); + + wxRect rect = wxRectFromPRectangle(pr); + return rect; +} + + +int wxStyledTextCtrl::GetLineFromPos(int pos) { + return SendMsg(EM_LINEFROMCHAR, pos); +} + + +int wxStyledTextCtrl::GetLineStartPos(int line) { + return SendMsg(EM_LINEINDEX, line); +} + + +int wxStyledTextCtrl::GetLineLengthAtPos(int pos) { + return SendMsg(EM_LINELENGTH, pos); +} + + +int wxStyledTextCtrl::GetLineLength(int line) { + return SendMsg(SCI_LINELENGTH, line); +} + + +int wxStyledTextCtrl::GetCurrentLine() { + int line = GetLineFromPos(GetCurrentPos()); + return line; +} + + +wxString wxStyledTextCtrl::GetCurrentLineText(int* linePos) { + wxString text; + int len = GetLineLength(GetCurrentLine()); + char* buff = text.GetWriteBuf(len+1); + + int pos = SendMsg(SCI_GETCURLINE, len+1, (long)buff); + text.UngetWriteBuf(); + + if (linePos) + *linePos = pos; + + return text; +} + + +int wxStyledTextCtrl::PositionFromPoint(wxPoint pt) { + Point spt(pt.x, pt.y); + long rv = SendMsg(EM_CHARFROMPOS, 0, (long)&spt); + return LOWORD(rv); +} + + +int wxStyledTextCtrl::LineFromPoint(wxPoint pt) { + Point spt(pt.x, pt.y); + long rv = SendMsg(EM_CHARFROMPOS, 0, (long)&spt); + return HIWORD(rv); +} + + +wxPoint wxStyledTextCtrl::PointFromPosition(int pos) { + Point pt; + SendMsg(EM_POSFROMCHAR, pos, (long)&pt); + return wxPoint(pt.x, pt.y); +} + + +int wxStyledTextCtrl::GetCurrentPos() { + return SendMsg(SCI_GETCURRENTPOS); +} + + +int wxStyledTextCtrl::GetAnchor() { + return SendMsg(SCI_GETANCHOR); +} + + +void wxStyledTextCtrl::SelectAll() { + SendMsg(SCI_SELECTALL); +} + + +void wxStyledTextCtrl::SetCurrentPosition(int pos) { + SendMsg(SCI_GOTOPOS, pos); +} + + +void wxStyledTextCtrl::SetAnchor(int pos) { + SendMsg(SCI_SETANCHOR, pos); +} + + +void wxStyledTextCtrl::GotoPos(int pos) { + SendMsg(SCI_GOTOPOS, pos); +} + + +void wxStyledTextCtrl::GotoLine(int line) { + SendMsg(SCI_GOTOLINE, line); +} + + +void wxStyledTextCtrl::ChangePosition(int delta, bool extendSelection) { + // TODO: Is documented but doesn't seem to be implemented + //SendMsg(SCI_CHANGEPOSITION, delta, extendSelection); +} + + +void wxStyledTextCtrl::PageMove(int cmdKey, bool extendSelection) { + // TODO: Is documented but doesn't seem to be implemented + //SendMsg(SCI_PAGEMOVE, cmdKey, extendSelection); +} + + +void wxStyledTextCtrl::ScrollBy(int columnDelta, int lineDelta) { + SendMsg(EM_LINESCROLL, columnDelta, lineDelta); +} + +void wxStyledTextCtrl::ScrollToLine(int line) { + m_swx->DoScrollToLine(line); +} + + +void wxStyledTextCtrl::ScrollToColumn(int column) { + m_swx->DoScrollToColumn(column); +} + + +void wxStyledTextCtrl::EnsureCaretVisible() { + SendMsg(EM_SCROLLCARET); +} + + +void wxStyledTextCtrl::SetCaretPolicy(int policy, int slop) { + SendMsg(SCI_SETCARETPOLICY, policy, slop); +} + + +int wxStyledTextCtrl::GetSelectionType() { + return SendMsg(EM_SELECTIONTYPE); +} + + + + +//---------------------------------------------------------------------- +// Searching + +int wxStyledTextCtrl::FindText(int minPos, int maxPos, + const wxString& text, + bool caseSensitive, bool wholeWord) { + FINDTEXTEX ft; + int flags = 0; + + flags |= caseSensitive ? FR_MATCHCASE : 0; + flags |= wholeWord ? FR_WHOLEWORD : 0; + ft.chrg.cpMin = minPos; + ft.chrg.cpMax = maxPos; + ft.lpstrText = (char*)text.c_str(); + + return SendMsg(EM_FINDTEXT, flags, (long)&ft); +} + + +void wxStyledTextCtrl::SearchAnchor() { + SendMsg(SCI_SEARCHANCHOR); +} + + +int wxStyledTextCtrl::SearchNext(const wxString& text, bool caseSensitive, bool wholeWord) { + int flags = 0; + flags |= caseSensitive ? FR_MATCHCASE : 0; + flags |= wholeWord ? FR_WHOLEWORD : 0; + + return SendMsg(SCI_SEARCHNEXT, flags, (long)text.c_str()); +} + + +int wxStyledTextCtrl::SearchPrev(const wxString& text, bool caseSensitive, bool wholeWord) { + int flags = 0; + flags |= caseSensitive ? FR_MATCHCASE : 0; + flags |= wholeWord ? FR_WHOLEWORD : 0; + + return SendMsg(SCI_SEARCHPREV, flags, (long)text.c_str()); +} + +//---------------------------------------------------------------------- +// Visible whitespace + + +bool wxStyledTextCtrl::GetViewWhitespace() { + return SendMsg(SCI_GETVIEWWS) != 0; +} + + +void wxStyledTextCtrl::SetViewWhitespace(bool visible) { + SendMsg(SCI_SETVIEWWS, visible); +} + + + +//---------------------------------------------------------------------- +// Line endings + +wxSTC_EOL wxStyledTextCtrl::GetEOLMode() { + return (wxSTC_EOL)SendMsg(SCI_GETEOLMODE); +} + + +void wxStyledTextCtrl::SetEOLMode(wxSTC_EOL mode) { + SendMsg(SCI_SETEOLMODE, mode); +} + + +bool wxStyledTextCtrl::GetViewEOL() { + return SendMsg(SCI_GETVIEWEOL) != 0; +} + + +void wxStyledTextCtrl::SetViewEOL(bool visible) { + SendMsg(SCI_SETVIEWEOL, visible); +} + +void wxStyledTextCtrl::ConvertEOL(wxSTC_EOL mode) { + SendMsg(SCI_CONVERTEOLS, mode); +} + +//---------------------------------------------------------------------- +// Styling + +int wxStyledTextCtrl::GetEndStyled() { + return SendMsg(SCI_GETENDSTYLED); +} + + +void wxStyledTextCtrl::StartStyling(int pos, int mask) { + SendMsg(SCI_STARTSTYLING, pos, mask); +} + + +void wxStyledTextCtrl::SetStyleFor(int length, int style) { + SendMsg(SCI_SETSTYLING, length, style); +} + + +void wxStyledTextCtrl::SetStyleBytes(int length, char* styleBytes) { + SendMsg(SCI_SETSTYLINGEX, length, (long)styleBytes); +} + + +//---------------------------------------------------------------------- +// Style Definition + + +static long wxColourAsLong(const wxColour& co) { + return (((long)co.Blue() << 16) | + ((long)co.Green() << 8) | + ((long)co.Red())); +} + +static wxColour wxColourFromLong(long c) { + wxColour clr; + clr.Set(c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff); + return clr; +} + + +static wxColour wxColourFromSpec(const wxString& spec) { + // spec should be #RRGGBB + char* junk; + int red = strtol(spec.Mid(1,2), &junk, 16); + int green = strtol(spec.Mid(3,2), &junk, 16); + int blue = strtol(spec.Mid(5,2), &junk, 16); + return wxColour(red, green, blue); +} + + +void wxStyledTextCtrl::StyleClearAll() { + SendMsg(SCI_STYLECLEARALL); +} + + +void wxStyledTextCtrl::StyleResetDefault() { + SendMsg(SCI_STYLERESETDEFAULT); +} + + + +// Extract style settings from a spec-string which is composed of one or +// more of the following comma separated elements: +// +// bold turns on bold +// italic turns on italics +// fore:#RRGGBB sets the foreground colour +// back:#RRGGBB sets the background colour +// face:[facename] sets the font face name to use +// size:[num] sets the font size in points +// eol turns on eol filling +// + +void wxStyledTextCtrl::StyleSetSpec(int styleNum, const wxString& spec) { + + wxStringTokenizer tkz(spec, ","); + while (tkz.HasMoreTokens()) { + wxString token = tkz.GetNextToken(); + + wxString option = token.BeforeFirst(':'); + wxString val = token.AfterFirst(':'); + + if (option == "bold") + StyleSetBold(styleNum, true); + + else if (option == "italic") + StyleSetItalic(styleNum, true); + + else if (option == "eol") + StyleSetEOLFilled(styleNum, true); + + else if (option == "size") { + long points; + if (val.ToLong(&points)) + StyleSetSize(styleNum, points); + } + + else if (option == "face") + StyleSetFaceName(styleNum, val); + + else if (option == "fore") + StyleSetForeground(styleNum, wxColourFromSpec(val)); + + else if (option == "back") + StyleSetBackground(styleNum, wxColourFromSpec(val)); + } +} + + +void wxStyledTextCtrl::StyleSetForeground(int styleNum, const wxColour& colour) { + SendMsg(SCI_STYLESETFORE, styleNum, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::StyleSetBackground(int styleNum, const wxColour& colour) { + SendMsg(SCI_STYLESETBACK, styleNum, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::StyleSetFont(int styleNum, wxFont& font) { + int size = font.GetPointSize(); + wxString faceName = font.GetFaceName(); + bool bold = font.GetWeight() == wxBOLD; + bool italic = font.GetStyle() != wxNORMAL; + + StyleSetFontAttr(styleNum, size, faceName, bold, italic); +} + + +void wxStyledTextCtrl::StyleSetFontAttr(int styleNum, int size, + const wxString& faceName, + bool bold, bool italic) { + StyleSetSize(styleNum, size); + StyleSetFaceName(styleNum, faceName); + StyleSetBold(styleNum, bold); + StyleSetItalic(styleNum, italic); +} + + +void wxStyledTextCtrl::StyleSetBold(int styleNum, bool bold) { + SendMsg(SCI_STYLESETBOLD, styleNum, bold); +} + + +void wxStyledTextCtrl::StyleSetItalic(int styleNum, bool italic) { + SendMsg(SCI_STYLESETITALIC, styleNum, italic); +} + + +void wxStyledTextCtrl::StyleSetFaceName(int styleNum, const wxString& faceName) { + SendMsg(SCI_STYLESETFONT, styleNum, (long)faceName.c_str()); +} + + +void wxStyledTextCtrl::StyleSetSize(int styleNum, int pointSize) { + SendMsg(SCI_STYLESETSIZE, styleNum, pointSize); +} + + +void wxStyledTextCtrl::StyleSetEOLFilled(int styleNum, bool fillEOL) { + SendMsg(SCI_STYLESETEOLFILLED, styleNum, fillEOL); +} + + +//---------------------------------------------------------------------- +// Margins in the edit area + +int wxStyledTextCtrl::GetLeftMargin() { + return LOWORD(SendMsg(EM_GETMARGINS)); +} + + +int wxStyledTextCtrl::GetRightMargin() { + return HIWORD(SendMsg(EM_GETMARGINS)); +} + + +void wxStyledTextCtrl::SetMargins(int left, int right) { + int flag = 0; + int val = 0; + + if (right != -1) { + flag |= EC_RIGHTMARGIN; + val = right << 16; + } + if (left != -1) { + flag |= EC_LEFTMARGIN; + val |= (left & 0xffff); + } + + SendMsg(EM_SETMARGINS, flag, val); +} + + +//---------------------------------------------------------------------- +// Margins for selection, markers, etc. + +void wxStyledTextCtrl::SetMarginType(int margin, int type) { + SendMsg(SCI_SETMARGINTYPEN, margin, type); +} + + +int wxStyledTextCtrl::GetMarginType(int margin) { + return SendMsg(SCI_GETMARGINTYPEN, margin); +} + + +void wxStyledTextCtrl::SetMarginWidth(int margin, int pixelWidth) { + SendMsg(SCI_SETMARGINWIDTHN, margin, pixelWidth); +} + + +int wxStyledTextCtrl::GetMarginWidth(int margin) { + return SendMsg(SCI_GETMARGINWIDTHN, margin); +} + + +void wxStyledTextCtrl::SetMarginMask(int margin, int mask) { + SendMsg(SCI_SETMARGINMASKN, margin, mask); +} + + +int wxStyledTextCtrl::GetMarginMask(int margin) { + return SendMsg(SCI_GETMARGINMASKN, margin); +} + + +void wxStyledTextCtrl::SetMarginSensitive(int margin, bool sensitive) { + SendMsg(SCI_SETMARGINSENSITIVEN, margin, sensitive); +} + + +bool wxStyledTextCtrl::GetMarginSensitive(int margin) { + return SendMsg(SCI_GETMARGINSENSITIVEN, margin); +} + + + + +//---------------------------------------------------------------------- +// Selection and Caret styles + + +void wxStyledTextCtrl::SetSelectionForeground(const wxColour& colour) { + SendMsg(SCI_SETSELFORE, 0, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::SetSelectionBackground(const wxColour& colour) { + SendMsg(SCI_SETSELBACK, 0, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::SetCaretForeground(const wxColour& colour) { + SendMsg(SCI_SETCARETFORE, 0, wxColourAsLong(colour)); +} + + +int wxStyledTextCtrl::GetCaretPeriod() { + return SendMsg(SCI_GETCARETPERIOD); +} + + +void wxStyledTextCtrl::SetCaretPeriod(int milliseconds) { + SendMsg(SCI_SETCARETPERIOD, milliseconds); +} + + + +//---------------------------------------------------------------------- +// Other settings + + +void wxStyledTextCtrl::SetBufferedDraw(bool isBuffered) { + SendMsg(SCI_SETBUFFEREDDRAW, isBuffered); +} + + +void wxStyledTextCtrl::SetTabWidth(int numChars) { + SendMsg(SCI_SETTABWIDTH, numChars); +} + + +void wxStyledTextCtrl::SetWordChars(const wxString& wordChars) { + SendMsg(SCI_SETTABWIDTH, 0, (long)wordChars.c_str()); +} + + +//---------------------------------------------------------------------- +// Brace highlighting + + +void wxStyledTextCtrl::BraceHighlight(int pos1, int pos2) { + SendMsg(SCI_BRACEHIGHLIGHT, pos1, pos2); +} + + +void wxStyledTextCtrl::BraceBadlight(int pos) { + SendMsg(SCI_BRACEBADLIGHT, pos); +} + + +int wxStyledTextCtrl::BraceMatch(int pos, int maxReStyle) { + return SendMsg(SCI_BRACEMATCH, pos, maxReStyle); +} + + + +//---------------------------------------------------------------------- +// Markers + +void wxStyledTextCtrl::MarkerDefine(int markerNumber, int markerSymbol, + const wxColour& foreground, + const wxColour& background) { + MarkerSetType(markerNumber, markerSymbol); + MarkerSetForeground(markerNumber, foreground); + MarkerSetBackground(markerNumber, background); +} + + +void wxStyledTextCtrl::MarkerSetType(int markerNumber, int markerSymbol) { + SendMsg(SCI_MARKERDEFINE, markerNumber, markerSymbol); +} + + +void wxStyledTextCtrl::MarkerSetForeground(int markerNumber, const wxColour& colour) { + SendMsg(SCI_MARKERSETFORE, markerNumber, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::MarkerSetBackground(int markerNumber, const wxColour& colour) { + SendMsg(SCI_MARKERSETBACK, markerNumber, wxColourAsLong(colour)); +} + + +int wxStyledTextCtrl::MarkerAdd(int line, int markerNumber) { + return SendMsg(SCI_MARKERADD, line, markerNumber); +} + + +void wxStyledTextCtrl::MarkerDelete(int line, int markerNumber) { + SendMsg(SCI_MARKERDELETE, line, markerNumber); +} + + +void wxStyledTextCtrl::MarkerDeleteAll(int markerNumber) { + SendMsg(SCI_MARKERDELETEALL, markerNumber); +} + + +int wxStyledTextCtrl::MarkerGet(int line) { + return SendMsg(SCI_MARKERGET); +} + + +int wxStyledTextCtrl::MarkerGetNextLine(int lineStart, int markerMask) { + return SendMsg(SCI_MARKERNEXT, lineStart, markerMask); +} + + +int wxStyledTextCtrl::MarkerGetPrevLine(int lineStart, int markerMask) { +// return SendMsg(SCI_MARKERPREV, lineStart, markerMask); + return 0; +} + + +int wxStyledTextCtrl::MarkerLineFromHandle(int handle) { + return SendMsg(SCI_MARKERLINEFROMHANDLE, handle); +} + + +void wxStyledTextCtrl::MarkerDeleteHandle(int handle) { + SendMsg(SCI_MARKERDELETEHANDLE, handle); +} + + + +//---------------------------------------------------------------------- +// Indicators + + +void wxStyledTextCtrl::IndicatorSetStyle(int indicNum, int indicStyle) { + SendMsg(SCI_INDICSETSTYLE, indicNum, indicStyle); +} + + +int wxStyledTextCtrl::IndicatorGetStyle(int indicNum) { + return SendMsg(SCI_INDICGETSTYLE, indicNum); +} + + +void wxStyledTextCtrl::IndicatorSetColour(int indicNum, const wxColour& colour) { + SendMsg(SCI_INDICSETSTYLE, indicNum, wxColourAsLong(colour)); +} + + + +//---------------------------------------------------------------------- +// Auto completion + + +void wxStyledTextCtrl::AutoCompShow(const wxString& listOfWords) { + SendMsg(SCI_AUTOCSHOW, 0, (long)listOfWords.c_str()); +} + + +void wxStyledTextCtrl::AutoCompCancel() { + SendMsg(SCI_AUTOCCANCEL); +} + + +bool wxStyledTextCtrl::AutoCompActive() { + return SendMsg(SCI_AUTOCACTIVE) != 0; +} + + +int wxStyledTextCtrl::AutoCompPosAtStart() { + return SendMsg(SCI_AUTOCPOSSTART); +} + + +void wxStyledTextCtrl::AutoCompComplete() { + SendMsg(SCI_AUTOCCOMPLETE); +} + + +void wxStyledTextCtrl::AutoCompStopChars(const wxString& stopChars) { + SendMsg(SCI_AUTOCSHOW, 0, (long)stopChars.c_str()); +} + + +//---------------------------------------------------------------------- +// Call tips + +void wxStyledTextCtrl::CallTipShow(int pos, const wxString& text) { + SendMsg(SCI_CALLTIPSHOW, pos, (long)text.c_str()); +} + + +void wxStyledTextCtrl::CallTipCancel() { + SendMsg(SCI_CALLTIPCANCEL); +} + + +bool wxStyledTextCtrl::CallTipActive() { + return SendMsg(SCI_CALLTIPACTIVE) != 0; +} + + +int wxStyledTextCtrl::CallTipPosAtStart() { + return SendMsg(SCI_CALLTIPPOSSTART); +} + + +void wxStyledTextCtrl::CallTipSetHighlight(int start, int end) { + SendMsg(SCI_CALLTIPSETHLT, start, end); +} + + +void wxStyledTextCtrl::CallTipSetBackground(const wxColour& colour) { + SendMsg(SCI_CALLTIPSETBACK, wxColourAsLong(colour)); +} + + +//---------------------------------------------------------------------- +// Key bindings + +void wxStyledTextCtrl::CmdKeyAssign(int key, int modifiers, int cmd) { + SendMsg(SCI_ASSIGNCMDKEY, MAKELONG(key, modifiers), cmd); +} + + +void wxStyledTextCtrl::CmdKeyClear(int key, int modifiers) { + SendMsg(SCI_CLEARCMDKEY, MAKELONG(key, modifiers)); +} + + +void wxStyledTextCtrl::CmdKeyClearAll() { + SendMsg(SCI_CLEARALLCMDKEYS); +} + + +void wxStyledTextCtrl::CmdKeyExecute(int cmd) { + SendMsg(cmd); +} + + + +//---------------------------------------------------------------------- +// Print formatting + +int +wxStyledTextCtrl::FormatRange(bool doDraw, + int startPos, + int endPos, + wxDC* draw, + wxDC* target, // Why does it use two? Can they be the same? + wxRect renderRect, + wxRect pageRect) { + FORMATRANGE fr; + + fr.hdc = draw; + fr.hdcTarget = target; + fr.rc.top = renderRect.GetTop(); + fr.rc.left = renderRect.GetLeft(); + fr.rc.right = renderRect.GetRight(); + fr.rc.bottom = renderRect.GetBottom(); + fr.rcPage.top = pageRect.GetTop(); + fr.rcPage.left = pageRect.GetLeft(); + fr.rcPage.right = pageRect.GetRight(); + fr.rcPage.bottom = pageRect.GetBottom(); + fr.chrg.cpMin = startPos; + fr.chrg.cpMax = endPos; + + return SendMsg(EM_FORMATRANGE, doDraw, (long)&fr); +} + + +//---------------------------------------------------------------------- +// Document Sharing + +void* wxStyledTextCtrl::GetDocument() { + return (void*)SendMsg(SCI_GETDOCPOINTER); +} + + +void wxStyledTextCtrl::SetDocument(void* document) { + SendMsg(SCI_SETDOCPOINTER, 0, (long)document); +} + + +//---------------------------------------------------------------------- +// Long Lines + +int wxStyledTextCtrl::GetEdgeColumn() { + return SendMsg(SCI_GETEDGECOLUMN); +} + +void wxStyledTextCtrl::SetEdgeColumn(int column) { + SendMsg(SCI_SETEDGECOLUMN, column); +} + +wxSTC_EDGE wxStyledTextCtrl::GetEdgeMode() { + return (wxSTC_EDGE) SendMsg(SCI_GETEDGEMODE); +} + +void wxStyledTextCtrl::SetEdgeMode(wxSTC_EDGE mode){ + SendMsg(SCI_SETEDGEMODE, mode); +} + +wxColour wxStyledTextCtrl::GetEdgeColour() { + long c = SendMsg(SCI_GETEDGECOLOUR); + return wxColourFromLong(c); +} + +void wxStyledTextCtrl::SetEdgeColour(const wxColour& colour) { + SendMsg(SCI_SETEDGECOLOUR, wxColourAsLong(colour)); +} + + +//---------------------------------------------------------------------- +// Lexer + +void wxStyledTextCtrl::SetLexer(wxSTC_LEX lexer) { + SendMsg(SCI_SETLEXER, lexer); +} + + +wxSTC_LEX wxStyledTextCtrl::GetLexer() { + return (wxSTC_LEX)SendMsg(SCI_GETLEXER); +} + + +void wxStyledTextCtrl::Colourise(int start, int end) { + SendMsg(SCI_COLOURISE, start, end); +} + + +void wxStyledTextCtrl::SetProperty(const wxString& key, const wxString& value) { + SendMsg(SCI_SETPROPERTY, (long)key.c_str(), (long)value.c_str()); +} + + +void wxStyledTextCtrl::SetKeywords(int keywordSet, const wxString& keywordList) { + SendMsg(SCI_SETKEYWORDS, keywordSet, (long)keywordList.c_str()); +} + + + +//---------------------------------------------------------------------- +// Event handlers + +void wxStyledTextCtrl::OnPaint(wxPaintEvent& evt) { + wxPaintDC dc(this); + wxRegion region = GetUpdateRegion(); + + m_swx->DoPaint(&dc, region.GetBox()); +} + +void wxStyledTextCtrl::OnScrollWin(wxScrollWinEvent& evt) { + if (evt.GetOrientation() == wxHORIZONTAL) + m_swx->DoHScroll(evt.GetEventType(), evt.GetPosition()); + else + m_swx->DoVScroll(evt.GetEventType(), evt.GetPosition()); +} + +void wxStyledTextCtrl::OnSize(wxSizeEvent& evt) { + wxSize sz = GetClientSize(); + m_swx->DoSize(sz.x, sz.y); +} + +void wxStyledTextCtrl::OnMouseLeftDown(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoButtonDown(Point(pt.x, pt.y), m_stopWatch.Time(), + evt.ShiftDown(), evt.ControlDown(), evt.AltDown()); +} + +void wxStyledTextCtrl::OnMouseMove(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoButtonMove(Point(pt.x, pt.y)); +} + +void wxStyledTextCtrl::OnMouseLeftUp(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoButtonUp(Point(pt.x, pt.y), m_stopWatch.Time(), + evt.ControlDown()); +} + + +void wxStyledTextCtrl::OnMouseRightUp(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoContextMenu(Point(pt.x, pt.y)); +} + +void wxStyledTextCtrl::OnChar(wxKeyEvent& evt) { + int processed = 0; + long key = evt.KeyCode(); + if ((key > WXK_ESCAPE) && + (key != WXK_DELETE) && (key < 255) && + !evt.ControlDown() && !evt.AltDown()) { + + m_swx->DoAddChar(key); + processed = true; + } + else { + key = toupper(key); + processed = m_swx->DoKeyDown(key, evt.ShiftDown(), + evt.ControlDown(), evt.AltDown()); + } + if (! processed) + evt.Skip(); +} + +void wxStyledTextCtrl::OnLoseFocus(wxFocusEvent& evt) { + m_swx->DoLoseFocus(); +} + +void wxStyledTextCtrl::OnGainFocus(wxFocusEvent& evt) { + m_swx->DoGainFocus(); +} + +void wxStyledTextCtrl::OnSysColourChanged(wxSysColourChangedEvent& evt) { + m_swx->DoSysColourChange(); +} + +void wxStyledTextCtrl::OnEraseBackground(wxEraseEvent& evt) { + // do nothing to help avoid flashing +} + + + +void wxStyledTextCtrl::OnMenu(wxCommandEvent& evt) { + m_swx->DoCommand(evt.GetId()); +} + + +//---------------------------------------------------------------------- +// Turn notifications from Scintilla into events + +void wxStyledTextCtrl::NotifyChange() { + wxStyledTextEvent evt(wxEVT_STC_CHANGE, GetId()); + GetEventHandler()->ProcessEvent(evt); +} + +void wxStyledTextCtrl::NotifyParent(SCNotification* _scn) { + SCNotification& scn = *_scn; + int eventType = 0; + switch (scn.nmhdr.code) { + case SCN_STYLENEEDED: + eventType = wxEVT_STC_STYLENEEDED; + break; + case SCN_CHARADDED: + eventType = wxEVT_STC_CHARADDED; + break; + case SCN_UPDATEUI: + eventType = wxEVT_STC_UPDATEUI; + break; + case SCN_SAVEPOINTREACHED: + eventType = wxEVT_STC_SAVEPOINTREACHED; + break; + case SCN_SAVEPOINTLEFT: + eventType = wxEVT_STC_SAVEPOINTLEFT; + break; + case SCN_MODIFYATTEMPTRO: + eventType = wxEVT_STC_ROMODIFYATTEMPT; + break; + case SCN_DOUBLECLICK: + eventType = wxEVT_STC_DOUBLECLICK; + break; + case SCN_MODIFIED: + eventType = wxEVT_STC_MODIFIED; + break; + case SCN_KEY: + eventType = wxEVT_STC_KEY; + break; + case SCN_MACRORECORD: + eventType = wxEVT_STC_MACRORECORD; + break; + case SCN_MARGINCLICK: + eventType = wxEVT_STC_MARGINCLICK; + break; + case SCN_NEEDSHOWN: + eventType = wxEVT_STC_NEEDSHOWN; + break; + } + if (eventType) { + wxStyledTextEvent evt(eventType, GetId()); + evt.SetPosition(scn.position); + evt.SetKey(scn.ch); + evt.SetModifiers(scn.modifiers); + if (eventType == wxEVT_STC_MODIFIED) { + evt.SetModificationType(scn.modificationType); + evt.SetText(scn.text); + evt.SetLength(scn.length); + evt.SetLinesAdded(scn.linesAdded); + evt.SetLine(scn.line); + evt.SetFoldLevelNow(scn.foldLevelNow); + evt.SetFoldLevelPrev(scn.foldLevelPrev); + } + if (eventType == wxEVT_STC_MARGINCLICK) + evt.SetMargin(scn.margin); + if (eventType == wxEVT_STC_MACRORECORD) { + evt.SetMessage(scn.message); + evt.SetWParam(scn.wParam); + evt.SetLParam(scn.lParam); + } + + GetEventHandler()->ProcessEvent(evt); + } +} + + + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +wxStyledTextEvent::wxStyledTextEvent(wxEventType commandType, int id) + : wxCommandEvent(commandType, id) +{ + m_position = 0; + m_key = 0; + m_modifiers = 0; + m_modificationType = 0; + m_length = 0; + m_linesAdded = 0; + m_line = 0; + m_foldLevelNow = 0; + m_foldLevelPrev = 0; + m_margin = 0; + m_message = 0; + m_wParam = 0; + m_lParam = 0; + + +} + +bool wxStyledTextEvent::GetShift() const { return (m_modifiers & SCI_SHIFT) != 0; } +bool wxStyledTextEvent::GetControl() const { return (m_modifiers & SCI_CTRL) != 0; } +bool wxStyledTextEvent::GetAlt() const { return (m_modifiers & SCI_ALT) != 0; } + +void wxStyledTextEvent::CopyObject(wxObject& obj) const { + wxCommandEvent::CopyObject(obj); + + wxStyledTextEvent* o = (wxStyledTextEvent*)&obj; + o->m_position = m_position; + o->m_key = m_key; + o->m_modifiers = m_modifiers; + o->m_modificationType = m_modificationType; + o->m_text = m_text; + o->m_length = m_length; + o->m_linesAdded = m_linesAdded; + o->m_line = m_line; + o->m_foldLevelNow = m_foldLevelNow; + o->m_foldLevelPrev = m_foldLevelPrev; + + o->m_margin = m_margin; + + o->m_message = m_message; + o->m_wParam = m_wParam; + o->m_lParam = m_lParam; + + + +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + diff --git a/include/wx/stc/stc.h b/include/wx/stc/stc.h new file mode 100644 index 0000000000..4920f70b33 --- /dev/null +++ b/include/wx/stc/stc.h @@ -0,0 +1,547 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: stc.h +// Purpose: A wxWindows implementation of Scintilla. This class is the +// one meant to be used directly by wx applications. It does not +// derive directly from the Scintilla classes, and in fact there +// is no mention of Scintilla classes at all in this header. +// This class delegates all method calls and events to the +// Scintilla objects and so forth. This allows the use of +// Scintilla without polluting the namespace with all the +// classes and itentifiers from Scintilla. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __stc_h__ +#define __stc_h__ + + +#include + + +//---------------------------------------------------------------------- +// constants and stuff + +enum wxSTC_UndoType { + wxSTC_UndoCollectNone, + wxSTC_UndoCollectAutoStart +}; + + +enum wxSTC_EOL { + wxSTC_EOL_CRLF, + wxSTC_EOL_CR, + wxSTC_EOL_LF +}; + +enum wxSTC_EDGE { + wxSTC_EDGE_NONE, + wxSTC_EDGE_LINE, + wxSTC_EDGE_BACKGROUND +}; + + + +const int wxSTC_LEX_STYLE_MAX = 31; +const int wxSTC_STYLE_DEFAULT = 32; +const int wxSTC_STYLE_LINENUMBER = 33; +const int wxSTC_STYLE_BRACELIGHT = 34; +const int wxSTC_STYLE_BRACEBAD = 35; +const int wxSTC_STYLE_CONTROLCHAR = 36; +const int wxSTC_STYLE_MAX = 63; +const int wxSTC_STYLE_MASK = 31; + +const int wxSTC_MARKER_MAX = 31; +const int wxSTC_MARK_CIRCLE = 0; +const int wxSTC_MARK_ROUNDRECT = 1; +const int wxSTC_MARK_ARROW = 2; +const int wxSTC_MARK_SMALLRECT = 3; +const int wxSTC_MARK_SHORTARROW = 4; +const int wxSTC_MARK_EMPTY = 5; + +const int wxSTC_INDIC_PLAIN = 0; +const int wxSTC_INDIC_SQUIGGLE = 1; +const int wxSTC_INDIC_TT = 2; +const int wxSTC_INDIC0_MASK = 32; +const int wxSTC_INDIC1_MASK = 64; +const int wxSTC_INDIC2_MASK = 128; +const int wxSTC_INDICS_MASK = (wxSTC_INDIC0_MASK | wxSTC_INDIC1_MASK | wxSTC_INDIC2_MASK); + + +// key commands +enum { + wxSTC_CMD_LINEDOWN = 2300, + wxSTC_CMD_LINEDOWNEXTEND, + wxSTC_CMD_LINEUP, + wxSTC_CMD_LINEUPEXTEND, + wxSTC_CMD_CHARLEFT, + wxSTC_CMD_CHARLEFTEXTEND, + wxSTC_CMD_CHARRIGHT, + wxSTC_CMD_CHARRIGHTEXTEND, + wxSTC_CMD_WORDLEFT, + wxSTC_CMD_WORDLEFTEXTEND, + wxSTC_CMD_WORDRIGHT, + wxSTC_CMD_WORDRIGHTEXTEND, + wxSTC_CMD_HOME, + wxSTC_CMD_HOMEEXTEND, + wxSTC_CMD_LINEEND, + wxSTC_CMD_LINEENDEXTEND, + wxSTC_CMD_DOCUMENTSTART, + wxSTC_CMD_DOCUMENTSTARTEXTEND, + wxSTC_CMD_DOCUMENTEND, + wxSTC_CMD_DOCUMENTENDEXTEND, + wxSTC_CMD_PAGEUP, + wxSTC_CMD_PAGEUPEXTEND, + wxSTC_CMD_PAGEDOWN, + wxSTC_CMD_PAGEDOWNEXTEND, + wxSTC_CMD_EDITTOGGLEOVERTYPE, + wxSTC_CMD_CANCEL, + wxSTC_CMD_DELETEBACK, + wxSTC_CMD_TAB, + wxSTC_CMD_BACKTAB, + wxSTC_CMD_NEWLINE, + wxSTC_CMD_FORMFEED, + wxSTC_CMD_VCHOME, + wxSTC_CMD_VCHOMEEXTEND, + wxSTC_CMD_ZOOMIN, + wxSTC_CMD_ZOOMOUT, + wxSTC_CMD_DELWORDLEFT, + wxSTC_CMD_DELWORDRIGHT +}; + + +enum wxSTC_LEX { + wxSTC_LEX_CONTAINER=0, + wxSTC_LEX_NULL, + wxSTC_LEX_PYTHON, + wxSTC_LEX_CPP, + wxSTC_LEX_HTML, + wxSTC_LEX_XML, + wxSTC_LEX_PERL, + wxSTC_LEX_SQL, + wxSTC_LEX_VB, + wxSTC_LEX_PROPERTIES, + wxSTC_LEX_ERRORLIST, + wxSTC_LEX_MAKEFILE, + wxSTC_LEX_BATCH, +}; + + + +const int wxSTC_CARET_SLOP = 0x01; +const int WXSTC_CARET_CENTER = 0x02; +const int wxSTC_CARET_STRICT = 0x04; + +const int wxSTC_MARGIN_SYMBOL = 0; +const int wxSTC_MARGIN_NUMBER = 1; + + +class ScintillaWX; // forward declare +class WordList; +struct SCNotification; + + +extern const wxChar* wxSTCNameStr; + +//---------------------------------------------------------------------- + +class wxStyledTextCtrl : public wxControl { +public: + + wxStyledTextCtrl(wxWindow *parent, wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, + const wxString& name = wxSTCNameStr); + ~wxStyledTextCtrl(); + + + + // Text retrieval and modification + wxString GetText(); + bool SetText(const wxString& text); + wxString GetLine(int line); + void ReplaceSelection(const wxString& text); + void SetReadOnly(bool readOnly); + bool GetReadOnly(); + wxString GetTextRange(int startPos, int endPos); + wxString GetStyledTextRange(int startPos, int endPos); + void GetTextRange(int startPos, int endPos, char* buff); + void GetStyledTextRange(int startPos, int endPos, char* buff); + void AddText(const wxString& text); + void AddStyledText(const wxString& text); + void InsertText(int pos, const wxString& text); + void ClearAll(); + char GetCharAt(int pos); + char GetStyleAt(int pos); + void SetStyleBits(int bits); + int GetStyleBits(); + + + // Clipboard + void Cut(); + void Copy(); + void Paste(); + bool CanPaste(); + void ClearClipbrd(); // avoiding name conflict with virtual in wxWindow + + + // Undo and Redo + void Undo(); + bool CanUndo(); + void EmptyUndoBuffer(); + void Redo(); + bool CanRedo(); + void SetUndoCollection(wxSTC_UndoType type); + wxSTC_UndoType GetUndoCollection(); + void BeginUndoAction(); + void EndUndoAction(); + + + // Selection and information + void GetSelection(int* startPos, int* endPos); + void SetSelection(int startPos, int endPos); + wxString GetSelectedText(); + void HideSelection(bool hide); + bool GetHideSelection(); + + int GetTextLength(); + int GetFirstVisibleLine(); + bool GetModified(); + int GetLineCount(); + wxRect GetRect(); + int GetLineFromPos(int pos); + int GetLineStartPos(int line); + int GetLineLengthAtPos(int pos); + int GetLineLength(int line); + wxString GetCurrentLineText(int* linePos=NULL); + int GetCurrentLine(); + int PositionFromPoint(wxPoint pt); + int LineFromPoint(wxPoint pt); + wxPoint PointFromPosition(int pos); + int GetCurrentPos(); + int GetAnchor(); + void SelectAll(); + void SetCurrentPosition(int pos); + void SetAnchor(int pos); + void GotoPos(int pos); + void GotoLine(int line); + void ChangePosition(int delta, bool extendSelection); + void PageMove(int cmdKey, bool extendSelection); + + void ScrollBy(int columnDelta, int lineDelta); + void ScrollToLine(int line); + void ScrollToColumn(int column); + void EnsureCaretVisible(); + void SetCaretPolicy(int policy, int slop=0); + int GetSelectionType(); + + + + // Searching + int FindText(int minPos, int maxPos, const wxString& text, + bool caseSensitive, bool wholeWord); + void SearchAnchor(); + int SearchNext(const wxString& text, bool caseSensitive, bool wholeWord); + int SearchPrev(const wxString& text, bool caseSensitive, bool wholeWord); + + + // Visible whitespace + bool GetViewWhitespace(); + void SetViewWhitespace(bool visible); + + + // Line endings + wxSTC_EOL GetEOLMode(); + void SetEOLMode(wxSTC_EOL mode); + bool GetViewEOL(); + void SetViewEOL(bool visible); + void ConvertEOL(wxSTC_EOL mode); + + + // Styling + int GetEndStyled(); + void StartStyling(int pos, int mask); + void SetStyleFor(int length, int style); + void SetStyleBytes(int length, char* styleBytes); + + + // Style Definition + void StyleClearAll(); + void StyleResetDefault(); + void StyleSetSpec(int styleNum, const wxString& spec); + void StyleSetForeground(int styleNum, const wxColour& colour); + void StyleSetBackground(int styleNum, const wxColour& colour); + void StyleSetFont(int styleNum, wxFont& font); + void StyleSetFontAttr(int styleNum, int size, const wxString& faceName, bool bold, bool italic); + void StyleSetBold(int styleNum, bool bold); + void StyleSetItalic(int styleNum, bool italic); + void StyleSetFaceName(int styleNum, const wxString& faceName); + void StyleSetSize(int styleNum, int pointSize); + void StyleSetEOLFilled(int styleNum, bool fillEOL); + + + // Margins in the edit area + int GetLeftMargin(); + int GetRightMargin(); + void SetMargins(int left, int right); + + + // Margins for selection, markers, etc. + void SetMarginType(int margin, int type); + int GetMarginType(int margin); + void SetMarginWidth(int margin, int pixelWidth); + int GetMarginWidth(int margin); + void SetMarginMask(int margin, int mask); + int GetMarginMask(int margin); + void SetMarginSensitive(int margin, bool sensitive); + bool GetMarginSensitive(int margin); + + + // Selection and Caret styles + void SetSelectionForeground(const wxColour& colour); + void SetSelectionBackground(const wxColour& colour); + void SetCaretForeground(const wxColour& colour); + int GetCaretPeriod(); + void SetCaretPeriod(int milliseconds); + + + // Other settings + void SetBufferedDraw(bool isBuffered); + void SetTabWidth(int numChars); + void SetWordChars(const wxString& wordChars); + + + // Brace highlighting + void BraceHighlight(int pos1, int pos2); + void BraceBadlight(int pos); + int BraceMatch(int pos, int maxReStyle=0); + + + // Markers + void MarkerDefine(int markerNumber, int markerSymbol, + const wxColour& foreground, + const wxColour& background); + void MarkerSetType(int markerNumber, int markerSymbol); + void MarkerSetForeground(int markerNumber, const wxColour& colour); + void MarkerSetBackground(int markerNumber, const wxColour& colour); + int MarkerAdd(int line, int markerNumber); + void MarkerDelete(int line, int markerNumber); + void MarkerDeleteAll(int markerNumber); + int MarkerGet(int line); + int MarkerGetNextLine(int lineStart, int markerMask); + int MarkerGetPrevLine(int lineStart, int markerMask); + int MarkerLineFromHandle(int handle); + void MarkerDeleteHandle(int handle); + + + // Indicators + void IndicatorSetStyle(int indicNum, int indicStyle); + int IndicatorGetStyle(int indicNum); + void IndicatorSetColour(int indicNum, const wxColour& colour); + + + // Auto completion + void AutoCompShow(const wxString& listOfWords); + void AutoCompCancel(); + bool AutoCompActive(); + int AutoCompPosAtStart(); + void AutoCompComplete(); + void AutoCompStopChars(const wxString& stopChars); + + + // Call tips + void CallTipShow(int pos, const wxString& text); + void CallTipCancel(); + bool CallTipActive(); + int CallTipPosAtStart(); + void CallTipSetHighlight(int start, int end); + void CallTipSetBackground(const wxColour& colour); + + + // Key bindings + void CmdKeyAssign(int key, int modifiers, int cmd); + void CmdKeyClear(int key, int modifiers); + void CmdKeyClearAll(); + void CmdKeyExecute(int cmd); + + + // Print formatting + int FormatRange(bool doDraw, + int startPos, + int endPos, + wxDC* draw, + wxDC* target, // Why does it use two? Can they be the same? + wxRect renderRect, + wxRect pageRect); + + + // Document Sharing (multiple views) + void* GetDocument(); + void SetDocument(void* document); + // TODO: create a wx wrapper for Scintilla's document class + + + // TODO: Folding + + + // Long Lines + int GetEdgeColumn(); + void SetEdgeColumn(int column); + wxSTC_EDGE GetEdgeMode(); + void SetEdgeMode(wxSTC_EDGE mode); + wxColour GetEdgeColour(); + void SetEdgeColour(const wxColour& colour); + + + // Lexer + void SetLexer(wxSTC_LEX lexer); + wxSTC_LEX GetLexer(); + void Colourise(int start, int end); + void SetProperty(const wxString& key, const wxString& value); + void SetKeywords(int keywordSet, const wxString& keywordList); + + + +private: + // Event handlers + void OnPaint(wxPaintEvent& evt); + void OnScrollWin(wxScrollWinEvent& evt); + void OnSize(wxSizeEvent& evt); + void OnMouseLeftDown(wxMouseEvent& evt); + void OnMouseMove(wxMouseEvent& evt); + void OnMouseLeftUp(wxMouseEvent& evt); + void OnMouseRightUp(wxMouseEvent& evt); + void OnChar(wxKeyEvent& evt); + void OnLoseFocus(wxFocusEvent& evt); + void OnGainFocus(wxFocusEvent& evt); + void OnSysColourChanged(wxSysColourChangedEvent& evt); + void OnEraseBackground(wxEraseEvent& evt); + void OnMenu(wxCommandEvent& evt); + + + // Turn notifications from Scintilla into events + void NotifyChange(); + void NotifyParent(SCNotification* scn); + + long SendMsg(int msg, long wp=0, long lp=0); + +private: + DECLARE_EVENT_TABLE() + + ScintillaWX* m_swx; + wxStopWatch m_stopWatch; + bool m_readOnly; + wxSTC_UndoType m_undoType; + + + friend class ScintillaWX; + friend class Platform; +}; + +//---------------------------------------------------------------------- + +class wxStyledTextEvent : public wxCommandEvent { +public: + wxStyledTextEvent(wxEventType commandType, int id); + ~wxStyledTextEvent() {} + + void SetPosition(int pos) { m_position = pos; } + void SetKey(int k) { m_key = k; } + void SetModifiers(int m) { m_modifiers = m; } + void SetModificationType(int t) { m_modificationType = t; } + void SetText(const char* t) { m_text = t; } + void SetLength(int len) { m_length = len; } + void SetLinesAdded(int num) { m_linesAdded = num; } + void SetLine(int val) { m_line = val; } + void SetFoldLevelNow(int val) { m_foldLevelNow = val; } + void SetFoldLevelPrev(int val) { m_foldLevelPrev = val; } + void SetMargin(int val) { m_margin = val; } + void SetMessage(int val) { m_message = val; } + void SetWParam(int val) { m_wParam = val; } + void SetLParam(int val) { m_lParam = val; } + + int GetPosition() const { return m_position; } + int GetKey() const { return m_key; } + int GetModifiers() const { return m_modifiers; } + int GetModificationType() const { return m_modificationType; } + wxString GetText() const { return m_text; } + int GetLength() const { return m_length; } + int GetLinesAdded() const { return m_linesAdded; } + int GetLine() const { return m_line; } + int GetFoldLevelNow() const { return m_foldLevelNow; } + int GetFoldLevelPrev() const { return m_foldLevelPrev; } + int GetMargin() const { return m_margin; } + int GetMessage() const { return m_message; } + int GetWParam() const { return m_wParam; } + int GetLParam() const { return m_lParam; } + + bool GetShift() const; + bool GetControl() const; + bool GetAlt() const; + + void CopyObject(wxObject& obj) const; + +private: + int m_position; + int m_key; + int m_modifiers; + + int m_modificationType; // wxEVT_STC_MODIFIED + wxString m_text; + int m_length; + int m_linesAdded; + int m_line; + int m_foldLevelNow; + int m_foldLevelPrev; + + int m_margin; // wxEVT_STC_MARGINCLICK + + int m_message; // wxEVT_STC_MACRORECORD + int m_wParam; + int m_lParam; + +}; + + + +enum { + wxEVT_STC_CHANGE = 1650, + wxEVT_STC_STYLENEEDED, + wxEVT_STC_CHARADDED, + wxEVT_STC_UPDATEUI, + wxEVT_STC_SAVEPOINTREACHED, + wxEVT_STC_SAVEPOINTLEFT, + wxEVT_STC_ROMODIFYATTEMPT, + wxEVT_STC_DOUBLECLICK, + wxEVT_STC_MODIFIED, + wxEVT_STC_KEY, + wxEVT_STC_MACRORECORD, + wxEVT_STC_MARGINCLICK, + wxEVT_STC_NEEDSHOWN +}; + +typedef void (wxEvtHandler::*wxStyledTextEventFunction)(wxStyledTextEvent&); + +#define EVT_STC_CHANGE(id, fn) { wxEVT_STC_CHANGE, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_STYLENEEDED(id, fn) { wxEVT_STC_STYLENEEDED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_CHARADDED(id, fn) { wxEVT_STC_CHARADDED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_UPDATEUI(id, fn) { wxEVT_STC_UPDATEUI, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_SAVEPOINTREACHED(id, fn) { wxEVT_STC_SAVEPOINTREACHED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_SAVEPOINTLEFT(id, fn) { wxEVT_STC_SAVEPOINTLEFT, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_ROMODIFYATTEMPT(id, fn) { wxEVT_STC_ROMODIFYATTEMPT, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_DOUBLECLICK(id, fn) { wxEVT_STC_DOUBLECLICK, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_MODIFIED(id, fn) { wxEVT_STC_MODIFIED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_CMDKEY(id, fn) { wxEVT_STC_CMDKEY, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, +#define EVT_STC_UNKNOWNCMDKEY(id, fn) { wxEVT_STC_UNKNOWNCMDKEY, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxStyledTextEventFunction) & fn, (wxObject *) NULL }, + + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +#endif + + diff --git a/samples/stc/.cvsignore b/samples/stc/.cvsignore new file mode 100644 index 0000000000..bfe355bda3 --- /dev/null +++ b/samples/stc/.cvsignore @@ -0,0 +1 @@ +stctest.res diff --git a/samples/stc/makefile.vc b/samples/stc/makefile.vc new file mode 100644 index 0000000000..956b781364 --- /dev/null +++ b/samples/stc/makefile.vc @@ -0,0 +1,14 @@ +# File: makefile.vc For stectrl +# Author: Robin Dunn +# Created: 1-Feb-2000 +# Updated: + +WXDIR = $(WXWIN) +PROGRAM = stctest + +OBJECTS = $(PROGRAM).obj +EXTRALIBS = $(WXDIR)\contrib\lib\stc$(LIBEXT).lib +EXTRAINC = -I$(WXDIR)\contrib\include + +!include $(WXDIR)\src\makeprog.vc + diff --git a/samples/stc/stctest.cpp b/samples/stc/stctest.cpp new file mode 100644 index 0000000000..fe337aadb3 --- /dev/null +++ b/samples/stc/stctest.cpp @@ -0,0 +1,204 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: stctest.cpp +// Purpose: sample of using wxStyledTextCtrl +// Author: Robin Dunn +// Modified by: +// Created: 3-Feb-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "stctest.cpp" + #pragma interface "stctest.cpp" +#endif + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWindows headers +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include + +#include + +//---------------------------------------------------------------------- + +class MyApp : public wxApp +{ +public: + virtual bool OnInit(); +}; + +//---------------------------------------------------------------------- + +// Define a new frame type: this is going to be our main frame +class MyFrame : public wxFrame +{ +public: + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnStyleNeeded(wxStyledTextEvent& event); + +private: + wxStyledTextCtrl* ed; + + DECLARE_EVENT_TABLE() +}; + + +// IDs for the controls and the menu commands +enum +{ + // menu items + ID_Quit = 1, + ID_About, + ID_ED +}; + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU (ID_Quit, MyFrame::OnQuit) + EVT_MENU (ID_About, MyFrame::OnAbout) + EVT_STC_STYLENEEDED (ID_ED, MyFrame::OnStyleNeeded) +END_EVENT_TABLE() + +IMPLEMENT_APP(MyApp) + +//---------------------------------------------------------------------- +// `Main program' equivalent: the program execution "starts" here + +bool MyApp::OnInit() +{ + MyFrame *frame = new MyFrame("Testing wxStyledTextCtrl", + wxPoint(5, 5), wxSize(400, 600)); + + frame->Show(TRUE); + return TRUE; +} + +//---------------------------------------------------------------------- + +// frame constructor +MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) +{ +#ifdef __WXMAC__ + // we need this in order to allow the about menu relocation, since ABOUT is + // not the default id of the about menu + wxApp::s_macAboutMenuItemId = ID_About; +#endif + + + // create a menu bar + wxMenu *menuFile = new wxMenu("", wxMENU_TEAROFF); + + // the "About" item should be in the help menu + wxMenu *helpMenu = new wxMenu; + helpMenu->Append(ID_About, "&About...\tCtrl-A", "Show about dialog"); + + menuFile->Append(ID_Quit, "E&xit\tAlt-X", "Quit this program"); + + // now append the freshly created menu to the menu bar... + wxMenuBar *menuBar = new wxMenuBar(); + menuBar->Append(menuFile, "&File"); + menuBar->Append(helpMenu, "&Help"); + + // ... and attach this menu bar to the frame + SetMenuBar(menuBar); + +#if wxUSE_STATUSBAR + CreateStatusBar(2); + SetStatusText("Testing wxStyledTextCtrl"); +#endif // wxUSE_STATUSBAR + + + //---------------------------------------- + // Setup the editor + ed = new wxStyledTextCtrl(this, ID_ED); + + // Default font + wxFont font(8, wxMODERN, wxNORMAL, wxNORMAL); + ed->StyleSetFont(wxSTC_STYLE_DEFAULT, font); + ed->StyleClearAll(); + + ed->StyleSetForeground(0, wxColour(0x80, 0x80, 0x80)); + ed->StyleSetForeground(1, wxColour(0x00, 0x7f, 0x00)); + //ed->StyleSetForeground(2, wxColour(0x00, 0x7f, 0x00)); + ed->StyleSetForeground(3, wxColour(0x7f, 0x7f, 0x7f)); + ed->StyleSetForeground(4, wxColour(0x00, 0x7f, 0x7f)); + ed->StyleSetForeground(5, wxColour(0x00, 0x00, 0x7f)); + ed->StyleSetForeground(6, wxColour(0x7f, 0x00, 0x7f)); + ed->StyleSetForeground(7, wxColour(0x7f, 0x00, 0x7f)); + ed->StyleSetForeground(8, wxColour(0x00, 0x7f, 0x7f)); + ed->StyleSetForeground(9, wxColour(0x7f, 0x7f, 0x7f)); + ed->StyleSetForeground(10, wxColour(0x00, 0x00, 0x00)); + ed->StyleSetForeground(11, wxColour(0x00, 0x00, 0x00)); + ed->StyleSetBold(5, TRUE); + ed->StyleSetBold(10, TRUE); + +#ifdef __WXMSW__ + ed->StyleSetSpec(2, "fore:#007f00,bold,face:Arial,size:7"); +#else + ed->StyleSetSpec(2, "fore:#007f00,bold,face:Helvetica,size:7"); +#endif + + // give it some text to play with + wxFile file("stctest.cpp"); + wxString st; + + char* buff = st.GetWriteBuf(file.Length()); + file.Read(buff, file.Length()); + st.UngetWriteBuf(); + + ed->InsertText(0, st); + ed->EmptyUndoBuffer(); + + ed->SetLexer(wxSTC_LEX_CPP); + ed->SetKeywords(0, + "asm auto bool break case catch char class 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 operator 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"); + +} + + +// event handlers + +void MyFrame::OnStyleNeeded(wxStyledTextEvent& event) { + int currEndStyled = ed->GetEndStyled(); + ed->Colourise(currEndStyled, event.GetPosition()); +} + + + + +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + // TRUE is to force the frame to close + Close(TRUE); +} + +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxString msg; + msg.Printf( _T("Testing wxStyledTextCtrl...\n")); + + wxMessageBox(msg, "About This Test", wxOK | wxICON_INFORMATION, this); +} diff --git a/samples/stc/stctest.rc b/samples/stc/stctest.rc new file mode 100644 index 0000000000..b86c4e2265 --- /dev/null +++ b/samples/stc/stctest.rc @@ -0,0 +1 @@ +#include "wx/msw/wx.rc" diff --git a/src/stc/PlatWX.cpp b/src/stc/PlatWX.cpp new file mode 100644 index 0000000000..0dbd3d5ea7 --- /dev/null +++ b/src/stc/PlatWX.cpp @@ -0,0 +1,585 @@ +// Scintilla source code edit control +// PlatWX.cxx - implementation of platform facilities on wxWindows +// Copyright 1998-1999 by Neil Hodgson +// Robin Dunn +// The License.txt file describes the conditions under which this software may be distributed. + + +#include "Platform.h" +#include "wx/stc/stc.h" + +Point Point::FromLong(long lpoint) { + return Point(lpoint & 0xFFFF, lpoint >> 32); +} + +wxRect wxRectFromPRectangle(PRectangle prc) { + wxRect rc(prc.left, prc.top, + prc.right-prc.left+1, prc.bottom-prc.top+1); + return rc; +} + +PRectangle PRectangleFromwxRect(wxRect rc) { + return PRectangle(rc.GetLeft(), rc.GetTop(), rc.GetRight(), rc.GetBottom()); +} + +Colour::Colour(long lcol) { + co.Set(lcol & 0xff, (lcol >> 8) & 0xff, (lcol >> 16) & 0xff); +} + +Colour::Colour(unsigned int red, unsigned int green, unsigned int blue) { + co.Set(red, green, blue); +} + +bool Colour::operator==(const Colour &other) const { + return co == other.co; +} + +long Colour::AsLong() const { + return (((long)co.Blue() << 16) | + ((long)co.Green() << 8) | + ((long)co.Red())); +} + +unsigned int Colour::GetRed() { + return co.Red(); +} + +unsigned int Colour::GetGreen() { + return co.Green(); +} + +unsigned int Colour::GetBlue() { + return co.Blue(); +} + +Palette::Palette() { + used = 0; + allowRealization = false; +} + +Palette::~Palette() { + Release(); +} + +void Palette::Release() { + used = 0; +} + +// 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 Palette::WantFind(ColourPair &cp, bool want) { + if (want) { + for (int i=0; i < used; i++) { + if (entries[i].desired == cp.desired) + return; + } + + if (used < numEntries) { + entries[used].desired = cp.desired; + entries[used].allocated = cp.desired; + used++; + } + } else { + for (int i=0; i < used; i++) { + if (entries[i].desired == cp.desired) { + cp.allocated = entries[i].allocated; + return; + } + } + cp.allocated = cp.desired; + } +} + +void Palette::Allocate(Window &) { + if (allowRealization) { + } +} + + +Font::Font() { + id = 0; + ascent = 0; +} + +Font::~Font() { +} + +void Font::Create(const char *faceName, int size, bool bold, bool italic) { + Release(); + id = new wxFont(size, + wxDEFAULT, + italic ? wxITALIC : wxNORMAL, + bold ? wxBOLD : wxNORMAL, + false, + faceName); +} + + +void Font::Release() { + if (id) + delete id; + id = 0; +} + + +Surface::Surface() : + hdc(0), hdcOwned(0), bitmap(0), + x(0), y(0) { +} + +Surface::~Surface() { + Release(); +} + +void Surface::Release() { + if (bitmap) { + ((wxMemoryDC*)hdc)->SelectObject(wxNullBitmap); + delete bitmap; + bitmap = 0; + } + if (hdcOwned) { + delete hdc; + hdc = 0; + hdcOwned = false; + } +} + + +bool Surface::Initialised() { + return hdc != 0; +} + +void Surface::Init() { + Release(); + hdc = new wxMemoryDC(); + hdcOwned = true; + // **** ::SetTextAlign(hdc, TA_BASELINE); +} + +void Surface::Init(SurfaceID hdc_) { + Release(); + hdc = hdc_; + // **** ::SetTextAlign(hdc, TA_BASELINE); +} + +void Surface::InitPixMap(int width, int height, Surface *surface_) { + Release(); + hdc = new wxMemoryDC(surface_->hdc); + hdcOwned = true; + bitmap = new wxBitmap(width, height); + ((wxMemoryDC*)hdc)->SelectObject(*bitmap); + // **** ::SetTextAlign(hdc, TA_BASELINE); +} + +void Surface::PenColour(Colour fore) { + hdc->SetPen(wxPen(fore.co, 1, wxSOLID)); +} + +void Surface::BrushColor(Colour back) { + hdc->SetBrush(wxBrush(back.co, wxSOLID)); +} + +void Surface::SetFont(Font &font_) { + hdc->SetFont(*font_.GetID()); +} + +int Surface::LogPixelsY() { + return hdc->GetPPI().y; +} + +void Surface::MoveTo(int x_, int y_) { + x = x_; + y = y_; +} + +void Surface::LineTo(int x_, int y_) { + hdc->DrawLine(x,y, x_,y_); + x = x_; + y = y_; +} + +void Surface::Polygon(Point *pts, int npts, Colour fore, + Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawPolygon(npts, (wxPoint*)pts); +} + +void Surface::RectangleDraw(PRectangle rc, Colour fore, Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawRectangle(wxRectFromPRectangle(rc)); +} + +void Surface::FillRectangle(PRectangle rc, Colour back) { + BrushColor(back); + hdc->SetPen(*wxTRANSPARENT_PEN); + hdc->DrawRectangle(wxRectFromPRectangle(rc)); +} + +void Surface::FillRectangle(PRectangle rc, Surface &surfacePattern) { + wxBrush br; + if (surfacePattern.bitmap) + br = wxBrush(*surfacePattern.bitmap); + else // Something is wrong so display in red + br = wxBrush(*wxRED, wxSOLID); + hdc->SetPen(*wxTRANSPARENT_PEN); + hdc->SetBrush(br); + hdc->DrawRectangle(wxRectFromPRectangle(rc)); +} + +void Surface::RoundedRectangle(PRectangle rc, Colour fore, Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawRoundedRectangle(wxRectFromPRectangle(rc), 8); +} + +void Surface::Ellipse(PRectangle rc, Colour fore, Colour back) { + PenColour(fore); + BrushColor(back); + hdc->DrawEllipse(wxRectFromPRectangle(rc)); +} + +void Surface::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + hdc->Blit(rc.left, rc.top, rc.Width(), rc.Height(), + surfaceSource.hdc, from.x, from.y, wxCOPY); +} + +void Surface::DrawText(PRectangle rc, Font &font, int ybase, + const char *s, int len, Colour fore, Colour back) { + SetFont(font); + hdc->SetTextForeground(fore.co); + hdc->SetTextBackground(back.co); + FillRectangle(rc, back); + + // ybase is where the baseline should be, but wxWin uses the upper left + // corner, so I need to calculate the real position for the text... + hdc->DrawText(wxString(s, len), rc.left, ybase - font.ascent); +} + +void Surface::DrawTextClipped(PRectangle rc, Font &font, int ybase, const char *s, int len, Colour fore, Colour back) { + SetFont(font); + hdc->SetTextForeground(fore.co); + hdc->SetTextBackground(back.co); + FillRectangle(rc, back); + hdc->SetClippingRegion(wxRectFromPRectangle(rc)); + + // see comments above + hdc->DrawText(wxString(s, len), rc.left, ybase - font.ascent); + hdc->DestroyClippingRegion(); +} + +int Surface::WidthText(Font &font, const char *s, int len) { + SetFont(font); + int w; + int h; + hdc->GetTextExtent(wxString(s, len), &w, &h); + return w; +} + +void Surface::MeasureWidths(Font &font, const char *s, int len, int *positions) { + SetFont(font); + int totalWidth = 0; + for (int i=0; iGetTextExtent(s[i], &w, &h); + totalWidth += w; + positions[i] = totalWidth; + } +} + +int Surface::WidthChar(Font &font, char ch) { + SetFont(font); + int w; + int h; + hdc->GetTextExtent(ch, &w, &h); + return w; +} + +#define EXTENT_TEST " `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +int Surface::Ascent(Font &font) { + SetFont(font); + int w, h, d, e; + hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e); + font.ascent = h - d; + return font.ascent; +} + +int Surface::Descent(Font &font) { + SetFont(font); + int w, h, d, e; + hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e); + return d; +} + +int Surface::InternalLeading(Font &font) { + return 0; +} + +int Surface::ExternalLeading(Font &font) { + SetFont(font); + int w, h, d, e; + hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e); + return e; +} + +int Surface::Height(Font &font) { + SetFont(font); + return hdc->GetCharHeight(); +} + +int Surface::AverageCharWidth(Font &font) { + SetFont(font); + return hdc->GetCharWidth(); +} + +int Surface::SetPalette(Palette *pal, bool inBackGround) { + return 0; // **** figure out what to do with palettes... +} + +void Surface::SetClip(PRectangle rc) { + hdc->SetClippingRegion(wxRectFromPRectangle(rc)); +} + + + +Window::~Window() { +} + +void Window::Destroy() { + if (id) + id->Destroy(); + id = 0; +} + +bool Window::HasFocus() { + return wxWindow::FindFocus() == id; +} + +PRectangle Window::GetPosition() { + wxRect rc(id->GetPosition(), id->GetSize()); + return PRectangleFromwxRect(rc); +} + +void Window::SetPosition(PRectangle rc) { + id->SetSize(rc.left, rc.top, rc.Width(), rc.Height()); +} + +void Window::SetPositionRelative(PRectangle rc, Window) { + SetPosition(rc); // ???? +} + +PRectangle Window::GetClientPosition() { + wxSize sz = id->GetClientSize(); + return PRectangle(0, 0, sz.x - 1, sz.y - 1); +} + +void Window::Show(bool show) { + id->Show(show); +} + +void Window::InvalidateAll() { + id->Refresh(false); +} + +void Window::InvalidateRectangle(PRectangle rc) { + id->Refresh(false, &wxRectFromPRectangle(rc)); +} + +void Window::SetFont(Font &font) { + id->SetFont(*font.GetID()); +} + +void Window::SetCursor(Cursor curs) { + int cursorId; + + switch (curs) { + case cursorText: + cursorId = wxCURSOR_IBEAM; + break; + case cursorArrow: + cursorId = wxCURSOR_ARROW; + break; + case cursorUp: + cursorId = wxCURSOR_ARROW; // ** no up arrow... wxCURSOR_UPARROW; + break; + case cursorWait: + cursorId = wxCURSOR_WAIT; + break; + case cursorHoriz: + cursorId = wxCURSOR_SIZEWE; + break; + case cursorVert: + cursorId = wxCURSOR_SIZENS; + break; + case cursorReverseArrow: + cursorId = wxCURSOR_POINT_RIGHT; + break; + default: + cursorId = wxCURSOR_ARROW; + break; + } + + id->SetCursor(wxCursor(cursorId)); +} + + +void Window::SetTitle(const char *s) { + id->SetTitle(s); +} + + + +ListBox::ListBox() { +} + +ListBox::~ListBox() { +} + +void ListBox::Create(Window &parent, int ctrlID) { + id = new wxListBox(parent.id, ctrlID, wxDefaultPosition, wxDefaultSize, + 0, NULL, wxLB_SINGLE | wxLB_SORT); +} + +void ListBox::Clear() { + ((wxListBox*)id)->Clear(); +} + +void ListBox::Append(char *s) { + ((wxListBox*)id)->Append(s); +} + +int ListBox::Length() { + return ((wxListBox*)id)->Number(); +} + +void ListBox::Select(int n) { + ((wxListBox*)id)->SetSelection(n); +} + +int ListBox::GetSelection() { + return ((wxListBox*)id)->GetSelection(); +} + +int ListBox::Find(const char *prefix) { + return ((wxListBox*)id)->FindString(prefix); +} + +void ListBox::GetValue(int n, char *value, int len) { + wxString text = ((wxListBox*)id)->GetString(n); + strncpy(value, text.c_str(), len); + value[len-1] = '\0'; +} + +void ListBox::Sort() { + // wxWindows keeps sorted so no need to sort +} + + +Menu::Menu() : id(0) { +} + +void Menu::CreatePopUp() { + Destroy(); + id = new wxMenu(); +} + +void Menu::Destroy() { + if (id) + delete id; + id = 0; +} + +void Menu::Show(Point pt, Window &w) { + w.GetID()->PopupMenu(id, pt.x - 4, pt.y); + Destroy(); +} + + +Colour Platform::Chrome() { + wxColour c; + c = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE); + return Colour(c.Red(), c.Green(), c.Blue()); +} + +Colour Platform::ChromeHighlight() { + wxColour c; + c = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT); + return Colour(c.Red(), c.Green(), c.Blue()); +} + +const char *Platform::DefaultFont() { + return wxNORMAL_FONT->GetFaceName(); +} + +int Platform::DefaultFontSize() { + return 8; +} + +unsigned int Platform::DoubleClickTime() { + return 500; // **** ::GetDoubleClickTime(); +} + +void Platform::DebugDisplay(const char *s) { + wxLogDebug(s); +} + +bool Platform::IsKeyDown(int key) { + return false; // I don't think we'll need this. +} + +long Platform::SendScintilla(WindowID w, + unsigned int msg, + unsigned long wParam, + long lParam) { + + wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w; + return stc->SendMsg(msg, wParam, lParam); +} + + +// These are utility functions not really tied to a platform + +int Platform::Minimum(int a, int b) { + if (a < b) + return a; + else + return b; +} + +int Platform::Maximum(int a, int b) { + if (a > b) + return a; + else + return b; +} + +#define TRACE + +void Platform::DebugPrintf(const char *format, ...) { +#ifdef TRACE + char buffer[2000]; + va_list pArguments; + va_start(pArguments, format); + vsprintf(buffer,format,pArguments); + va_end(pArguments); + Platform::DebugDisplay(buffer); +#endif +} + +int Platform::Clamp(int val, int minVal, int maxVal) { + if (val > maxVal) + val = maxVal; + if (val < minVal) + val = minVal; + return val; +} + + + + + + diff --git a/src/stc/README.txt b/src/stc/README.txt new file mode 100644 index 0000000000..46bc58fb01 --- /dev/null +++ b/src/stc/README.txt @@ -0,0 +1,47 @@ +This contrib is the wxStyledTextCtrl, which is a wrapper around the +Scintilla edit control. (See www.scintilla.org) + +There is still VERY MUCH to be done, most notable of which is a more +advanced sample that exercises more of the code. (I havn't tested +AutoComplete or CallTips, or most of the event types at all yet.) And +also documentation, adding wrappers for some new scintilla +functionality, building and testing on wxGTK, etc. Be patient, it all +will get there soon. + + + +Let me describe a bit about the architecture I am implementing... +Obviously there is the Platform layer which implements the varioius +platform classes by using wxWindows classes and filling in where +needed. Then there is a ScintillaWX class that is derived from +ScintillaBase and implements the necessary virtual methods that +Scintilla needs to fully funciton. This class however is not meant to +ever be used directly by wx programmers. I call it one end of the +bridge between the wx and Scintilla worlds. The other end of the +bridge is a class called wxStyledTextCtrl that looks, feels and acts +like other classes in wxWindows. Here is a diagram: + + + +------------------+ +-------------------+ + | wxStyledTextCtrl |--bridge--| ScintillaWX | + +------------------+ +-------------------+ + | ScintillaBase | + +-------------------+ + | Editor | + +-------------------+ + | PlatWX | + +-------------------+ + + +wxStyledTextCtrl derives from wxControl so it has a window that can be +drawn upon. When a wxStyledTextCtrl is constructed it constructs a +ScintillaWX for itself and passes itself to the scintilla object to be +set as the wMain and wDraw attributes. All method calls on the STC +are sent over the bridge in the form of calls to ScintiallWX::WndProc. +All notifications are sent back over the bridge and turned into +wxEvents. + + +Robin + + diff --git a/src/stc/ScintillaWX.cpp b/src/stc/ScintillaWX.cpp new file mode 100644 index 0000000000..5b82473a49 --- /dev/null +++ b/src/stc/ScintillaWX.cpp @@ -0,0 +1,457 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: ScintillaWX.cxx +// Purpose: A wxWindows implementation of Scintilla. A class derived +// from ScintillaBase that uses the "wx platform" defined in +// PlatformWX.cxx This class is one end of a bridge between +// the wx world and the Scintilla world. It needs a peer +// object of type wxStyledTextCtrl to function. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#include "ScintillaWX.h" +#include "wx/stc/stc.h" + + +//---------------------------------------------------------------------- + +const int H_SCROLL_MAX = 2000; +const int H_SCROLL_STEP = 20; +const int H_SCROLL_PAGE = 200; + +//---------------------------------------------------------------------- +// Helper classes + +class wxSTCTimer : public wxTimer { +public: + wxSTCTimer(ScintillaWX* swx) { + this->swx = swx; + } + + void Notify() { + swx->DoTick(); + } + +private: + ScintillaWX* swx; +}; + + + +bool wxSTCDropTarget::OnDropText(wxCoord x, wxCoord y, const wxString& data) { + return swx->DoDropText(x, y, data); +} + +wxDragResult wxSTCDropTarget::OnEnter(wxCoord x, wxCoord y, wxDragResult def) { + return swx->DoDragEnter(x, y, def); +} + +wxDragResult wxSTCDropTarget::OnDragOver(wxCoord x, wxCoord y, wxDragResult def) { + return swx->DoDragOver(x, y, def); +} + +void wxSTCDropTarget::OnLeave() { + swx->DoDragLeave(); +} + + + +//---------------------------------------------------------------------- +// Constructor/Destructor + + +ScintillaWX::ScintillaWX(wxStyledTextCtrl* win) { + capturedMouse = false; + wMain = win; + wDraw = win; + stc = win; + Initialise(); +} + + +ScintillaWX::~ScintillaWX() { + SetTicking(false); +} + +//---------------------------------------------------------------------- +// base class virtuals + + +void ScintillaWX::Initialise() { + //ScintillaBase::Initialise(); + dropTarget.SetScintilla(this); + stc->SetDropTarget(&dropTarget); +} + + +void ScintillaWX::Finalise() { + ScintillaBase::Finalise(); +} + + +void ScintillaWX::StartDrag() { + wxDropSource source; + wxTextDataObject data(dragChars); + wxDragResult result; + + source.SetData(data); + result = source.DoDragDrop(TRUE); + if (result == wxDragMove && dropWentOutside) + ClearSelection(); + inDragDrop = FALSE; + SetDragPosition(invalidPosition); +} + + +void ScintillaWX::SetTicking(bool on) { + wxSTCTimer* steTimer; + if (timer.ticking != on) { + timer.ticking = on; + if (timer.ticking) { + steTimer = new wxSTCTimer(this); + steTimer->Start(timer.tickSize); + timer.tickerID = (int)steTimer; + } else { + steTimer = (wxSTCTimer*)timer.tickerID; + steTimer->Stop(); + delete steTimer; + timer.tickerID = 0; + } + } + timer.ticksToWait = caret.period; +} + + +void ScintillaWX::SetMouseCapture(bool on) { + if (on) + wMain.GetID()->CaptureMouse(); + else + wMain.GetID()->ReleaseMouse(); + capturedMouse = on; +} + + +bool ScintillaWX::HaveMouseCapture() { + return capturedMouse; +} + + +void ScintillaWX::ScrollText(int linesToMove) { + int dy = vs.lineHeight * (linesToMove); + // TODO: calculate the rectangle to refreshed... + wMain.GetID()->ScrollWindow(0, dy); +} + +void ScintillaWX::SetVerticalScrollPos() { + wMain.GetID()->SetScrollPos(wxVERTICAL, topLine); +} + +void ScintillaWX::SetHorizontalScrollPos() { + wMain.GetID()->SetScrollPos(wxHORIZONTAL, xOffset); +} + + +bool ScintillaWX::ModifyScrollBars(int nMax, int nPage) { + bool modified = false; + int sbMax = wMain.GetID()->GetScrollRange(wxVERTICAL); + int sbThumb = wMain.GetID()->GetScrollThumb(wxVERTICAL); + int sbPos = wMain.GetID()->GetScrollPos(wxVERTICAL); + + + if (sbMax != nMax || sbThumb != nPage) { + wMain.GetID()->SetScrollbar(wxVERTICAL, sbPos, nPage, nMax); + modified = true; + } + + sbMax = wMain.GetID()->GetScrollRange(wxHORIZONTAL); + sbThumb = wMain.GetID()->GetScrollThumb(wxHORIZONTAL); + if ((sbMax != H_SCROLL_MAX) || (sbThumb != H_SCROLL_STEP)) { + wMain.GetID()->SetScrollbar(wxHORIZONTAL, 0, H_SCROLL_STEP, H_SCROLL_MAX); + modified = true; + } + return modified; +} + + +void ScintillaWX::NotifyChange() { + stc->NotifyChange(); +} + + +void ScintillaWX::NotifyParent(SCNotification scn) { + stc->NotifyParent(&scn); +} + + + +void ScintillaWX::Copy() { + if (currentPos != anchor) { + char* text = CopySelectionRange(); + textDO.SetText(text); + wxTheClipboard->Open(); + wxTheClipboard->SetData(&textDO); + wxTheClipboard->Close(); + } +} + + +void ScintillaWX::Paste() { + pdoc->BeginUndoAction(); + ClearSelection(); + + wxTextDataObject data; + bool canPaste; + + wxTheClipboard->Open(); + canPaste = wxTheClipboard->GetData(data); + wxTheClipboard->Close(); + if (canPaste) { + wxString str = data.GetText(); + int len = str.Length(); + pdoc->InsertString(currentPos, str.c_str(), len); + SetEmptySelection(currentPos + len); + } + + pdoc->EndUndoAction(); + NotifyChange(); + Redraw(); +} + + +bool ScintillaWX::CanPaste() { + wxTextDataObject data; + bool canPaste; + + wxTheClipboard->Open(); + canPaste = wxTheClipboard->GetData(data); + wxTheClipboard->Close(); + + return canPaste; +} + +void ScintillaWX::CreateCallTipWindow(PRectangle) { + ct.wCallTip = new wxWindow(wDraw.GetID(), -1); + ct.wDraw = ct.wCallTip; +} + + +void ScintillaWX::AddToPopUp(const char *label, int cmd, bool enabled) { + if (!label[0]) + popup.GetID()->AppendSeparator(); + else + popup.GetID()->Append(cmd, label); + + if (!enabled) + popup.GetID()->Enable(cmd, enabled); + + // TODO: need to create event handler mappings for the cmd ID +} + + +void ScintillaWX::ClaimSelection() { + +} + + +LRESULT ScintillaWX::DefWndProc(UINT /*iMessage*/, WPARAM /*wParam*/, LPARAM /*lParam*/) { + return 0; +} + +LRESULT ScintillaWX::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { + switch (iMessage) { + case EM_CANPASTE: + return CanPaste(); + default: + return ScintillaBase::WndProc(iMessage, wParam, lParam); + } + return 0; +} + + + +//---------------------------------------------------------------------- +// Event delegates + +void ScintillaWX::DoPaint(wxDC* dc, wxRect rect) { + + paintState = painting; + Surface surfaceWindow; + surfaceWindow.Init(dc); + PRectangle rcPaint = PRectangleFromwxRect(rect); + dc->BeginDrawing(); + Paint(&surfaceWindow, rcPaint); + dc->EndDrawing(); + surfaceWindow.Release(); + if (paintState == paintAbandoned) { + // Painting area was insufficient to cover new styling or brace highlight positions + FullPaint(); + } + paintState = notPainting; +} + + +void ScintillaWX::DoHScroll(int type, int pos) { + int xPos = xOffset; + switch (type) { + case wxEVT_SCROLLWIN_LINEUP: + xPos -= H_SCROLL_STEP; + break; + case wxEVT_SCROLLWIN_LINEDOWN: + xPos += H_SCROLL_STEP; + break; + case wxEVT_SCROLLWIN_PAGEUP: + xPos -= H_SCROLL_PAGE; + break; + case wxEVT_SCROLLWIN_PAGEDOWN: + xPos += H_SCROLL_PAGE; + break; + case wxEVT_SCROLLWIN_TOP: + xPos = 0; + break; + case wxEVT_SCROLLWIN_BOTTOM: + xPos = H_SCROLL_MAX; + break; + case wxEVT_SCROLLWIN_THUMBTRACK: + xPos = pos; + break; + } + HorizontalScrollTo(xPos); +} + +void ScintillaWX::DoVScroll(int type, int pos) { + int topLineNew = topLine; + switch (type) { + case wxEVT_SCROLLWIN_LINEUP: + topLineNew -= 1; + break; + case wxEVT_SCROLLWIN_LINEDOWN: + topLineNew += 1; + break; + case wxEVT_SCROLLWIN_PAGEUP: + topLineNew -= LinesToScroll(); + break; + case wxEVT_SCROLLWIN_PAGEDOWN: + topLineNew += LinesToScroll(); + break; + case wxEVT_SCROLLWIN_TOP: + topLineNew = 0; + break; + case wxEVT_SCROLLWIN_BOTTOM: + topLineNew = MaxScrollPos(); + break; + case wxEVT_SCROLLWIN_THUMBTRACK: + topLineNew = pos; + break; + } + ScrollTo(topLineNew); +} + +void ScintillaWX::DoSize(int width, int height) { + PRectangle rcClient(0,0,width,height); + SetScrollBarsTo(rcClient); + DropGraphics(); +} + +void ScintillaWX::DoLoseFocus(){ + DropCaret(); +} + +void ScintillaWX::DoGainFocus(){ + ShowCaretAtCurrentPosition(); +} + +void ScintillaWX::DoSysColourChange() { + InvalidateStyleData(); +} + +void ScintillaWX::DoButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + ButtonDown(pt, curTime, shift, ctrl, alt); +} + +void ScintillaWX::DoButtonUp(Point pt, unsigned int curTime, bool ctrl) { + ButtonUp(pt, curTime, ctrl); +} + +void ScintillaWX::DoButtonMove(Point pt) { + ButtonMove(pt); +} + + +void ScintillaWX::DoAddChar(char ch) { + AddChar(ch); +} + +int ScintillaWX::DoKeyDown(int key, bool shift, bool ctrl, bool alt) { + return KeyDown(key, shift, ctrl, alt); +} + + +void ScintillaWX::DoCommand(int ID) { + Command(ID); +} + + +void ScintillaWX::DoContextMenu(Point pt) { + ContextMenu(pt); +} + + +//---------------------------------------------------------------------- + +bool ScintillaWX::DoDropText(long x, long y, const wxString& data) { + SetDragPosition(invalidPosition); + int movePos = PositionFromLocation(Point(x,y)); + DropAt(movePos, data, dragResult == wxDragMove, FALSE); // TODO: rectangular? + return TRUE; +} + + +wxDragResult ScintillaWX::DoDragEnter(wxCoord x, wxCoord y, wxDragResult def) { + return def; +} + + +wxDragResult ScintillaWX::DoDragOver(wxCoord x, wxCoord y, wxDragResult def) { + SetDragPosition(PositionFromLocation(Point(x, y))); + dragResult = def; + return def; +} + + +void ScintillaWX::DoDragLeave() { + SetDragPosition(invalidPosition); +} + +//---------------------------------------------------------------------- + +// Redraw all of text area. This paint will not be abandoned. +void ScintillaWX::FullPaint() { + paintState = painting; + rcPaint = GetTextRectangle(); + wxClientDC dc(wMain.GetID()); + Surface surfaceWindow; + surfaceWindow.Init(&dc); + Paint(&surfaceWindow, rcPaint); + surfaceWindow.Release(); + paintState = notPainting; +} + + +void ScintillaWX::DoScrollToLine(int line) { + ScrollTo(line); +} + + +void ScintillaWX::DoScrollToColumn(int column) { + HorizontalScrollTo(column * vs.spaceWidth); +} + + + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- diff --git a/src/stc/ScintillaWX.h b/src/stc/ScintillaWX.h new file mode 100644 index 0000000000..d25eb18188 --- /dev/null +++ b/src/stc/ScintillaWX.h @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: ScintillaWX.h +// Purpose: A wxWindows implementation of Scintilla. A class derived +// from ScintillaBase that uses the "wx platform" defined in +// PlatWX.cpp. This class is one end of a bridge between +// the wx world and the Scintilla world. It needs a peer +// object of type wxStyledTextCtrl to function. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __ScintillaWX_h__ +#define __ScintillaWX_h__ + +//---------------------------------------------------------------------- + +#include "Platform.h" + +#include "Scintilla.h" +#ifdef SCI_LEXER +#include "SciLexer.h" +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#endif +#include "ContractionState.h" +#include "SVector.h" +#include "CellBuffer.h" +#include "CallTip.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "AutoComplete.h" +#include "Document.h" +#include "Editor.h" +#include "ScintillaBase.h" + +#include +#include +#include +#include + +//---------------------------------------------------------------------- + +class wxStyledTextCtrl; // forward +class ScintillaWX; + + +//---------------------------------------------------------------------- +// Helper classes + +class wxSTCDropTarget : public wxTextDropTarget { +public: + void SetScintilla(ScintillaWX* swx) { + this->swx = swx; + } + + bool OnDropText(wxCoord x, wxCoord y, const wxString& data); + wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def); + wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def); + void OnLeave(); + +private: + ScintillaWX* swx; +}; + + +//---------------------------------------------------------------------- + +class ScintillaWX : public ScintillaBase { +public: + + ScintillaWX(wxStyledTextCtrl* win); + ~ScintillaWX(); + + // base class virtuals + virtual void Initialise(); + virtual void Finalise(); + virtual void StartDrag(); + virtual void SetTicking(bool on); + virtual void SetMouseCapture(bool on); + virtual bool HaveMouseCapture(); + virtual void ScrollText(int linesToMove); + virtual void SetVerticalScrollPos(); + virtual void SetHorizontalScrollPos(); + virtual bool ModifyScrollBars(int nMax, int nPage); + virtual void Copy(); + virtual void Paste(); + virtual void CreateCallTipWindow(PRectangle rc); + virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); + virtual void ClaimSelection(); + + virtual LRESULT DefWndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); + virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); + + virtual void NotifyChange(); + virtual void NotifyParent(SCNotification scn); + + + // Event delegates + void DoPaint(wxDC* dc, wxRect rect); + void DoHScroll(int type, int pos); + void DoVScroll(int type, int pos); + void DoSize(int width, int height); + void DoLoseFocus(); + void DoGainFocus(); + void DoSysColourChange(); + void DoButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); + void DoButtonUp(Point pt, unsigned int curTime, bool ctrl); + void DoButtonMove(Point pt); + void DoAddChar(char ch); + int DoKeyDown(int key, bool shift, bool ctrl, bool alt); + void DoTick() { Tick(); } + + bool DoDropText(long x, long y, const wxString& data); + wxDragResult DoDragEnter(wxCoord x, wxCoord y, wxDragResult def); + wxDragResult DoDragOver(wxCoord x, wxCoord y, wxDragResult def); + void DoDragLeave(); + + void DoCommand(int ID); + void DoContextMenu(Point pt); + + + // helpers + void FullPaint(); + bool CanPaste(); + bool GetHideSelection() { return hideSelection; } + void DoScrollToLine(int line); + void DoScrollToColumn(int column); + +private: + bool capturedMouse; + wxStyledTextCtrl* stc; + + wxTextDataObject textDO; + wxSTCDropTarget dropTarget; + wxDragResult dragResult; +}; + +//---------------------------------------------------------------------- +#endif diff --git a/src/stc/makefile.vc b/src/stc/makefile.vc new file mode 100644 index 0000000000..8e91828d3c --- /dev/null +++ b/src/stc/makefile.vc @@ -0,0 +1,106 @@ +# File: makefile.vc For stectrl +# Author: Robin Dunn +# Created: 1-Feb-2000 +# Updated: + + + +# Set WXDIR for your system +WXDIR = $(WXWIN) +SCINTILLA=.\scintilla +S=$(SCINTILLA)\src +EXTRAINC=-D__WX__ -DSCI_LEXER -I$(SCINTILLA)/include -I$(S) -I. -I$(WXDIR)\contrib\include +NOPCH=1 + +!include $(WXDIR)\src\makevc.env + +OBJECTS = \ + $(D)\Accessor.obj \ + $(D)\AutoComplete.obj \ + $(D)\CallTip.obj \ + $(D)\CellBuffer.obj \ + $(D)\ContractionState.obj\ + $(D)\Document.obj \ + $(D)\Editor.obj \ + $(D)\Indicator.obj \ + $(D)\KeyMap.obj \ + $(D)\KeyWords.obj \ + $(D)\LineMarker.obj \ + $(D)\PropSet.obj \ + $(D)\ScintillaBase.obj \ + $(D)\Style.obj \ + $(D)\ViewStyle.obj \ + \ + $(D)\PlatWX.obj \ + $(D)\ScintillaWX.obj \ + $(D)\stc.obj \ + + + + +LIBTARGET = $(WXDIR)\contrib\lib\stc$(LIBEXT).lib + +all: $(D) $(LIBTARGET) + +$(D) : + mkdir $(D) + +wx: + cd $(WXDIR)\src\msw + nmake -f makefile.vc FINAL=$(FINAL) + cd $(THISDIR) + +wxclean: + cd $(WXDIR)\src\msw + nmake -f makefile.vc clean + cd $(THISDIR) + + + + +$(LIBTARGET): $(OBJECTS) + -erase $(LIBTARGET) + $(implib) @<< +-out:$(LIBTARGET) +-machine:$(CPU) +$(OBJECTS) +<< + + +$(PROGRAM).exe: $(D)\$(PROGRAM).obj $(DUMMYOBJ) $(WXLIB) $(LIBTARGET) $(PROGRAM).res + $(link) @<< +-out:$(PROGRAM).exe +$(LINKFLAGS) +$(DUMMYOBJ) $(D)\$(PROGRAM).obj $(LIBTARGET) $(PROGRAM).res +$(LIBS) +<< + +$(PROGRAM).res : $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc + $(rc) -r /i$(WXDIR)\include -fo$@ $(PROGRAM).rc + + + +{$(S)}.cxx{$(D)}.obj: + $(cc) @<< +$(CPPFLAGS) /c /Fo$@ /Tp $< +<< + +{}.cpp{$(D)}.obj: + $(cc) @<< +$(CPPFLAGS) /c /Fo$@ /Tp $< +<< + + +show: + @echo $(CPPFLAGS) + + +clean: + -erase $(D)\*.obj + -erase *.sbr + -erase *.exe + -erase *.res + -erase *.map + -erase *.pdb + -erase $(LIBTARGET) + diff --git a/src/stc/scintilla/README.txt b/src/stc/scintilla/README.txt new file mode 100644 index 0000000000..705fb99652 --- /dev/null +++ b/src/stc/scintilla/README.txt @@ -0,0 +1,7 @@ +This directory contains copies of the scintilla/src and +scintilla/include directories from the Scintilla/SCiTE source +distribution. All other code needed to implement Scintilla on top of +wxWindows is located in the directory above this one. + +The current version of the Scintilla code is somewhere between 1.22 +and 1.23, (from their CVS.) diff --git a/src/stc/scintilla/include/Accessor.h b/src/stc/scintilla/include/Accessor.h new file mode 100644 index 0000000000..1bba4af55e --- /dev/null +++ b/src/stc/scintilla/include/Accessor.h @@ -0,0 +1,76 @@ +// SciTE - Scintilla based Text Editor +// Accessor.h - rapid easy access to contents of a Scintilla +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +class Accessor { +protected: + // bufferSize is a trade off between time taken to copy the characters and SendMessage overhead + // slopSize positions the buffer before the desired position in case there is some backtracking + enum {bufferSize=4000, slopSize=bufferSize/8}; + char buf[bufferSize+1]; + WindowID id; + PropSet &props; + int startPos; + int endPos; + int lenDoc; + int offset; // Optional but including an offset makes GCC generate better code + void Fill(int position); +public: + Accessor(WindowID id_, PropSet &props_, int offset_=0) : + id(id_), props(props_), startPos(0x7FFFFFFF), endPos(0), + lenDoc(-1), offset(offset_) { + } + char operator[](int position) { + position += offset; + if (position < startPos || position >= endPos) { + Fill(position); + } + return buf[position - startPos]; + } + char SafeGetCharAt(int position, char chDefault=' ') { + // Safe version of operator[], returning a defined value for invalid position + position += offset; + if (position < startPos || position >= endPos) { + Fill(position); + if (position < startPos || position >= endPos) { + // Position is outside range of document + return chDefault; + } + } + return buf[position - startPos]; + } + char StyleAt(int position); + int GetLine(int position); + int LineStart(int line); + int LevelAt(int line); + int Length(); + void Flush() { + startPos = 0x7FFFFFFF; + lenDoc = -1; + } + int GetLineState(int line); + int SetLineState(int line, int state); + PropSet &GetPropSet() { return props; } +}; + +class StylingContext : public Accessor { + char styleBuf[bufferSize]; + int validLen; + char chFlags; + char chWhile; + unsigned int startSeg; +public: + StylingContext(WindowID id_, PropSet &props_, int offset_=0) : + Accessor(id_,props_,offset_), validLen(0), chFlags(0) {} + void StartAt(unsigned int start, char chMask=31); + void SetFlags(char chFlags_, char chWhile_) {chFlags = chFlags_; chWhile = chWhile_; }; + void ColourSegment(unsigned int start, unsigned int end, int chAttr); + unsigned int GetStartSegment() { return startSeg; } + void StartSegment(unsigned int pos); + void ColourTo(unsigned int pos, int chAttr); + int GetLine(int position); + void SetLevel(int line, int level); + void Flush(); +}; + diff --git a/src/stc/scintilla/include/KeyWords.h b/src/stc/scintilla/include/KeyWords.h new file mode 100644 index 0000000000..2cc03b788f --- /dev/null +++ b/src/stc/scintilla/include/KeyWords.h @@ -0,0 +1,8 @@ +// SciTE - Scintilla based Text Editor +// KeyWords.h - colourise for particular languages +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +void ColouriseDoc(int codePage, int startPos, int lengthDoc, int initStyle, + int language, WordList *keywordlists[], StylingContext &styler); + diff --git a/src/stc/scintilla/include/Platform.h b/src/stc/scintilla/include/Platform.h new file mode 100644 index 0000000000..3a5e9816dc --- /dev/null +++ b/src/stc/scintilla/include/Platform.h @@ -0,0 +1,392 @@ +// Scintilla source code edit control +// 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-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PLATFORM_H +#define PLATFORM_H + +// PLAT_GTK = GTK+ on Linux, PLAT_WIN = Win32 API on Win32 OS +// PLAT_WX is wxWindows on any supported platform +// Could also have PLAT_GTKWIN = GTK+ on Win32 OS in future + +#define PLAT_GTK 0 +#define PLAT_WIN 0 +#define PLAT_WX 0 + +#if defined(__WX__) +#undef PLAT_WX +#define PLAT_WX 1 + +#elif defined(GTK) +#undef PLAT_GTK +#define PLAT_GTK 1 + +#else +#undef PLAT_WIN +#define PLAT_WIN 1 + +#endif + + +// Include the main header for each platform + +#if PLAT_GTK +#include +#include +#endif + +#if PLAT_WIN +#define _WIN32_WINNT 0x0400 // Otherwise some required stuff gets ifdef'd out +// Vassili Bourdo: shut up annoying Visual C++ warnings: +#ifdef _MSC_VER +#pragma warning(disable: 4800 4244 4309) +#endif +#include +#include +#endif + +#if PLAT_WX +#include +#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 + +#if PLAT_GTK +typedef GdkColor ColourID; +typedef GdkFont* FontID; +typedef GdkDrawable* SurfaceID; +typedef GtkWidget* WindowID; +typedef GtkItemFactory* MenuID; +#endif + +#if PLAT_WIN +typedef COLORREF ColourID; +typedef HFONT FontID; +typedef HDC SurfaceID; +typedef HWND WindowID; +typedef HMENU MenuID; +#endif + +#if PLAT_WX +typedef wxColour ColourID; +typedef wxFont* FontID; +typedef wxDC* SurfaceID; +typedef wxWindow* WindowID; +typedef wxMenu* MenuID; +#endif + +#if PLAT_GTK || PLAT_WX +#define SHIFT_PRESSED 1 +#define LEFT_CTRL_PRESSED 2 +#define LEFT_ALT_PRESSED 4 +#endif + +// Point is exactly the same as the Win32 POINT and GTK+ GdkPoint so can be used interchangeably + +class Point { +public: + int x; + int y; + + 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); +}; + +// 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 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); + } + int Width() { return right - left; } + int Height() { return bottom - top; } +}; + +#if PLAT_WX +wxRect wxRectFromPRectangle(PRectangle prc); +PRectangle PRectangleFromwxRect(wxRect rc); +#endif + +class Colour { + ColourID co; +public: + Colour(long lcol=0); + Colour(unsigned int red, unsigned int green, unsigned int blue); + bool operator==(const Colour &other) const; + long AsLong() const; + unsigned int GetRed(); + unsigned int GetGreen(); + unsigned int GetBlue(); + + friend class Surface; + friend class Palette; +}; + +// Colour pairs hold a desired colour and the colour that the graphics engine +// allocates to approximate the desired colour. +// To make palette management more automatic, ColourPairs could register at +// construction time with a palette management object. +struct ColourPair { + Colour desired; + Colour allocated; + + ColourPair(Colour desired_=Colour(0,0,0)) { + desired = desired_; + allocated = desired; + } +}; + +class Window; // Forward declaration for Palette + +class Palette { + int used; + enum {numEntries = 100}; + ColourPair entries[numEntries]; +#if PLAT_GTK + GdkColor *allocatedPalette; + int allocatedLen; +#elif PLAT_WIN + HPALETTE hpal; +#elif PLAT_WX + // wxPalette* pal; // **** Is this needed? +#endif +public: + 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); + + friend class Surface; +}; + +class Font { + 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(); + ~Font(); + + void Create(const char *faceName, int size, bool bold=false, bool italic=false); + void Release(); + + FontID GetID() { return id; } + friend class Surface; +}; + +// A surface abstracts a place to draw +class Surface { +private: +#if PLAT_GTK + GdkDrawable *drawable; + GdkGC *gc; + GdkPixmap *ppixmap; + int x; + int y; + bool inited; + bool createdGC; +#elif PLAT_WIN + HDC hdc; + bool hdcOwned; + HPEN pen; + HPEN penOld; + HBRUSH brush; + HBRUSH brushOld; + HFONT font; + HFONT fontOld; + HBITMAP bitmap; + HBITMAP bitmapOld; + HPALETTE paletteOld; +#elif PLAT_WX + wxDC* hdc; + bool hdcOwned; + wxBitmap* bitmap; + int x; + int y; +#endif + + // Private so Surface objects can not be copied + Surface(const Surface &) {} + Surface &operator=(const Surface &) { return *this; } +#if PLAT_WIN || PLAT_WX + void BrushColor(Colour back); + void SetFont(Font &font_); +#endif +public: + Surface(); + ~Surface(); + + void Init(); + void Init(SurfaceID hdc_); + void InitPixMap(int width, int height, Surface *surface_); + + void Release(); + bool Initialised(); + void PenColour(Colour fore); + int LogPixelsY(); + void MoveTo(int x_, int y_); + void LineTo(int x_, int y_); + void Polygon(Point *pts, int npts, Colour fore, Colour back); + void RectangleDraw(PRectangle rc, Colour fore, Colour back); + void FillRectangle(PRectangle rc, Colour back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, Colour fore, Colour back); + void Ellipse(PRectangle rc, Colour fore, Colour back); + void Copy(PRectangle rc, Point from, Surface &surfaceSource); + + void DrawText(PRectangle rc, Font &font_, int ybase, const char *s, int len, Colour fore, Colour back); + void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, Colour fore, Colour back); + 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_); + int ExternalLeading(Font &font_); + int Height(Font &font_); + int AverageCharWidth(Font &font_); + + int SetPalette(Palette *pal, bool inBackGround); + void SetClip(PRectangle rc); +}; + +// 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 { + friend class ListBox; +protected: + WindowID id; +public: + Window() : id(0) {} + virtual ~Window(); + Window &operator=(WindowID id_) { + id = id_; + return *this; + } + WindowID GetID() { return id; } + bool Created() { 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); + void SetFont(Font &font); + enum Cursor { cursorText, cursorArrow, cursorUp, cursorWait, cursorHoriz, cursorVert, cursorReverseArrow }; + void SetCursor(Cursor curs); + void SetTitle(const char *s); +#if PLAT_WIN + LRESULT SendMessage(UINT msg, WPARAM wParam=0, LPARAM lParam=0); + int GetDlgCtrlID(); + HINSTANCE GetInstance(); +#endif +}; + +class ListBox : public Window { +#if PLAT_GTK + WindowID list; + WindowID scroller; + int current; +#endif +public: + ListBox(); + virtual ~ListBox(); + ListBox &operator=(WindowID id_) { + id = id_; + return *this; + } + void Create(Window &parent, int ctrlID); + void Clear(); + void Append(char *s); + int Length(); + void Select(int n); + int GetSelection(); + int Find(const char *prefix); + void GetValue(int n, char *value, int len); + void Sort(); +}; + +class Menu { + MenuID id; +public: + Menu(); + MenuID GetID() { return id; } + void CreatePopUp(); + void Destroy(); + void Show(Point pt, Window &w); +}; + +// 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 Colour Chrome(); + static Colour ChromeHighlight(); + static const char *DefaultFont(); + static int DefaultFontSize(); + static unsigned int DoubleClickTime(); + 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); + + // These are utility functions not really tied to a platform + static int Minimum(int a, int b); + static int Maximum(int a, int b); + static void DebugPrintf(const char *format, ...); + static int Clamp(int val, int minVal, int maxVal); +}; + +#endif diff --git a/src/stc/scintilla/include/PropSet.h b/src/stc/scintilla/include/PropSet.h new file mode 100644 index 0000000000..31da01f954 --- /dev/null +++ b/src/stc/scintilla/include/PropSet.h @@ -0,0 +1,180 @@ +// SciTE - Scintilla based Text Editor +// PropSet.h - a java style properties file module +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef PROPSET_H +#define PROPSET_H + +bool EqualCaseInsensitive(const char *a, const char *b); + +// Define another string class. +// While it would be 'better' to use std::string, that doubles the executable size. + +inline char *StringDup(const char *s) { + if (!s) + return 0; + char *sNew = new char[strlen(s) + 1]; + if (sNew) + strcpy(sNew, s); + return sNew; +} + +class SString { + char *s; +public: + SString() { + s = 0; + } + SString(const SString &source) { + s = StringDup(source.s); + } + SString(const char *s_) { + s = StringDup(s_); + } + SString(int i) { + char number[100]; + sprintf(number, "%0d", i); + //itoa(i, number, 10); + s = StringDup(number); + } + ~SString() { + delete []s; + s = 0; + } + SString &operator=(const SString &source) { + if (this != &source) { + delete []s; + s = StringDup(source.s); + } + return *this; + } + bool operator==(const SString &other) const { + if ((s == 0) && (other.s == 0)) + return true; + if ((s == 0) || (other.s == 0)) + return false; + return strcmp(s, other.s) == 0; + } + bool operator==(const char *sother) const { + if ((s == 0) && (sother == 0)) + return true; + if ((s == 0) || (sother == 0)) + return false; + return strcmp(s, sother) == 0; + } + const char *c_str() const { + if (s) + return s; + else + return ""; + } + int length() const { + if (s) + return strlen(s); + else + return 0; + } + char operator[](int i) { + if (s) + return s[i]; + else + return '\0'; + } + SString &operator +=(const char *sother) { + int len = length(); + int lenOther = strlen(sother); + char *sNew = new char[len + lenOther + 1]; + if (sNew) { + if (s) + memcpy(sNew, s, len); + memcpy(sNew + len, sother, lenOther); + sNew[len + lenOther] = '\0'; + delete []s; + s = sNew; + } + return *this; + } + int value() { + if (s) + return atoi(s); + else + return 0; + } +}; + +class PropSet { +private: + char **vals; + int size; + int used; +public: + PropSet *superPS; + PropSet(); + ~PropSet(); + void EnsureCanAddEntry(); + void Set(const char *key, const char *val); + void Set(char *keyval); + SString Get(const char *key); + int GetInt(const char *key, int defaultValue=0); + SString GetWild(const char *keybase, const char *filename); + SString GetNewExpand(const char *keybase, const char *filename); + void Clear(); + void ReadFromMemory(const char *data, int len); + void Read(const char *filename); +}; + +// This is a fixed length list of strings suitable for display in combo boxes +// as a memory of user entries +template +class EntryMemory { + SString entries[sz]; +public: + void Insert(SString s) { + for (int i=0;i0;j--) { + entries[j] = entries[j-1]; + } + entries[0] = s; + return; + } + } + for (int k=sz-1;k>0;k--) { + entries[k] = entries[k-1]; + } + entries[0] = s; + } + int Length() const { + int len = 0; + for (int i=0;i +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCILEXER_H +#define SCILEXER_H + +// SciLexer features - not in standard Scintilla + +#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 + +// Lexical states for SCLEX_PYTHON +#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 + +// Lexical states for SCLEX_CPP, SCLEX_VB +#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_PUNTUATION 8 +#define SCE_C_PREPROCESSOR 9 +#define SCE_C_OPERATOR 10 +#define SCE_C_IDENTIFIER 11 +#define SCE_C_STRINGEOL 12 + +// Lexical states for SCLEX_HTML, SCLEX_xML +#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 +// Embedded Javascript +#define SCE_HJ_START 11 +#define SCE_HJ_DEFAULT 12 +#define SCE_HJ_COMMENT 13 +#define SCE_HJ_COMMENTLINE 14 +#define SCE_HJ_COMMENTDOC 15 +#define SCE_HJ_NUMBER 16 +#define SCE_HJ_WORD 17 +#define SCE_HJ_KEYWORD 18 +#define SCE_HJ_DOUBLESTRING 19 +#define SCE_HJ_SINGLESTRING 20 +#define SCE_HJ_SYMBOLS 21 +#define SCE_HJ_STRINGEOL 28 +// XML and ASP +#define SCE_H_TAGEND 22 +#define SCE_H_XMLSTART 23 +#define SCE_H_XMLEND 24 +#define SCE_H_SCRIPT 25 +#define SCE_H_ASP 26 +#define SCE_H_ASPAT 27 +// Embedded VBScript +#define SCE_HB_START 40 +#define SCE_HB_DEFAULT 41 +#define SCE_HB_COMMENTLINE 42 +#define SCE_HB_NUMBER 43 +#define SCE_HB_WORD 44 +#define SCE_HB_STRING 45 +#define SCE_HB_IDENTIFIER 46 +#define SCE_HB_STRINGEOL 47 +// Embedded Python +#define SCE_HP_START 50 +#define SCE_HP_DEFAULT 51 +#define SCE_HP_COMMENTLINE 52 +#define SCE_HP_NUMBER 53 +#define SCE_HP_STRING 54 +#define SCE_HP_CHARACTER 55 +#define SCE_HP_WORD 56 +#define SCE_HP_TRIPLE 57 +#define SCE_HP_TRIPLEDOUBLE 58 +#define SCE_HP_CLASSNAME 59 +#define SCE_HP_DEFNAME 60 +#define SCE_HP_OPERATOR 61 +#define SCE_HP_IDENTIFIER 62 + +// Lexical states for SCLEX_PERL +#define SCE_PL_DEFAULT 0 +#define SCE_PL_HERE 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_REF 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 + +#endif diff --git a/src/stc/scintilla/include/Scintilla.h b/src/stc/scintilla/include/Scintilla.h new file mode 100644 index 0000000000..07572168dc --- /dev/null +++ b/src/stc/scintilla/include/Scintilla.h @@ -0,0 +1,415 @@ +// Scintilla source code edit control +// Scintilla.h - interface to the edit control +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCINTILLA_H +#define SCINTILLA_H + +// Compile-time configuration options +#define MACRO_SUPPORT 1 // Comment out to remove macro hooks + +#if PLAT_GTK +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SCINTILLA(obj) GTK_CHECK_CAST (obj, scintilla_get_type (), ScintillaObject) +#define SCINTILLA_CLASS(klass) GTK_CHECK_CLASS_CAS T (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 + { + GtkFixed vbox; + void *pscin; + }; + + struct _ScintillaClass + { + GtkFixedClass parent_class; + + void (* command) (ScintillaObject *ttt); + void (* notify) (ScintillaObject *ttt); + }; + + guint scintilla_get_type (void); + GtkWidget* scintilla_new (void); + void scintilla_set_id (ScintillaObject *sci,int id); + long scintilla_send_message (ScintillaObject *sci,int iMessage,int wParam,int lParam); + +#include "WinDefs.h" + +#ifdef __cplusplus +} +#endif + +#endif + +#if PLAT_WX +#include "WinDefs.h" +#endif + +// Both GTK and Windows + +#define INVALID_POSITION -1 + +// Define start of Scintilla messages to be greater than all edit (EM_*) messages +// as many EM_ messages can be used. +#define SCI_START 2000 +#define SCI_OPTIONAL_START 3000 +#define SCI_LEXER_START 4000 + +#define SCI_ADDTEXT SCI_START + 1 +#define SCI_ADDSTYLEDTEXT SCI_START + 2 +#define SCI_INSERTTEXT SCI_START + 3 +#define SCI_CLEARALL SCI_START + 4 +#define SCI_GETLENGTH SCI_START + 6 +#define SCI_GETCHARAT SCI_START + 7 +#define SCI_GETCURRENTPOS SCI_START + 8 +#define SCI_GETANCHOR SCI_START + 9 +#define SCI_GETSTYLEAT SCI_START + 10 + +#define SCI_REDO SCI_START + 11 +#define SCI_SETUNDOCOLLECTION SCI_START + 12 +#define SCI_SELECTALL SCI_START + 13 +#define SCI_SETSAVEPOINT SCI_START + 14 +#define SCI_GETSTYLEDTEXT SCI_START + 15 +#define SCI_CANREDO SCI_START + 16 +#define SCI_MARKERLINEFROMHANDLE SCI_START + 17 +#define SCI_MARKERDELETEHANDLE SCI_START + 18 + +#define SC_UNDOCOLLECT_NONE 0 +#define SC_UNDOCOLLECT_AUTOSTART 1 + +#define SCI_GETVIEWWS SCI_START + 20 +#define SCI_SETVIEWWS SCI_START + 21 +#define SCI_CHANGEPOSITION SCI_START + 22 +#define SCI_GOTOLINE SCI_START + 24 +#define SCI_GOTOPOS SCI_START + 25 +#define SCI_SETANCHOR SCI_START + 26 +#define SCI_GETCURLINE SCI_START + 27 +#define SCI_GETENDSTYLED SCI_START + 28 +#define SCI_CONVERTEOLS SCI_START + 29 + +#define SCI_GETEOLMODE SCI_START + 30 +#define SCI_SETEOLMODE SCI_START + 31 + +#define SC_EOL_CRLF 0 +#define SC_EOL_CR 1 +#define SC_EOL_LF 2 + +#define SCI_STARTSTYLING SCI_START + 32 +#define SCI_SETSTYLING SCI_START + 33 + +#define SCI_SETBUFFEREDDRAW SCI_START + 35 +#define SCI_SETTABWIDTH SCI_START + 36 +#define SCI_SETCODEPAGE SCI_START + 37 +#define SCI_SETUSEPALETTE SCI_START + 39 + +#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 SCI_MARKERDEFINE SCI_START + 40 +#define SCI_MARKERSETFORE SCI_START + 41 +#define SCI_MARKERSETBACK SCI_START + 42 +#define SCI_MARKERADD SCI_START + 43 +#define SCI_MARKERDELETE SCI_START + 44 +#define SCI_MARKERDELETEALL SCI_START + 45 +#define SCI_MARKERGET SCI_START + 46 +#define SCI_MARKERNEXT SCI_START + 47 +#define SCI_MARKERPREVIOUS SCI_START + 48 + +#define SC_MARKNUM_FOLDER 30 +#define SC_MARKNUM_FOLDEROPEN 31 + +#define SC_MASK_FOLDERS ((1< +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef WINDEFS_H +#define WINDEFS_H + +#define WORD short +#define WPARAM unsigned long +#define LPARAM long +#define LRESULT long +#define DWORD long + +#define UINT unsigned int +#define LPSTR char * +#define LONG long + +/* RTF control */ +#define EM_CANPASTE (1074) +#define EM_CANUNDO (198) +#define EM_CHARFROMPOS (215) +#define EM_DISPLAYBAND (1075) +#define EM_EMPTYUNDOBUFFER (205) +#define EM_EXGETSEL (1076) +#define EM_EXLIMITTEXT (1077) +#define EM_EXLINEFROMCHAR (1078) +#define EM_EXSETSEL (1079) +#define EM_FINDTEXT (1080) +#define EM_FINDTEXTEX (1103) +#define EM_FINDWORDBREAK (1100) +#define EM_FMTLINES (200) +#define EM_FORMATRANGE (1081) +#define EM_GETCHARFORMAT (1082) +#define EM_GETEVENTMASK (1083) +#define EM_GETFIRSTVISIBLELINE (206) +#define EM_GETHANDLE (189) +#define EM_GETLIMITTEXT (213) +#define EM_GETLINE (196) +#define EM_GETLINECOUNT (186) +#define EM_GETMARGINS (212) +#define EM_GETMODIFY (184) +#define EM_GETIMECOLOR (1129) +#define EM_GETIMEOPTIONS (1131) +#define EM_GETOPTIONS (1102) +#define EM_GETOLEINTERFACE (1084) +#define EM_GETPARAFORMAT (1085) +#define EM_GETPASSWORDCHAR (210) +#define EM_GETPUNCTUATION (1125) +#define EM_GETRECT (178) +#define EM_GETSEL (176) +#define EM_GETSELTEXT (1086) +#define EM_GETTEXTRANGE (1099) +#define EM_GETTHUMB (190) +#define EM_GETWORDBREAKPROC (209) +#define EM_GETWORDBREAKPROCEX (1104) +#define EM_GETWORDWRAPMODE (1127) +#define EM_HIDESELECTION (1087) +#define EM_LIMITTEXT (197) +#define EM_LINEFROMCHAR (201) +#define EM_LINEINDEX (187) +#define EM_LINELENGTH (193) +#define EM_LINESCROLL (182) +#define EM_PASTESPECIAL (1088) +#define EM_POSFROMCHAR (214) +#define EM_REPLACESEL (194) +#define EM_REQUESTRESIZE (1089) +#define EM_SCROLL (181) +#define EM_SCROLLCARET (183) +#define EM_SELECTIONTYPE (1090) +#define EM_SETBKGNDCOLOR (1091) +#define EM_SETCHARFORMAT (1092) +#define EM_SETEVENTMASK (1093) +#define EM_SETHANDLE (188) +#define EM_SETIMECOLOR (1128) +#define EM_SETIMEOPTIONS (1130) +#define EM_SETLIMITTEXT (197) +#define EM_SETMARGINS (211) +#define EM_SETMODIFY (185) +#define EM_SETOLECALLBACK (1094) +#define EM_SETOPTIONS (1101) +#define EM_SETPARAFORMAT (1095) +#define EM_SETPASSWORDCHAR (204) +#define EM_SETPUNCTUATION (1124) +#define EM_SETREADONLY (207) +#define EM_SETRECT (179) +#define EM_SETRECTNP (180) +#define EM_SETSEL (177) +#define EM_SETTABSTOPS (203) +#define EM_SETTARGETDEVICE (1096) +#define EM_SETWORDBREAKPROC (208) +#define EM_SETWORDBREAKPROCEX (1105) +#define EM_SETWORDWRAPMODE (1126) +#define EM_STREAMIN (1097) +#define EM_STREAMOUT (1098) +#define EM_UNDO (199) + +#define WM_NULL (0) +#define WM_CLEAR (771) +#define WM_COMMAND (273) +#define WM_COPY (769) +#define WM_CUT (768) +#define WM_GETTEXT (13) +#define WM_GETTEXTLENGTH (14) +#define WM_NOTIFY (78) +#define WM_PASTE (770) +#define WM_SETTEXT (12) +#define WM_UNDO (772) + +#define EN_CHANGE (768) +#define EN_KILLFOCUS (512) +#define EN_SETFOCUS (256) + +#define EC_LEFTMARGIN 1 +#define EC_RIGHTMARGIN 2 +#define EC_USEFONTINFO 0xffff + +#if PLAT_GTK +#define VK_DOWN GDK_Down +#define VK_UP GDK_Up +#define VK_LEFT GDK_Left +#define VK_RIGHT GDK_Right +#define VK_HOME GDK_Home +#define VK_END GDK_End +#define VK_PRIOR GDK_Page_Up +#define VK_NEXT GDK_Page_Down +#define VK_DELETE GDK_Delete +#define VK_INSERT GDK_Insert +#define VK_ESCAPE GDK_Escape +#define VK_BACK GDK_BackSpace +#define VK_TAB GDK_Tab +#define VK_RETURN GDK_Return +#define VK_ADD GDK_KP_Add +#define VK_SUBTRACT GDK_KP_Subtract +#endif + +#if PLAT_WX +#define VK_DOWN WXK_DOWN +#define VK_UP WXK_UP +#define VK_LEFT WXK_LEFT +#define VK_RIGHT WXK_RIGHT +#define VK_HOME WXK_HOME +#define VK_END WXK_END +#define VK_PRIOR WXK_PRIOR +#define VK_NEXT WXK_NEXT +#define VK_DELETE WXK_DELETE +#define VK_INSERT WXK_INSERT +#define VK_ESCAPE WXK_ESCAPE +#define VK_BACK WXK_BACK +#define VK_TAB WXK_TAB +#define VK_RETURN WXK_RETURN +#define VK_ADD WXK_ADD +#define VK_SUBTRACT WXK_SUBTRACT + +// Are these needed any more +#define LPSTR char * +#define LONG long +#define LPDWORD (long *) +#endif + +/* SELCHANGE structure */ +#define SEL_EMPTY (0) +#define SEL_TEXT (1) +#define SEL_OBJECT (2) +#define SEL_MULTICHAR (4) +#define SEL_MULTIOBJECT (8) + +/* FINDREPLACE structure */ +#define FR_MATCHCASE (0x4) +#define FR_WHOLEWORD (0x2) +#define FR_DOWN (0x1) + +#define SHIFT_PRESSED 1 +#define LEFT_CTRL_PRESSED 2 +#define LEFT_ALT_PRESSED 4 + +struct RECT { + LONG left; + LONG top; + LONG right; + LONG bottom; +}; + +struct CHARRANGE { + LONG cpMin; + LONG cpMax; +}; + +struct TEXTRANGE { + CHARRANGE chrg; + LPSTR lpstrText; +}; + +struct FINDTEXTEX { + CHARRANGE chrg; + LPSTR lpstrText; + CHARRANGE chrgText; +}; + +struct NMHDR { + WindowID hwndFrom; + UINT idFrom; + UINT code; +}; + +struct FORMATRANGE { + SurfaceID hdc; + SurfaceID hdcTarget; + RECT rc; + RECT rcPage; + CHARRANGE chrg; +}; + +#define MAKELONG(a, b) ((a) | ((b) << 16)) +#define LOWORD(x) (x & 0xffff) +#define HIWORD(x) (x >> 16) + +#endif diff --git a/src/stc/scintilla/src/Accessor.cxx b/src/stc/scintilla/src/Accessor.cxx new file mode 100644 index 0000000000..57b7e4dc4e --- /dev/null +++ b/src/stc/scintilla/src/Accessor.cxx @@ -0,0 +1,112 @@ +// SciTE - Scintilla based Text Editor +// Accessor.cxx - rapid easy access to contents of a Scintilla +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "Scintilla.h" + +void Accessor::Fill(int position) { + if (lenDoc == -1) + lenDoc = Platform::SendScintilla(id, WM_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::SendScintilla(id, EM_GETTEXTRANGE, 0, reinterpret_cast(&tr)); +} + +char Accessor::StyleAt(int position) { + return static_cast(Platform::SendScintilla( + id, SCI_GETSTYLEAT, position, 0)); +} + +int Accessor::GetLine(int position) { + return Platform::SendScintilla(id, EM_LINEFROMCHAR, position, 0); +} + +int Accessor::LineStart(int line) { + return Platform::SendScintilla(id, EM_LINEINDEX, line, 0); +} + +int Accessor::LevelAt(int line) { + return Platform::SendScintilla(id, SCI_GETFOLDLEVEL, line, 0); +} + +int Accessor::Length() { + if (lenDoc == -1) + lenDoc = Platform::SendScintilla(id, WM_GETTEXTLENGTH, 0, 0); + return lenDoc; +} + +int Accessor::GetLineState(int line) { + return Platform::SendScintilla(id, SCI_GETLINESTATE, line); +} + +int Accessor::SetLineState(int line, int state) { + return Platform::SendScintilla(id, SCI_SETLINESTATE, line, state); +} + +void StylingContext::StartAt(unsigned int start, char chMask) { + Platform::SendScintilla(id, SCI_STARTSTYLING, start, chMask); +} + +void StylingContext::ColourSegment(unsigned int start, unsigned int end, int chAttr) { + // Only perform styling if non empty range + if (end != start - 1) { + if (end < start) { + Platform::DebugPrintf("Bad colour positions %d - %d\n", start, end); + } + + if (validLen + (end - start + 1) >= bufferSize) + Flush(); + if (validLen + (end - start + 1) >= bufferSize) { + // Too big for buffer so send directly + Platform::SendScintilla(id, SCI_SETSTYLING, end - start + 1, chAttr); + } else { + if (chAttr != chWhile) + chFlags = 0; + chAttr |= chFlags; + for (unsigned int i = start; i <= end; i++) { + styleBuf[validLen++] = chAttr; + } + } + } +} + +void StylingContext::StartSegment(unsigned int pos) { + startSeg = pos; +} + +void StylingContext::ColourTo(unsigned int pos, int chAttr) { + ColourSegment(startSeg, pos, chAttr); + startSeg = pos+1; +} + +int StylingContext::GetLine(int position) { + return Platform::SendScintilla(id, EM_LINEFROMCHAR, position, 0); +} + +void StylingContext::SetLevel(int line, int level) { + Platform::SendScintilla(id, SCI_SETFOLDLEVEL, line, level); +} + +void StylingContext::Flush() { + if (validLen > 0) { + Platform::SendScintilla(id, SCI_SETSTYLINGEX, validLen, + reinterpret_cast(styleBuf)); + validLen = 0; + } +} diff --git a/src/stc/scintilla/src/AutoComplete.cxx b/src/stc/scintilla/src/AutoComplete.cxx new file mode 100644 index 0000000000..c3ec29c3c9 --- /dev/null +++ b/src/stc/scintilla/src/AutoComplete.cxx @@ -0,0 +1,104 @@ +// Scintilla source code edit control +// AutoComplete.cxx - defines the auto completion list box +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "AutoComplete.h" + +AutoComplete::AutoComplete() { + lb = 0; + active = false; + posStart = 0; + strcpy(stopChars, ""); +} + +AutoComplete::~AutoComplete() { + lb.Destroy(); +} + +bool AutoComplete::Active() { + return active; +} + +void AutoComplete::Start(Window &parent, int ctrlID, int position, int startLen_) { + if (!lb.Created()) { + lb.Create(parent, ctrlID); + } + 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); +} + +int AutoComplete::SetList(const char *list) { + int maxStrLen = 12; + lb.Clear(); + char *words = new char[strlen(list) + 1]; + if (words) { + strcpy(words, list); + char *startword = words; + int i = 0; + for (; words && words[i]; i++) { + if (words[i] == ' ') { + words[i] = '\0'; + lb.Append(startword); + maxStrLen = Platform::Maximum(maxStrLen, strlen(startword)); + startword = words + i + 1; + } + } + if (startword) { + lb.Append(startword); + maxStrLen = Platform::Maximum(maxStrLen, strlen(startword)); + } + delete []words; + } + lb.Sort(); + return maxStrLen; +} + +void AutoComplete::Show() { + lb.Show(); + lb.Select(0); +} + +void AutoComplete::Cancel() { + if (lb.Created()) { + lb.Destroy(); + lb = 0; + 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) { + int pos = lb.Find(word); + //Platform::DebugPrintf("Autocompleting at <%s> %d\n", wordCurrent, pos); + if (pos != -1) + lb.Select(pos); +} + diff --git a/src/stc/scintilla/src/AutoComplete.h b/src/stc/scintilla/src/AutoComplete.h new file mode 100644 index 0000000000..10216027bd --- /dev/null +++ b/src/stc/scintilla/src/AutoComplete.h @@ -0,0 +1,43 @@ +// Scintilla source code edit control +// AutoComplete.h - defines the auto completion list box +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef AUTOCOMPLETE_H +#define AUTOCOMPLETE_H + +class AutoComplete { + bool active; + char stopChars[256]; +public: + ListBox lb; + int posStart; + int startLen; + + 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, int startLen_); + + // 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 list string contains a sequence of words separated by spaces + int SetList(const char *list); + + void 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); +}; + +#endif diff --git a/src/stc/scintilla/src/CallTip.cxx b/src/stc/scintilla/src/CallTip.cxx new file mode 100644 index 0000000000..ad6740208b --- /dev/null +++ b/src/stc/scintilla/src/CallTip.cxx @@ -0,0 +1,168 @@ +// Scintilla source code edit control +// CallTip.cxx - code for displaying call tips +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include "Platform.h" + +#include "CallTip.h" + +CallTip::CallTip() { + wCallTip = 0; + inCallTipMode = false; + posStartCallTip = 0; + val = 0; + startHighlight = 0; + endHighlight = 0; + + colourBG.desired = Colour(0xff, 0xff, 0xff); + colourUnSel.desired = Colour(0x80, 0x80, 0x80); + colourSel.desired = Colour(0, 0, 0x80); + colourShade.desired = Colour(0, 0, 0); + colourLight.desired = Colour(0xc0, 0xc0, 0xc0); +} + +CallTip::~CallTip() { + 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); +} + +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); + // To make a nice small call tip window, it is only sized to fit most normal characters without accents + int lineHeight = surfaceWindow->Height(font); + 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; + char *chunkVal = val; + bool moreChunks = true; + 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; + int x = 5; + int xEnd = x + surfaceWindow->WidthText(font, chunkVal, thisStartHighlight); + rcClient.left = x; + rcClient.top = ytext - ascent - 1; + rcClient.right = xEnd; + surfaceWindow->DrawText(rcClient, font, ytext, + chunkVal, thisStartHighlight, + colourUnSel.allocated, colourBG.allocated); + x = xEnd; + + xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisStartHighlight, + thisEndHighlight - thisStartHighlight); + rcClient.top = ytext; + rcClient.left = x; + rcClient.right = xEnd; + surfaceWindow->DrawText(rcClient, font, ytext, + chunkVal + thisStartHighlight, thisEndHighlight - thisStartHighlight, + colourSel.allocated, colourBG.allocated); + x = xEnd; + + xEnd = x + surfaceWindow->WidthText(font, chunkVal + thisEndHighlight, + chunkLength - thisEndHighlight); + rcClient.left = x; + rcClient.right = xEnd; + surfaceWindow->DrawText(rcClient, font, ytext, + chunkVal + thisEndHighlight, chunkLength - thisEndHighlight, + colourUnSel.allocated, colourBG.allocated); + chunkVal = chunkEnd + 1; + ytext += lineHeight; + } + // 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); +} + +PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn, + const char *faceName, int size) { + Surface surfaceMeasure; + surfaceMeasure.Init(); + int deviceHeight = (size * surfaceMeasure.LogPixelsY()) / 72; + font.Create(faceName, deviceHeight); + if (val) + delete []val; + val = new char[strlen(defn) + 1]; + if (!val) + return PRectangle(); + strcpy(val, defn); + startHighlight = 0; + endHighlight = 0; + inCallTipMode = true; + posStartCallTip = pos; + // Look for multiple lines in the text + // Only support \n here - simply means container must avoid \r! + int width = 0; + int numLines = 1; + const char *newline; + const char *look = val; + while ((newline = strchr(look, '\n')) != NULL) { + int thisWidth = surfaceMeasure.WidthText(font, look, newline - look); + width = Platform::Maximum(width, thisWidth); + look = newline + 1; + numLines++; + } + int lastWidth = surfaceMeasure.WidthText(font, look, strlen(look)); + width = Platform::Maximum(width, lastWidth) + 10; + int lineHeight = surfaceMeasure.Height(font); + // Extra line for border and an empty line at top and bottom + int height = lineHeight * numLines - surfaceMeasure.InternalLeading(font) + 2 + 2; + return PRectangle(pt.x -5, pt.y + lineHeight + 1, pt.x + width - 5, pt.y + lineHeight + 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(); + } + } +} diff --git a/src/stc/scintilla/src/CallTip.h b/src/stc/scintilla/src/CallTip.h new file mode 100644 index 0000000000..cd5b093c84 --- /dev/null +++ b/src/stc/scintilla/src/CallTip.h @@ -0,0 +1,46 @@ +// Scintilla source code edit control +// CallTip.h - interface to the call tip control +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CALLTIP_H +#define CALLTIP_H + +const char callClassName[] = "CallTip"; + +class CallTip { + int startHighlight; + int endHighlight; + char *val; + Font font; +public: + Window wCallTip; + Window wDraw; + bool inCallTipMode; + int posStartCallTip; + ColourPair colourBG; + ColourPair colourUnSel; + ColourPair colourSel; + ColourPair colourShade; + ColourPair colourLight; + + 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); + + // 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); + + 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); +}; + +#endif diff --git a/src/stc/scintilla/src/CellBuffer.cxx b/src/stc/scintilla/src/CellBuffer.cxx new file mode 100644 index 0000000000..777688511a --- /dev/null +++ b/src/stc/scintilla/src/CellBuffer.cxx @@ -0,0 +1,950 @@ +// Scintilla source code edit control +// CellBuffer.cxx - manages a buffer of cells +// Copyright 1998-2000 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 "SVector.h" +#include "CellBuffer.h" + +MarkerHandleSet::MarkerHandleSet() { + root = 0; +} + +MarkerHandleSet::~MarkerHandleSet() { + MarkerHandleNumber *mhn = root; + while (mhn) { + MarkerHandleNumber *mhnToFree = mhn; + mhn = mhn->next; + delete mhnToFree; + } + root = 0; +} + +int MarkerHandleSet::Length() { + int c = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + c++; + mhn = mhn->next; + } + return c; +} + +int MarkerHandleSet::NumberFromHandle(int handle) { + MarkerHandleNumber *mhn = root; + while (mhn) { + if (mhn->handle == handle) { + return mhn->number; + } + mhn = mhn->next; + } + return - 1; +} + +int MarkerHandleSet::MarkValue() { + unsigned int m = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + m |= (1 << mhn->number); + mhn = mhn->next; + } + return m; +} + +bool MarkerHandleSet::Contains(int handle) { + 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); + } +} + +void MarkerHandleSet::RemoveNumber(int markerNum) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + MarkerHandleNumber *mhn = *pmhn; + if (mhn->number == markerNum) { + *pmhn = mhn->next; + delete mhn; + return; + } + pmhn = &((*pmhn)->next); + } +} + +void MarkerHandleSet::CombineWith(MarkerHandleSet *other) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + pmhn = &((*pmhn)->next); + } + *pmhn = other->root; + other->root = 0; +} + +LineVector::LineVector() { + linesData = 0; + lines = 0; + levels = 0; + Init(); +} + +LineVector::~LineVector() { + for (int line = 0; line < lines; line++) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + delete []linesData; + linesData = 0; + delete []levels; + levels = 0; +} + +void LineVector::Init() { + for (int line = 0; line < lines; line++) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + delete []linesData; + linesData = new LineData[static_cast(growSize)]; + size = growSize; + lines = 1; + delete []levels; + levels = 0; + sizeLevels = 0; +} + +void LineVector::Expand(int sizeNew) { + LineData *linesDataNew = new LineData[sizeNew]; + if (linesDataNew) { + for (int i = 0; i < size; i++) + linesDataNew[i] = linesData[i]; + // Do not delete handleSets here as they are transferred to new linesData + delete []linesData; + linesData = linesDataNew; + size = sizeNew; + } else { + Platform::DebugPrintf("No memory available\n"); + // TODO: Blow up + } +} + +void LineVector::ExpandLevels(int sizeNew) { + if (sizeNew == -1) + sizeNew = size; + int *levelsNew = new int[sizeNew]; + if (levelsNew) { + int i = 0; + for (; i < sizeLevels; i++) + levelsNew[i] = levels[i]; + for (; i < sizeNew; i++) + levelsNew[i] = SC_FOLDLEVELBASE; + delete []levels; + levels = levelsNew; + sizeLevels = sizeNew; + } else { + Platform::DebugPrintf("No memory available\n"); + // TODO: Blow up + } +} + +void LineVector::InsertValue(int pos, int value) { + //Platform::DebugPrintf("InsertValue[%d] = %d\n", pos, value); + if ((lines + 2) >= size) { + Expand(size + growSize); + if (levels) { + ExpandLevels(size + growSize); + } + } + lines++; + for (int i = lines + 1; i > pos; i--) { + linesData[i] = linesData[i - 1]; + } + linesData[pos].startPosition = value; + linesData[pos].handleSet = 0; +} + +void LineVector::SetValue(int pos, int value) { + //Platform::DebugPrintf("SetValue[%d] = %d\n", pos, value); + if ((pos + 2) >= size) { + //Platform::DebugPrintf("Resize %d %d\n", size,pos); + Expand(pos + growSize); + //Platform::DebugPrintf("end Resize %d %d\n", size,pos); + lines = pos; + if (levels) { + ExpandLevels(pos + growSize); + } + } + linesData[pos].startPosition = value; +} + +void LineVector::Remove(int pos) { + //Platform::DebugPrintf("Remove %d\n", pos); + // Retain the markers from the deleted line by oring them into the previous line + if (pos > 0) { + MergeMarkers(pos - 1); + } + for (int i = pos; i < lines; i++) { + linesData[i] = linesData[i + 1]; + } + lines--; +} + +int LineVector::LineFromPosition(int pos) { + //Platform::DebugPrintf("LineFromPostion %d lines=%d end = %d\n", pos, lines, linesData[lines].startPosition); + if (lines == 0) + return 0; + //Platform::DebugPrintf("LineFromPosition %d\n", pos); + if (pos >= linesData[lines].startPosition) + return lines - 1; + int lower = 0; + int upper = lines; + int middle = 0; + do { + middle = (upper + lower + 1) / 2; // Round high + if (pos < linesData[middle].startPosition) { + upper = middle - 1; + } else { + lower = middle; + } + } while (lower < upper); + //Platform::DebugPrintf("LineFromPostion %d %d %d\n", pos, lower, linesData[lower].startPosition, linesData[lower > 1 ? lower - 1 : 0].startPosition); + return lower; +} + +int LineVector::AddMark(int line, int markerNum) { + handleCurrent++; + if (!linesData[line].handleSet) { + // Need new structure to hold marker handle + linesData[line].handleSet = new MarkerHandleSet; + if (!linesData[line].handleSet) + return - 1; + } + linesData[line].handleSet->InsertHandle(handleCurrent, markerNum); + + return handleCurrent; +} + +void LineVector::MergeMarkers(int pos) { + if (linesData[pos].handleSet || linesData[pos + 1].handleSet) { + if (linesData[pos].handleSet && linesData[pos + 1].handleSet) { + linesData[pos].handleSet->CombineWith(linesData[pos].handleSet); + linesData[pos].handleSet = 0; + } + } +} + +void LineVector::DeleteMark(int line, int markerNum) { + if (linesData[line].handleSet) { + if (markerNum == -1) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } else { + linesData[line].handleSet->RemoveNumber(markerNum); + if (linesData[line].handleSet->Length() == 0) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + } + } +} + +void LineVector::DeleteMarkFromHandle(int markerHandle) { + int line = LineFromHandle(markerHandle); + if (line >= 0) { + linesData[line].handleSet->RemoveHandle(markerHandle); + if (linesData[line].handleSet->Length() == 0) { + delete linesData[line].handleSet; + linesData[line].handleSet = 0; + } + } +} + +int LineVector::LineFromHandle(int markerHandle) { + for (int line = 0; line < lines; line++) { + if (linesData[line].handleSet) { + if (linesData[line].handleSet->Contains(markerHandle)) { + return line; + } + } + } + return - 1; +} + +Action::Action() { + at = startAction; + position = 0; + data = 0; + lenData = 0; +} + +Action::~Action() { + Destroy(); +} + +void Action::Create(actionType at_, int position_, char *data_, int lenData_) { + delete []data; + position = position_; + at = at_; + data = data_; + lenData = lenData_; +} + +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; + + // Ownership of source data transferred to this + source->position = 0; + source->at = startAction; + source->data = 0; + source->lenData = 0; +} + +CellBuffer::CellBuffer(int initialLength) { + body = new char[initialLength]; + size = initialLength; + length = 0; + part1len = 0; + gaplen = initialLength; + part2body = body + gaplen; + readOnly = false; + + lenActions = 100; + actions = new Action[lenActions]; + maxAction = 0; + currentAction = 0; + collectingUndo = undoCollectAutoStart; + undoSequenceDepth = 0; + savePoint = 0; + + actions[currentAction].Create(startAction); +} + +CellBuffer::~CellBuffer() { + delete []body; + body = 0; + delete []actions; + actions = 0; +} + +void CellBuffer::GapTo(int position) { + if (position == part1len) + return; + if (position < part1len) { + int diff = part1len - position; + //Platform::DebugPrintf("Move gap backwards to %d diff = %d part1len=%d length=%d \n", position,diff, part1len, length); + for (int i = 0; i < diff; i++) + body[part1len + gaplen - i - 1] = body[part1len - i - 1]; + } else { // position > part1len + int diff = position - part1len; + //Platform::DebugPrintf("Move gap forwards to %d diff =%d\n", position,diff); + for (int i = 0; i < diff; i++) + body[part1len + i] = body[part1len + gaplen + i]; + } + part1len = position; + part2body = body + gaplen; +} + +void CellBuffer::RoomFor(int insertionLength) { + //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength); + if (gaplen <= insertionLength) { + //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength); + GapTo(length); + int newSize = size + insertionLength + 4000; + //Platform::DebugPrintf("moved gap %d\n", newSize); + char *newBody = new char[newSize]; + memcpy(newBody, body, size); + delete []body; + body = newBody; + gaplen += newSize - size; + part2body = body + gaplen; + size = newSize; + //Platform::DebugPrintf("end need room %d %d - size=%d length=%d\n", gaplen, insertionLength,size,length); + } +} + +// To make it easier to write code that uses ByteAt, a position outside the range of the buffer +// can be retrieved. All characters outside the range have the value '\0'. +char CellBuffer::ByteAt(int position) { + if (position < part1len) { + if (position < 0) { + return '\0'; + } else { + return body[position]; + } + } else { + if (position >= length) { + return '\0'; + } else { + return part2body[position]; + } + } +} + +void CellBuffer::SetByteAt(int position, char ch) { + + if (position < 0) { + //Platform::DebugPrintf("Bad position %d\n",position); + return; + } + if (position >= length + 11) { + Platform::DebugPrintf("Very Bad position %d of %d\n", position, length); + //exit(2); + return; + } + if (position >= length) { + //Platform::DebugPrintf("Bad position %d of %d\n",position,length); + return; + } + + if (position < part1len) { + body[position] = ch; + } else { + part2body[position] = ch; + } +} + +char CellBuffer::CharAt(int position) { + return ByteAt(position*2); +} + +void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) { + if (lengthRetrieve < 0) + return; + if (position < 0) + return; + int bytePos = position * 2; + if ((bytePos + lengthRetrieve * 2) > length) { + Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n",bytePos, + lengthRetrieve, length); + return; + } + GapTo(0); // Move the buffer so its easy to subscript into it + char *pb = part2body + bytePos; + while (lengthRetrieve--) { + *buffer++ = *pb; + pb +=2; + } +} + +char CellBuffer::StyleAt(int position) { + return ByteAt(position*2 + 1); +} + +const char *CellBuffer::InsertString(int position, char *s, int insertLength) { + char *data = 0; + // InsertString and DeleteChars are the bottleneck though which all changes occur + if (!readOnly) { + if (collectingUndo) { + // Save into the undo/redo stack, but only the characters - not the formatting + // This takes up about half load time + data = new char[insertLength / 2]; + for (int i = 0; i < insertLength / 2; i++) { + data[i] = s[i * 2]; + } + AppendAction(insertAction, position, data, insertLength / 2); + } + + BasicInsertString(position, s, insertLength); + } + return data; +} + +void CellBuffer::InsertCharStyle(int position, char ch, char style) { + char s[2]; + s[0] = ch; + s[1] = style; + InsertString(position*2, s, 2); +} + +bool CellBuffer::SetStyleAt(int position, char style, char mask) { + char curVal = ByteAt(position*2 + 1); + if ((curVal & mask) != style) { + SetByteAt(position*2 + 1, (curVal & ~mask) | style); + return true; + } else { + return false; + } +} + +bool CellBuffer::SetStyleFor(int position, int lengthStyle, char style, char mask) { + int bytePos = position * 2 + 1; + bool changed = false; + while (lengthStyle--) { + char curVal = ByteAt(bytePos); + if ((curVal & mask) != style) { + SetByteAt(bytePos, (curVal & ~mask) | style); + changed = true; + } + bytePos += 2; + } + return changed; +} + +void CellBuffer::EnsureUndoRoom() { + //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, length, currentAction); + if (currentAction >= 2) { + // Have to test that there is room for 2 more actions in the array + // as two actions may be created by this 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 CellBuffer::AppendAction(actionType at, int position, char *data, int lengthData) { + EnsureUndoRoom(); + //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction); + if (currentAction >= 2) { + // See if current action can be coalesced into previous action + // Will work if both are inserts or deletes and position is same or two different + if ((at != actions[currentAction - 1].at) || (abs(position - actions[currentAction - 1].position) > 2)) { + currentAction++; + } else if (currentAction == savePoint) { + currentAction++; + } + } else { + currentAction++; + } + actions[currentAction].Create(at, position, data, lengthData); + if ((collectingUndo == undoCollectAutoStart) && (0 == undoSequenceDepth)) { + currentAction++; + actions[currentAction].Create(startAction); + } + maxAction = currentAction; +} + +const char *CellBuffer::DeleteChars(int position, int deleteLength) { + // InsertString and DeleteChars are the bottleneck though which all changes occur + char *data = 0; + if (!readOnly) { + if (collectingUndo) { + // Save into the undo/redo stack, but only the characters - not the formatting + data = new char[deleteLength / 2]; + for (int i = 0; i < deleteLength / 2; i++) { + data[i] = ByteAt(position + i * 2); + } + AppendAction(removeAction, position, data, deleteLength / 2); + } + + BasicDeleteChars(position, deleteLength); + } + return data; +} + +int CellBuffer::ByteLength() { + return length; +} + +int CellBuffer::Length() { + return ByteLength() / 2; +} + +int CellBuffer::Lines() { + //Platform::DebugPrintf("Lines = %d\n", lv.lines); + return lv.lines; +} + +int CellBuffer::LineStart(int line) { + if (line < 0) + return 0; + else if (line > lv.lines) + return length; + else + return lv.linesData[line].startPosition; +} + +bool CellBuffer::IsReadOnly() { + return readOnly; +} + +void CellBuffer::SetReadOnly(bool set) { + readOnly = set; +} + +void CellBuffer::SetSavePoint() { + savePoint = currentAction; +} + +bool CellBuffer::IsSavePoint() { + return savePoint == currentAction; +} + +int CellBuffer::AddMark(int line, int markerNum) { + if ((line >= 0) && (line < lv.lines)) { + return lv.AddMark(line, markerNum); + } + return - 1; +} + +void CellBuffer::DeleteMark(int line, int markerNum) { + if ((line >= 0) && (line < lv.lines)) { + lv.DeleteMark(line, markerNum); + } +} + +void CellBuffer::DeleteMarkFromHandle(int markerHandle) { + lv.DeleteMarkFromHandle(markerHandle); +} + +int CellBuffer::GetMark(int line) { + if ((line >= 0) && (line < lv.lines) && (lv.linesData[line].handleSet)) + return lv.linesData[line].handleSet->MarkValue(); + return 0; +} + +void CellBuffer::DeleteAllMarks(int markerNum) { + for (int line = 0; line < lv.lines; line++) { + lv.DeleteMark(line, markerNum); + } +} + +int CellBuffer::LineFromHandle(int markerHandle) { + return lv.LineFromHandle(markerHandle); +} + +// Without undo + +void CellBuffer::BasicInsertString(int position, char *s, int insertLength) { + //Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength); + if (insertLength == 0) + return; + RoomFor(insertLength); + GapTo(position); + + memcpy(body + part1len, s, insertLength); + length += insertLength; + part1len += insertLength; + gaplen -= insertLength; + part2body = body + gaplen; + + int lineInsert = lv.LineFromPosition(position / 2) + 1; + // Point all the lines after the insertion point further along in the buffer + for (int lineAfter = lineInsert; lineAfter <= lv.lines; lineAfter++) { + lv.linesData[lineAfter].startPosition += insertLength / 2; + } + char chPrev = ' '; + if ((position - 2) >= 0) + chPrev = ByteAt(position - 2); + char chAfter = ' '; + if ((position + insertLength) < length) + chAfter = ByteAt(position + insertLength); + if (chPrev == '\r' && chAfter == '\n') { + //Platform::DebugPrintf("Splitting a crlf pair at %d\n", lineInsert); + // Splitting up a crlf pair at position + lv.InsertValue(lineInsert, position / 2); + lineInsert++; + } + char ch = ' '; + for (int i = 0; i < insertLength; i += 2) { + ch = s[i]; + if (ch == '\r') { + //Platform::DebugPrintf("Inserting cr at %d\n", lineInsert); + lv.InsertValue(lineInsert, (position + i) / 2 + 1); + lineInsert++; + } else if (ch == '\n') { + if (chPrev == '\r') { + //Platform::DebugPrintf("Patching cr before lf at %d\n", lineInsert-1); + // Patch up what was end of line + lv.SetValue(lineInsert - 1, (position + i) / 2 + 1); + } else { + //Platform::DebugPrintf("Inserting lf at %d\n", lineInsert); + lv.InsertValue(lineInsert, (position + i) / 2 + 1); + lineInsert++; + } + } + chPrev = ch; + } + // Joining two lines where last insertion is cr and following text starts with lf + if (chAfter == '\n') { + if (ch == '\r') { + //Platform::DebugPrintf("Joining cr before lf at %d\n", lineInsert-1); + // End of line already in buffer so drop the newly created one + lv.Remove(lineInsert - 1); + } + } +} + +void CellBuffer::BasicDeleteChars(int position, int deleteLength) { + //Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength); + if (deleteLength == 0) + return; + + if ((position == 0) && (deleteLength == length)) { + // If whole buffer is being deleted, faster to reinitialise lines data + // than to delete each line. + //printf("Whole buffer being deleted\n"); + 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 / 2) + 1; + // Point all the lines after the insertion point further along in the buffer + for (int lineAfter = lineRemove; lineAfter <= lv.lines; lineAfter++) { + lv.linesData[lineAfter].startPosition -= deleteLength / 2; + } + char chPrev = ' '; + if (position >= 2) + chPrev = ByteAt(position - 2); + char chBefore = chPrev; + char chNext = ' '; + if (position < length) + chNext = ByteAt(position); + bool ignoreNL = false; + if (chPrev == '\r' && chNext == '\n') { + //Platform::DebugPrintf("Deleting lf after cr, move line end to cr at %d\n", lineRemove); + // Move back one + lv.SetValue(lineRemove, position / 2); + lineRemove++; + ignoreNL = true; // First \n is not real deletion + } + + char ch = chNext; + for (int i = 0; i < deleteLength; i += 2) { + chNext = ' '; + if ((position + i + 2) < length) + chNext = ByteAt(position + i + 2); + //Platform::DebugPrintf("Deleting %d %x\n", i, ch); + if (ch == '\r') { + if (chNext != '\n') { + //Platform::DebugPrintf("Removing cr end of line\n"); + lv.Remove(lineRemove); + } + } else if ((ch == '\n') && !ignoreNL) { + //Platform::DebugPrintf("Removing lf end of line\n"); + lv.Remove(lineRemove); + ignoreNL = false; // Further \n are not real deletions + } + + 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 = ' '; + if ((position + deleteLength) < length) + chAfter = ByteAt(position + deleteLength); + if (chBefore == '\r' && chAfter == '\n') { + //d.printf("Joining cr before lf at %d\n", lineRemove); + // Using lineRemove-1 as cr ended line before start of deletion + lv.Remove(lineRemove - 1); + lv.SetValue(lineRemove - 1, position / 2 + 1); + } + } + GapTo(position); + length -= deleteLength; + gaplen += deleteLength; + part2body = body + gaplen; +} + +undoCollectionType CellBuffer::SetUndoCollection(undoCollectionType collectUndo) { + collectingUndo = collectUndo; + undoSequenceDepth = 0; + return collectingUndo; +} + +bool CellBuffer::IsCollectingUndo() { + return collectingUndo; +} + +void CellBuffer::AppendUndoStartAction() { + EnsureUndoRoom(); + // Finish any currently active undo sequence + undoSequenceDepth = 0; + if (actions[currentAction].at != startAction) { + undoSequenceDepth++; + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } +} + +void CellBuffer::BeginUndoAction() { + EnsureUndoRoom(); + if (undoSequenceDepth == 0) { + if (actions[currentAction].at != startAction) { + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } + } + undoSequenceDepth++; +} + +void CellBuffer::EndUndoAction() { + EnsureUndoRoom(); + undoSequenceDepth--; + if (0 == undoSequenceDepth) { + if (actions[currentAction].at != startAction) { + currentAction++; + actions[currentAction].Create(startAction); + maxAction = currentAction; + } + } +} + +void CellBuffer::DeleteUndoHistory() { + for (int i = 1; i < maxAction; i++) + actions[i].Destroy(); + maxAction = 0; + currentAction = 0; + savePoint = 0; +} + +bool CellBuffer::CanUndo() { + return (!readOnly) && ((currentAction > 0) && (maxAction > 0)); +} + +int CellBuffer::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 &CellBuffer::UndoStep() { + const Action &actionStep = actions[currentAction]; + if (actionStep.at == insertAction) { + BasicDeleteChars(actionStep.position, actionStep.lenData*2); + } else if (actionStep.at == removeAction) { + char *styledData = new char[actionStep.lenData * 2]; + for (int i = 0; i < actionStep.lenData; i++) { + styledData[i*2] = actionStep.data[i]; + styledData[i*2+1] = 0; + } + BasicInsertString(actionStep.position, styledData, actionStep.lenData*2); + delete []styledData; + } + currentAction--; + return actionStep; +} + +bool CellBuffer::CanRedo() { + return (!readOnly) && (maxAction > currentAction); +} + +int CellBuffer::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 &CellBuffer::RedoStep() { + const Action &actionStep = actions[currentAction]; + if (actionStep.at == insertAction) { + char *styledData = new char[actionStep.lenData * 2]; + for (int i = 0; i < actionStep.lenData; i++) { + styledData[i*2] = actionStep.data[i]; + styledData[i*2+1] = 0; + } + BasicInsertString(actionStep.position, styledData, actionStep.lenData*2); + delete []styledData; + } else if (actionStep.at == removeAction) { + BasicDeleteChars(actionStep.position, actionStep.lenData*2); + } + currentAction++; + return actionStep; +} + +int CellBuffer::SetLineState(int line, int state) { + int stateOld = lineStates[line]; + lineStates[line] = state; + return stateOld; +} + +int CellBuffer::GetLineState(int line) { + return lineStates[line]; +} + +int CellBuffer::GetMaxLineState() { + return lineStates.Length(); +} + +int CellBuffer::SetLevel(int line, int level) { + int prev = 0; + if ((line >= 0) && (line < lv.lines)) { + if (!lv.levels) { + lv.ExpandLevels(); + } + prev = lv.levels[line]; + if (lv.levels[line] != level) { + lv.levels[line] = level; + } + } + return prev; +} + +int CellBuffer::GetLevel(int line) { + if (lv.levels && (line >= 0) && (line < lv.lines)) { + return lv.levels[line]; + } else { + return SC_FOLDLEVELBASE; + } +} + diff --git a/src/stc/scintilla/src/CellBuffer.h b/src/stc/scintilla/src/CellBuffer.h new file mode 100644 index 0000000000..5fbe2ea8a0 --- /dev/null +++ b/src/stc/scintilla/src/CellBuffer.h @@ -0,0 +1,197 @@ +// Scintilla source code edit control +// CellBuffer.h - manages the text of the document +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CELLBUFFER_H +#define CELLBUFFER_H + +// 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(); + int NumberFromHandle(int handle); + int MarkValue(); // Bit set of marker numbers + bool Contains(int handle); + bool InsertHandle(int handle, int markerNum); + void RemoveHandle(int handle); + void RemoveNumber(int markerNum); + void CombineWith(MarkerHandleSet *other); +}; + +// Each line stores the starting position of the first character of the line in the cell buffer +// and potentially a marker handle set. Often a line will not have any attached markers. +struct LineData { + int startPosition; + MarkerHandleSet *handleSet; + LineData() : startPosition(0), handleSet(0) { + } +}; + +// The line vector contains information about each of the lines in a cell buffer. +class LineVector { +public: + enum { growSize = 4000 }; + int lines; + LineData *linesData; + int size; + int *levels; + int sizeLevels; + + // Handles are allocated sequentially and should never have to be reused as 32 bit ints are very big. + int handleCurrent; + + LineVector(); + ~LineVector(); + void Init(); + + void Expand(int sizeNew); + void ExpandLevels(int sizeNew=-1); + void InsertValue(int pos, int value); + void SetValue(int pos, int value); + void Remove(int pos); + int LineFromPosition(int pos); + + int AddMark(int line, int marker); + void MergeMarkers(int pos); + void DeleteMark(int line, int markerNum); + void DeleteMarkFromHandle(int markerHandle); + int LineFromHandle(int markerHandle); +}; + +// Actions are used to store all the information required to perform one undo/redo step. +enum actionType { insertAction, removeAction, startAction }; + +class Action { +public: + actionType at; + int position; + char *data; + int lenData; + + Action(); + ~Action(); + void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0); + void Destroy(); + void Grab(Action *source); +}; + +enum undoCollectionType { undoCollectNone, undoCollectAutoStart, undoCollectManualStart }; + +// 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: + char *body; + int size; + int length; + int part1len; + int gaplen; + char *part2body; + bool readOnly; + + Action *actions; + int lenActions; + int maxAction; + int currentAction; + undoCollectionType collectingUndo; + int undoSequenceDepth; + int savePoint; + + LineVector lv; + + SVector lineStates; + + void GapTo(int position); + void RoomFor(int insertionLength); + + void EnsureUndoRoom(); + void AppendAction(actionType at, int position, char *data, int length); + + inline char ByteAt(int position); + void SetByteAt(int position, char ch); + +public: + + CellBuffer(int initialLength = 4000); + ~CellBuffer(); + + // Retrieving positions outside the range of the buffer works and returns 0 + char CharAt(int position); + void GetCharRange(char *buffer, int position, int lengthRetrieve); + char StyleAt(int position); + + int ByteLength(); + int Length(); + int Lines(); + int LineStart(int line); + int LineFromPosition(int pos) { return lv.LineFromPosition(pos); } + const char *InsertString(int position, char *s, int insertLength); + void InsertCharStyle(int position, char ch, char style); + + // Setting styles for positions outside the range of the buffer is safe and has no effect. + // True is returned if the style of a character changed. + bool SetStyleAt(int position, char style, char mask=(char)0xff); + bool SetStyleFor(int position, int length, char style, char mask); + + const char *DeleteChars(int position, int deleteLength); + + 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(); + + // Line marker functions + int AddMark(int line, int markerNum); + void DeleteMark(int line, int markerNum); + void DeleteMarkFromHandle(int markerHandle); + int GetMark(int line); + void DeleteAllMarks(int markerNum); + int LineFromHandle(int markerHandle); + + // Without undo + void BasicInsertString(int position, char *s, int insertLength); + void BasicDeleteChars(int position, int deleteLength); + + undoCollectionType SetUndoCollection(undoCollectionType collectUndo); + bool IsCollectingUndo(); + void AppendUndoStartAction(); + void BeginUndoAction(); + void EndUndoAction(); + void DeleteUndoHistory(); + + // To perform an undo, StartUndo is called to retreive the number of steps, then UndoStep is + // called that many times. Similarly for redo. + bool CanUndo(); + int StartUndo(); + const Action &UndoStep(); + bool CanRedo(); + int StartRedo(); + const Action &RedoStep(); + + int SetLineState(int line, int state); + int GetLineState(int line); + int GetMaxLineState(); + + int SetLevel(int line, int level); + int GetLevel(int line); +}; + +#define CELL_SIZE 2 + +#endif diff --git a/src/stc/scintilla/src/ContractionState.cxx b/src/stc/scintilla/src/ContractionState.cxx new file mode 100644 index 0000000000..6f41461eb1 --- /dev/null +++ b/src/stc/scintilla/src/ContractionState.cxx @@ -0,0 +1,203 @@ +// Scintilla source code edit control +// ContractionState.cxx - manages visibility of lines for folding +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include "Platform.h" + +#include "ContractionState.h" + +OneLine::OneLine() { + displayLine = 0; + docLine = 0; + visible = true; + expanded = true; +} + +ContractionState::ContractionState() { + lines = 0; + size = 0; + linesInDoc = 1; + linesInDisplay = 1; + valid = false; +} + +ContractionState::~ContractionState() { + Clear(); +} + +void ContractionState::MakeValid() const { + if (!valid) { + // Could be cleverer by keeping the index of the last still valid entry + // rather than invalidating all. + int linePrev = -1; + int lineDisplay = 0; + for (int line=0; line= 0) && (lineDoc < linesInDoc)) { + return lines[lineDoc].displayLine; + } + return -1; +} + +int ContractionState::DocFromDisplay(int lineDisplay) const { + if (lineDisplay <= 0) + return 0; + if (lineDisplay >= linesInDisplay) + return linesInDoc-1; + if (size == 0) + return lineDisplay; + MakeValid(); + return lines[lineDisplay].docLine; +} + +void ContractionState::Grow(int sizeNew) { + OneLine *linesNew = new OneLine[sizeNew]; + if (linesNew) { + int i = 0; + for (; i < size; i++) { + linesNew[i] = lines[i]; + } + for (; i < sizeNew; i++) { + linesNew[i].displayLine = i; + } + delete []lines; + lines = linesNew; + size = sizeNew; + valid = false; + } else { + Platform::DebugPrintf("No memory available\n"); + // TODO: Blow up + } +} + +void ContractionState::InsertLines(int lineDoc, int lineCount) { + if (size == 0) { + linesInDoc += lineCount; + linesInDisplay += lineCount; + return; + } + //Platform::DebugPrintf("InsertLine[%d] = %d\n", lineDoc); + if ((linesInDoc + 2) >= size) { + Grow(size + growSize); + } + linesInDoc += lineCount; + linesInDisplay += lineCount; + for (int i = linesInDoc + 1; i >= lineDoc + lineCount; i--) { + lines[i].visible = lines[i - lineCount].visible; + lines[i].expanded = lines[i - lineCount].expanded; + } + for (int d=0;d= 0) && (lineDoc < linesInDoc)) { + return lines[lineDoc].visible; + } else { + return false; + } +} + +bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible) { + if (size == 0) { + Grow(lineDocEnd + growSize); + } + // TODO: modify docLine members to mirror displayLine + int delta = 0; + // Change lineDocs + if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < linesInDoc)) { + for (int line=lineDocStart; line <= lineDocEnd; line++) { + if (lines[line].visible != visible) { + delta += visible ? 1 : -1; + lines[line].visible = visible; + } + lines[line].displayLine += delta; + } + if (delta != 0) { + for (int line=lineDocEnd+1; line <= linesInDoc; line++) { + lines[line].displayLine += delta; + } + } + } + linesInDisplay += delta; + valid = false; + return delta != 0; +} + +bool ContractionState::GetExpanded(int lineDoc) const { + if (size == 0) + return true; + if ((lineDoc >= 0) && (lineDoc < linesInDoc)) { + return lines[lineDoc].expanded; + } else { + return false; + } +} + +bool ContractionState::SetExpanded(int lineDoc, bool expanded) { + if (size == 0) { + Grow(lineDoc + growSize); + } + if ((lineDoc >= 0) && (lineDoc < linesInDoc)) { + if (lines[lineDoc].expanded != expanded) { + lines[lineDoc].expanded = expanded; + return true; + } + } + return false; +} diff --git a/src/stc/scintilla/src/ContractionState.h b/src/stc/scintilla/src/ContractionState.h new file mode 100644 index 0000000000..9e17a76937 --- /dev/null +++ b/src/stc/scintilla/src/ContractionState.h @@ -0,0 +1,50 @@ +// Scintilla source code edit control +// ContractionState.h - manages visibility of lines for folding +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef CONTRACTIONSTATE_H +#define CONTRACTIONSTATE_H + +class OneLine { +public: + int displayLine; // position within set of visible lines + int docLine; // inverse of displayLine + bool visible; + bool expanded; + + OneLine(); + virtual ~OneLine() {} +}; + +class ContractionState { + void Grow(int sizeNew); + enum { growSize = 4000 }; + int linesInDoc; + int linesInDisplay; + mutable OneLine *lines; + int size; + mutable bool valid; + void MakeValid() const; +public: + ContractionState(); + virtual ~ContractionState(); + + void Clear(); + + int LinesInDoc() const; + int LinesDisplayed() const; + int DisplayFromDoc(int lineDoc) const; + int DocFromDisplay(int lineDisplay) const; + + void InsertLines(int lineDoc, int lineCount); + 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); +}; + +#endif diff --git a/src/stc/scintilla/src/Document.cxx b/src/stc/scintilla/src/Document.cxx new file mode 100644 index 0000000000..7d832241fc --- /dev/null +++ b/src/stc/scintilla/src/Document.cxx @@ -0,0 +1,734 @@ +// Scintilla source code edit control +// Document.cxx - text document that handles notifications, DBCS, styling, words and end of line +// Copyright 1998-2000 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 "SVector.h" +#include "CellBuffer.h" +#include "Document.h" + +Document::Document() { + refCount = 0; +#ifdef unix + eolMode = SC_EOL_LF; +#else + eolMode = SC_EOL_CRLF; +#endif + dbcsCodePage = 0; + stylingBits = 5; + stylingBitsMask = 0x1F; + stylingPos = 0; + stylingMask = 0; + for (int ch = 0; ch < 256; ch++) { + wordchars[ch] = isalnum(ch) || ch == '_'; + } + endStyled = 0; + enteredCount = 0; + tabInChars = 8; + watchers = 0; + lenWatchers = 0; +} + +Document::~Document() { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyDeleted(this, watchers[i].userData); + } + delete []watchers; + watchers = 0; + lenWatchers = 0; +} + +// Increase reference count and return its previous value. +int Document::AddRef() { + return refCount++; +} + +// Decrease reference count and return its provius 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::LineStart(int line) { + return cb.LineStart(line); +} + +int Document::LineFromPosition(int pos) { + return cb.LineFromPosition(pos); +} + +int Document::LineEndPosition(int position) { + int line = LineFromPosition(position); + if (line == LinesTotal() - 1) { + position = LineStart(line + 1); + } else { + 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::VCHomePosition(int position) { + int line = LineFromPosition(position); + int startPosition = LineStart(line); + int endLine = LineStart(line + 1) - 1; + 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 = cb.SetLevel(line, level); + if (prev != level) { + DocModification mh(SC_MOD_CHANGEFOLD, LineStart(line), 0, 0, 0); + mh.line = line; + mh.foldLevelNow = level; + mh.foldLevelPrev = prev; + NotifyModified(mh); + } + return prev; +} + +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) && IsSubordinate(level, GetLevel(lineMaxSubord+1))) { + 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 ((lineMaxSubord > lineParent) && (GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG)) { + lineMaxSubord--; + } + } + } + return lineMaxSubord; +} + +int Document::GetFoldParent(int line) { + int level = GetLevel(line); + 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'); +} + +bool Document::IsDBCS(int pos) { +#if PLAT_WIN + if (dbcsCodePage) { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int startLine = pos; + while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') + startLine--; + while (startLine <= pos) { + if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) { + startLine++; + if (startLine >= pos) + return true; + } + startLine++; + } + } + return false; +#else + return false; +#endif +} + +// 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 value - should be fixed up after + if (pos < 0) + return pos; + if (pos > Length()) + return pos; + + // Position 0 and Length() can not be between any two characters + if (pos == 0) + return pos; + if (pos == Length()) + return pos; + + // 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 PLAT_WIN + if (dbcsCodePage) { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int startLine = pos; + while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') + startLine--; + bool atLeadByte = false; + while (startLine < pos) { + if (atLeadByte) + atLeadByte = false; + else if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) + atLeadByte = true; + else + atLeadByte = false; + startLine++; + //Platform::DebugPrintf("DBCS %s\n", atlead ? "D" : "-"); + } + + if (atLeadByte) { + // Position is between a lead byte and a trail byte + if (moveDir > 0) + return pos + 1; + else + return pos - 1; + } + } +#endif + + return pos; +} + +void Document::ModifiedAt(int pos) { + if (endStyled > pos) + endStyled = pos; +} + +// Document only modified by gateways DeleteChars, InsertStyledString, Undo, Redo, and SetStyleAt. +// SetStyleAt does not change the persistent state of a document + +// Unlike Undo, Redo, and InsertStyledString, the pos argument is a cell number not a char number +void Document::DeleteChars(int pos, int len) { + if (enteredCount == 0) { + enteredCount++; + if (cb.IsReadOnly()) + NotifyModifyAttempt(); + if (!cb.IsReadOnly()) { + int prevLinesTotal = LinesTotal(); + bool startSavePoint = cb.IsSavePoint(); + const char *text = cb.DeleteChars(pos*2, len * 2); + if (startSavePoint && cb.IsCollectingUndo()) + NotifySavePoint(!startSavePoint); + ModifiedAt(pos); + int modFlags = SC_MOD_DELETETEXT | SC_PERFORMED_USER; + DocModification mh(modFlags, pos, len, LinesTotal() - prevLinesTotal, text); + NotifyModified(mh); + } + enteredCount--; + } +} + +void Document::InsertStyledString(int position, char *s, int insertLength) { + if (enteredCount == 0) { + enteredCount++; + if (cb.IsReadOnly()) + NotifyModifyAttempt(); + if (!cb.IsReadOnly()) { + int prevLinesTotal = LinesTotal(); + bool startSavePoint = cb.IsSavePoint(); + const char *text = cb.InsertString(position, s, insertLength); + if (startSavePoint && cb.IsCollectingUndo()) + NotifySavePoint(!startSavePoint); + ModifiedAt(position / 2); + + int modFlags = SC_MOD_INSERTTEXT | SC_PERFORMED_USER; + DocModification mh(modFlags, position / 2, insertLength / 2, LinesTotal() - prevLinesTotal, text); + NotifyModified(mh); + } + enteredCount--; + } +} + +int Document::Undo() { + int newPos = 0; + if (enteredCount == 0) { + enteredCount++; + bool startSavePoint = cb.IsSavePoint(); + int steps = cb.StartUndo(); + for (int step=0; step= lineTop; line--) { + InsertChar(LineStart(line), '\t'); + } + } else { + // 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 ispc = 0; + while (ispc < tabInChars && cb.CharAt(LineStart(line) + ispc) == ' ') + ispc++; + int posStartLine = LineStart(line); + if (ispc == tabInChars) { + DeleteChars(posStartLine, ispc); + } else if (cb.CharAt(posStartLine + ispc) == '\t') { + DeleteChars(posStartLine, ispc + 1); + } else { // Hit a non-white + DeleteChars(posStartLine, ispc); + } + } + } +} + +void Document::ConvertLineEnds(int eolModeSet) { + BeginUndoAction(); + for (int pos = 0; pos < Length(); pos++) { + if (cb.CharAt(pos) == '\r') { + if (cb.CharAt(pos+1) == '\n') { + if (eolModeSet != SC_EOL_CRLF) { + DeleteChars(pos, 2); + if (eolModeSet == SC_EOL_CR) + InsertString(pos, "\r", 1); + else + InsertString(pos, "\n", 1); + } else { + pos++; + } + } else { + if (eolModeSet != SC_EOL_CR) { + DeleteChars(pos, 1); + if (eolModeSet == SC_EOL_CRLF) { + InsertString(pos, "\r\n", 2); + pos++; + } else { + InsertString(pos, "\n", 1); + } + } + } + } else if (cb.CharAt(pos) == '\n') { + if (eolModeSet != SC_EOL_LF) { + DeleteChars(pos, 1); + if (eolModeSet == SC_EOL_CRLF) { + InsertString(pos, "\r\n", 2); + pos++; + } else { + InsertString(pos, "\r", 1); + } + } + } + } + EndUndoAction(); +} + +bool Document::IsWordChar(unsigned char ch) { + return wordchars[ch]; +} + +int Document::ExtendWordSelect(int pos, int delta) { + if (delta < 0) { + while (pos > 0 && IsWordChar(cb.CharAt(pos - 1))) + pos--; + } else { + while (pos < (Length()) && IsWordChar(cb.CharAt(pos))) + pos++; + } + return pos; +} + +int Document::NextWordStart(int pos, int delta) { + if (delta < 0) { + while (pos > 0 && (cb.CharAt(pos - 1) == ' ' || cb.CharAt(pos - 1) == '\t')) + pos--; + if (isspace(cb.CharAt(pos - 1))) { // Back up to previous line + while (pos > 0 && isspace(cb.CharAt(pos - 1))) + pos--; + } else { + bool startAtWordChar = IsWordChar(cb.CharAt(pos - 1)); + while (pos > 0 && !isspace(cb.CharAt(pos - 1)) && (startAtWordChar == IsWordChar(cb.CharAt(pos - 1)))) + pos--; + } + } else { + bool startAtWordChar = IsWordChar(cb.CharAt(pos)); + while (pos < (Length()) && isspace(cb.CharAt(pos))) + pos++; + while (pos < (Length()) && !isspace(cb.CharAt(pos)) && (startAtWordChar == IsWordChar(cb.CharAt(pos)))) + pos++; + while (pos < (Length()) && (cb.CharAt(pos) == ' ' || cb.CharAt(pos) == '\t')) + pos++; + } + return pos; +} + +bool Document::IsWordAt(int start, int end) { + int lengthDoc = Length(); + if (start > 0) { + char ch = CharAt(start - 1); + if (IsWordChar(ch)) + return false; + } + if (end < lengthDoc - 1) { + char ch = CharAt(end); + if (IsWordChar(ch)) + return false; + } + return true; +} + +// 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 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 = strlen(s); + int endSearch = 0; + if (startPos <= endPos) { + endSearch = endPos - lengthFind + 1; + } else { + endSearch = endPos; + } + //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); + char firstChar = s[0]; + if (!caseSensitive) + firstChar = toupper(firstChar); + int pos = startPos; + while (forward ? (pos < endSearch) : (pos >= endSearch)) { + char ch = CharAt(pos); + if (caseSensitive) { + if (ch == firstChar) { + bool found = true; + for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { + ch = CharAt(pos + posMatch); + if (ch != s[posMatch]) + found = false; + } + if (found) { + if ((!word) || IsWordAt(pos, pos + lengthFind)) + return pos; + } + } + } else { + if (toupper(ch) == firstChar) { + bool found = true; + for (int posMatch = 1; posMatch < lengthFind && found; posMatch++) { + ch = CharAt(pos + posMatch); + if (toupper(ch) != toupper(s[posMatch])) + found = false; + } + if (found) { + if ((!word) || IsWordAt(pos, pos + lengthFind)) + return pos; + } + } + } + pos += increment; + if (dbcsCodePage) { + // Ensure trying to match from start of character + pos = MovePositionOutsideChar(pos, increment, false); + } + } + //Platform::DebugPrintf("Not found\n"); + return - 1; +} + +int Document::LinesTotal() { + return cb.Lines(); +} + +void Document::SetWordChars(unsigned char *chars) { + int ch; + for (ch = 0; ch < 256; ch++) { + wordchars[ch] = false; + } + if (chars) { + while (*chars) { + wordchars[*chars] = true; + chars++; + } + } else { + for (ch = 0; ch < 256; ch++) { + wordchars[ch] = isalnum(ch) || ch == '_'; + } + } +} + +void Document::SetStylingBits(int bits) { + stylingBits = bits; + stylingBitsMask = 0; + for (int bit=0; bitNotifyModifyAttempt(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) { + for (int i = 0; i < lenWatchers; i++) { + watchers[i].watcher->NotifyModified(this, mh, watchers[i].userData); + } +} diff --git a/src/stc/scintilla/src/Document.h b/src/stc/scintilla/src/Document.h new file mode 100644 index 0000000000..fba611c7f7 --- /dev/null +++ b/src/stc/scintilla/src/Document.h @@ -0,0 +1,222 @@ +// Scintilla source code edit control +// Document.h - text document that handles notifications, DBCS, styling, words and end of line +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef DOCUMENT_H +#define DOCUMENT_H + +// 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); + } + + bool Contains(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 { + +public: + // Used to pair watcher pointer with user data + class WatcherWithUserData { + public: + DocWatcher *watcher; + void *userData; + WatcherWithUserData() { + watcher = 0; + userData = 0; + } + }; + +private: + int refCount; + CellBuffer cb; + bool wordchars[256]; + int stylingPos; + int stylingMask; + int endStyled; + int enteredCount; + + WatcherWithUserData *watchers; + int lenWatchers; + +public: + int stylingBits; + int stylingBitsMask; + + int eolMode; + int dbcsCodePage; + int tabInChars; + + Document(); + virtual ~Document(); + + int AddRef(); + int Release(); + + int LineFromPosition(int pos); + int ClampPositionIntoDocument(int pos); + bool IsCrLf(int pos); + int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); + + // Gateways to modifying document + void DeleteChars(int pos, int len); + void InsertStyledString(int position, char *s, int insertLength); + int Undo(); + int Redo(); + bool CanUndo() { return cb.CanUndo(); } + bool CanRedo() { return cb.CanRedo(); } + void DeleteUndoHistory() { cb.DeleteUndoHistory(); } + undoCollectionType SetUndoCollection(undoCollectionType collectUndo) { + return cb.SetUndoCollection(collectUndo); + } + void AppendUndoStartAction() { cb.AppendUndoStartAction(); } + void BeginUndoAction() { cb.BeginUndoAction(); } + void EndUndoAction() { cb.EndUndoAction(); } + void SetSavePoint(); + bool IsSavePoint() { return cb.IsSavePoint(); } + void Indent(bool forwards, int lineBottom, int lineTop); + void ConvertLineEnds(int eolModeSet); + void SetReadOnly(bool set) { cb.SetReadOnly(set); } + + void InsertChar(int pos, char ch); + void InsertString(int position, const char *s); + void InsertString(int position, const char *s, int insertLength); + void DelChar(int pos); + int 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) { return cb.GetMark(line); } + int AddMark(int line, int markerNum) { return cb.AddMark(line, markerNum); } + void DeleteMark(int line, int markerNum) { cb.DeleteMark(line, markerNum); } + void DeleteMarkFromHandle(int markerHandle) { cb.DeleteMarkFromHandle(markerHandle); } + void DeleteAllMarks(int markerNum) { cb.DeleteAllMarks(markerNum); } + int LineFromHandle(int markerHandle) { return cb.LineFromHandle(markerHandle); } + int LineStart(int line); + int LineEndPosition(int position); + int VCHomePosition(int position); + + int SetLevel(int line, int level); + int GetLevel(int line) { return cb.GetLevel(line); } + int GetLastChild(int lineParent, int level=-1); + int GetFoldParent(int line); + + void Indent(bool forwards); + int ExtendWordSelect(int pos, int delta); + int NextWordStart(int pos, int delta); + int Length() { return cb.Length(); } + long FindText(int minPos, int maxPos, const char *s, bool caseSensitive, bool word); + long FindText(WORD iMessage,WPARAM wParam,LPARAM lParam); + int LinesTotal(); + + void SetWordChars(unsigned char *chars); + void SetStylingBits(int bits); + void StartStyling(int position, char mask); + void SetStyleFor(int length, char style); + void SetStyles(int length, char *styles); + int GetEndStyled() { return endStyled; } + + int SetLineState(int line, int state) { return cb.SetLineState(line, state); } + int GetLineState(int line) { return cb.GetLineState(line); } + int GetMaxLineState() { return cb.GetMaxLineState(); } + + bool AddWatcher(DocWatcher *watcher, void *userData); + bool RemoveWatcher(DocWatcher *watcher, void *userData); + const WatcherWithUserData *GetWatchers() const { return watchers; } + int GetLenWatchers() const { return lenWatchers; } + +private: + bool IsDBCS(int pos); + bool IsWordChar(unsigned char ch); + bool IsWordAt(int start, int end); + void ModifiedAt(int pos); + + 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; + + DocModification(int modificationType_, int position_=0, int length_=0, + int linesAdded_=0, const char *text_=0) : + modificationType(modificationType_), + position(position_), + length(length_), + linesAdded(linesAdded_), + text(text_), + line(0), + foldLevelNow(0), + foldLevelPrev(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; +}; + +#endif diff --git a/src/stc/scintilla/src/Editor.cxx b/src/stc/scintilla/src/Editor.cxx new file mode 100644 index 0000000000..6508c95b1f --- /dev/null +++ b/src/stc/scintilla/src/Editor.cxx @@ -0,0 +1,3693 @@ +// Scintilla source code edit control +// Editor.cxx - main code for the edit control +// Copyright 1998-2000 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 "ContractionState.h" +#include "SVector.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "Document.h" +#include "Editor.h" + +Caret::Caret() : +active(true), on(true), period(500) {} + +Timer::Timer() : +ticking(false), ticksToWait(0), tickerID(0) {} + +Editor::Editor() { + ctrlID = 0; + + stylesValid = false; + + hideSelection = false; + inOverstrike = false; + + bufferedDraw = true; + + lastClickTime = 0; + ptMouseLast.x = 0; + ptMouseLast.y = 0; + firstExpose = true; + inDragDrop = false; + dropWentOutside = false; + posDrag = invalidPosition; + posDrop = invalidPosition; + selectionType = selChar; + + lastXChosen = 0; + lineAnchor = 0; + originalAnchorPos = 0; + + dragChars = 0; + lenDrag = 0; + dragIsRectangle = false; + selType = selStream; + xStartSelect = 0; + xEndSelect = 0; + + caretPolicy = CARET_SLOP; + caretSlop = 0; + + searchAnchor = 0; + + ucWheelScrollLines = 0; + cWheelDelta = 0; //wheel delta from roll + + xOffset = 0; + xCaretMargin = 50; + + currentPos = 0; + anchor = 0; + + topLine = 0; + posTopLine = 0; + + needUpdateUI = true; + braces[0]=invalidPosition; + braces[1]=invalidPosition; + bracesMatchStyle = STYLE_BRACEBAD; + + edgeState = EDGE_NONE; + theEdge = 0; + + paintState = notPainting; + + modEventMask = SC_MODEVENTMASKALL; + + pdoc = new Document(); + pdoc ->AddRef(); + pdoc->AddWatcher(this, 0); + +#ifdef MACRO_SUPPORT + recordingMacro = 0; +#endif + foldFlags = 0; +} + +Editor::~Editor() { + pdoc->RemoveWatcher(this, 0); + pdoc->Release(); + pdoc = 0; + DropGraphics(); + + delete []dragChars; + dragChars = 0; + lenDrag = 0; +} + +void Editor::Finalise() { +} + +void Editor::DropGraphics() { + pixmapLine.Release(); + pixmapSelMargin.Release(); + pixmapSelPattern.Release(); +} + +void Editor::InvalidateStyleData() { + stylesValid = false; + palette.Release(); + DropGraphics(); +} + +void Editor::InvalidateStyleRedraw() { + InvalidateStyleData(); + Redraw(); +} + +void Editor::RefreshColourPalette(Palette &pal, bool want) { + vs.RefreshColourPalette(pal, want); +} + +void Editor::RefreshStyleData() { + if (!stylesValid) { + stylesValid = true; + Surface surface; + surface.Init(); + vs.Refresh(surface); + RefreshColourPalette(palette, true); + palette.Allocate(wMain); + RefreshColourPalette(palette, false); + SetScrollBars(); + } +} + +PRectangle Editor::GetClientRectangle() { + return wDraw.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() - LinesOnScreen(); + if (retVal < 0) + return 0; + else + return retVal; +} + +bool IsControlCharacter(char ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +const char *ControlCharacterString(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"; + } +} + +Point Editor::LocationFromPosition(unsigned int pos) { + RefreshStyleData(); + int line = pdoc->LineFromPosition(pos); + int lineVisible = cs.DisplayFromDoc(line); + //Platform::DebugPrintf("line=%d\n", line); + Surface surface; + surface.Init(); + Point pt; + pt.y = (lineVisible - topLine) * vs.lineHeight; // + half a lineheight? + unsigned int posLineStart = pdoc->LineStart(line); + if ((pos - posLineStart) > LineLayout::maxLineLength) { + // very long line so put x at arbitrary large position + pt.x = 30000 + vs.fixedColumnWidth - xOffset; + } else { + LineLayout ll; + LayoutLine(line, &surface, vs, ll); + pt.x = ll.positions[pos - posLineStart] + vs.fixedColumnWidth - xOffset; + } + return pt; +} + +int Editor::XFromPosition(unsigned 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(topLine); +} + +int Editor::PositionFromLocation(Point pt) { + RefreshStyleData(); + pt.x = pt.x - vs.fixedColumnWidth + xOffset; + int line = cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); + if (pt.y < 0) { // Division rounds towards 0 + line = cs.DocFromDisplay((pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine); + } + if (line < 0) + return 0; + if (line >= pdoc->LinesTotal()) + return pdoc->Length(); +//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); + Surface surface; + surface.Init(); + unsigned int posLineStart = pdoc->LineStart(line); + + LineLayout ll; + LayoutLine(line, &surface, vs, ll); + for (int i = 0; i < ll.numCharsInLine; i++) { + if (pt.x < ((ll.positions[i] + ll.positions[i + 1]) / 2) || + ll.chars[i] == '\r' || ll.chars[i] == '\n') { + return i + posLineStart; + } + } + + return ll.numCharsInLine + posLineStart; +} + +int Editor::PositionFromLineX(int line, int x) { + RefreshStyleData(); + if (line >= pdoc->LinesTotal()) + return pdoc->Length(); + //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); + Surface surface; + surface.Init(); + unsigned int posLineStart = pdoc->LineStart(line); + + LineLayout ll; + LayoutLine(line, &surface, vs, ll); + for (int i = 0; i < ll.numCharsInLine; i++) { + if (x < ((ll.positions[i] + ll.positions[i + 1]) / 2) || + ll.chars[i] == '\r' || ll.chars[i] == '\n') { + return i + posLineStart; + } + } + + return ll.numCharsInLine + posLineStart; +} + +void Editor::RedrawRect(PRectangle rc) { + //Platform::DebugPrintf("Redraw %d %d - %d %d\n", rc.left, rc.top, rc.right, rc.bottom); + wDraw.InvalidateRectangle(rc); +} + +void Editor::Redraw() { + //Platform::DebugPrintf("Redraw all\n"); + wDraw.InvalidateAll(); +} + +void Editor::RedrawSelMargin() { + if (vs.maskInLine) { + Redraw(); + } else { + PRectangle rcSelMargin = GetClientRectangle(); + rcSelMargin.right = vs.fixedColumnWidth; + wDraw.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 maxLine = cs.DisplayFromDoc(pdoc->LineFromPosition(maxPos)); + 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(int line) { + if ((line == -1) || (selType == selStream)) { + return Platform::Minimum(currentPos, anchor); + } else { // selType == selRectangle + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + int lineStart = pdoc->LineFromPosition(selStart); + int lineEnd = pdoc->LineFromPosition(selEnd); + if (line < lineStart || line > lineEnd) { + return -1; + } else { + int minX = Platform::Minimum(xStartSelect, xEndSelect); + //return PositionFromLineX(line, minX + vs.fixedColumnWidth - xOffset); + return PositionFromLineX(line, minX); + } + } +} + +int Editor::SelectionEnd(int line) { + if ((line == -1) || (selType == selStream)) { + return Platform::Maximum(currentPos, anchor); + } else { // selType == selRectangle + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + int lineStart = pdoc->LineFromPosition(selStart); + int lineEnd = pdoc->LineFromPosition(selEnd); + if (line < lineStart || line > lineEnd) { + return -1; + } else { + int maxX = Platform::Maximum(xStartSelect, xEndSelect); + // measure line and return character closest to minx + return PositionFromLineX(line, maxX); + } + } +} + +void Editor::SetSelection(int currentPos_, int anchor_) { + currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); + anchor_ = pdoc->ClampPositionIntoDocument(anchor_); + if ((currentPos != currentPos_) || (anchor != anchor_)) { + int firstAffected = anchor; + if (firstAffected > currentPos) + firstAffected = currentPos; + if (firstAffected > anchor_) + firstAffected = anchor_; + if (firstAffected > currentPos_) + firstAffected = currentPos_; + int lastAffected = anchor; + if (lastAffected < currentPos) + lastAffected = currentPos; + if (lastAffected < anchor_) + lastAffected = anchor_; + if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted + lastAffected = (currentPos_ + 1); + currentPos = currentPos_; + anchor = anchor_; + needUpdateUI = true; + InvalidateRange(firstAffected, lastAffected); + } + ClaimSelection(); +} + +void Editor::SetSelection(int currentPos_) { + currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); + if (currentPos != currentPos_) { + int firstAffected = anchor; + if (firstAffected > currentPos) + firstAffected = currentPos; + if (firstAffected > currentPos_) + firstAffected = currentPos_; + int lastAffected = anchor; + if (lastAffected < currentPos) + lastAffected = currentPos; + if (lastAffected < (currentPos_ + 1)) // +1 ensures caret repainted + lastAffected = (currentPos_ + 1); + currentPos = currentPos_; + needUpdateUI = true; + InvalidateRange(firstAffected, lastAffected); + } + ClaimSelection(); +} + +void Editor::SetEmptySelection(int currentPos_) { + SetSelection(currentPos_, currentPos_); +} + +int Editor::MovePositionTo(int newPos, bool extend) { + int delta = newPos - currentPos; + newPos = pdoc->ClampPositionIntoDocument(newPos); + newPos = pdoc->MovePositionOutsideChar(newPos, delta); + if (extend) { + SetSelection(newPos); + } else { + SetEmptySelection(newPos); + } + EnsureCaretVisible(); + ShowCaretAtCurrentPosition(); + return 0; +} + +int Editor::MovePositionSoVisible(int pos, int moveDir) { + pos = pdoc->ClampPositionIntoDocument(pos); + pos = pdoc->MovePositionOutsideChar(pos, moveDir); + int lineDoc = pdoc->LineFromPosition(pos); + if (cs.GetVisible(lineDoc)) { + return pos; + } else { + int lineDisplay = cs.DisplayFromDoc(lineDoc); + if (moveDir > 0) { + lineDisplay = Platform::Clamp(lineDisplay + 1, 0, cs.LinesDisplayed()); + return pdoc->LineStart(cs.DocFromDisplay(lineDisplay)); + } else { + // lineDisplay is already line before fold as lines in fold use display line of line before fold + lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); + return pdoc->LineEndPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay))); + } + } +} + +// Choose the x position that the caret will try to stick to as it is moves up and down +void Editor::SetLastXChosen() { + Point pt = LocationFromPosition(currentPos); + lastXChosen = pt.x; +} + +void Editor::ScrollTo(int line) { + 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. + if (abs(linesToMove) <= 10) { + ScrollText(linesToMove); + } else { + Redraw(); + } + 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); + xOffset = xPos; + if (xOffset < 0) + xOffset = 0; + SetHorizontalScrollPos(); + Redraw(); +} + +void Editor::EnsureCaretVisible(bool useMargin) { + //Platform::DebugPrintf("EnsureCaretVisible %d\n", xOffset); + PRectangle rcClient = GetTextRectangle(); + int posCaret = currentPos; + if (posDrag >= 0) + posCaret = posDrag; + Point pt = LocationFromPosition(posCaret); + Point ptEOL = LocationFromPosition(pdoc->LineEndPosition(posCaret)); + Point ptBottomCaret = pt; + int lineCaret = cs.DisplayFromDoc(pdoc->LineFromPosition(posCaret)); + ptBottomCaret.y += vs.lineHeight - 1; + + // Ensure the caret is reasonably visible in context. + int xMargin = Platform::Clamp(xCaretMargin, 2, Platform::Maximum(rcClient.Width() - 10, 4) / 2); + if (!useMargin) + xMargin = 2; + + // Ensure certain amount of text visible on both sides of caretSo move if caret just on edge + rcClient.left = rcClient.left + xMargin; + rcClient.right = rcClient.right - xMargin; + + if (!rcClient.Contains(pt) || !rcClient.Contains(ptBottomCaret) || (caretPolicy & CARET_STRICT)) { + //Platform::DebugPrintf("EnsureCaretVisible move, (%d,%d) (%d,%d)\n", pt.x, pt.y, rcClient.left, rcClient.right); + // It should be possible to scroll the window to show the caret, + // but this fails to remove the caret on GTK+ + if (caretPolicy & CARET_SLOP) { + if ((topLine > lineCaret) || ((caretPolicy & CARET_STRICT) && (topLine + caretSlop > lineCaret))) { + SetTopLine(Platform::Clamp(lineCaret - caretSlop, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } else if ((lineCaret > topLine + LinesOnScreen() - 1) || + ((caretPolicy & CARET_STRICT) && (lineCaret > topLine + LinesOnScreen() - 1 - caretSlop))) { + SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() + 1 + caretSlop, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + } else { + if ((topLine > lineCaret) || (lineCaret > topLine + LinesOnScreen() - 1) || (caretPolicy & CARET_STRICT)) { + SetTopLine(Platform::Clamp(lineCaret - LinesOnScreen() / 2 + 1, 0, MaxScrollPos())); + SetVerticalScrollPos(); + Redraw(); + } + } + int xOffsetNew = xOffset; + if (pt.x < rcClient.left) { + xOffsetNew = xOffset - (rcClient.left - pt.x); + } else if (pt.x >= rcClient.right) { + xOffsetNew = xOffset + (pt.x - rcClient.right); + int xOffsetEOL = xOffset + (ptEOL.x - rcClient.right) - xMargin + 2; + //Platform::DebugPrintf("Margin %d %d\n", xOffsetNew, xOffsetEOL); + // Ensure don't scroll out into empty space + if (xOffsetNew > xOffsetEOL) + xOffsetNew = xOffsetEOL; + } + if (xOffsetNew < 0) + xOffsetNew = 0; + if (xOffset != xOffsetNew) { + xOffset = xOffsetNew; + SetHorizontalScrollPos(); + Redraw(); + } + } +} + +void Editor::ShowCaretAtCurrentPosition() { + if (!wMain.HasFocus()) { + caret.active = false; + caret.on = false; + return; + } + caret.active = true; + caret.on = true; + SetTicking(true); +} + +void Editor::DropCaret() { + caret.active = false; + InvalidateCaret(); +} + +void Editor::InvalidateCaret() { + if (posDrag >= 0) + InvalidateRange(posDrag, posDrag + 1); + else + InvalidateRange(currentPos, currentPos + 1); +} + +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].symbol) { + /* 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 + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); + } else { + surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated); + } + + int visibleLine = topLine; + int line = cs.DocFromDisplay(visibleLine); + int yposScreen = 0; + + while (line < pdoc->LinesTotal() && yposScreen < rcMargin.bottom) { + int marks = pdoc->GetMark(line); + if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { + if (cs.GetExpanded(line)) { + marks |= 1 << SC_MARKNUM_FOLDEROPEN; + } else { + marks |= 1 << SC_MARKNUM_FOLDER; + } + } + marks &= vs.ms[margin].mask; + PRectangle rcMarker = rcSelMargin; + rcMarker.top = yposScreen; + rcMarker.bottom = yposScreen + vs.lineHeight; + if (!vs.ms[margin].symbol) { + char number[100]; + number[0] = '\0'; + sprintf(number, "%d", line + 1); + if (foldFlags & 8) + sprintf(number, "%X", pdoc->GetLevel(line)); + int xpos = 0; + PRectangle rcNumber=rcMarker; + // Right justify + int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, strlen(number)); + xpos = rcNumber.right - width - 3; + rcNumber.left = xpos; + if ((visibleLine < cs.LinesDisplayed()) && cs.GetVisible(line)) { + surface->DrawText(rcNumber, vs.styles[STYLE_LINENUMBER].font, + rcNumber.top + vs.maxAscent, number, strlen(number), + vs.styles[STYLE_LINENUMBER].fore.allocated, + vs.styles[STYLE_LINENUMBER].back.allocated); + } + } + + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + rcMarker.top++; + rcMarker.bottom--; + vs.markers[markBit].Draw(surface, rcMarker); + } + marks >>= 1; + } + } + + visibleLine++; + line = cs.DocFromDisplay(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 ((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); +} + +void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll) { + int numCharsInLine = 0; + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; + char styleByte = 0; + int styleMask = pdoc->stylingBitsMask; + for (int charInDoc = posLineStart; + charInDoc < posLineEnd && numCharsInLine < LineLayout::maxLineLength - 1; + charInDoc++) { + char chDoc = pdoc->CharAt(charInDoc); + styleByte = pdoc->StyleAt(charInDoc); + if (vstyle.viewEOL || ((chDoc != '\r') && (chDoc != '\n'))) { + ll.chars[numCharsInLine] = chDoc; + ll.styles[numCharsInLine] = styleByte & styleMask; + ll.indicators[numCharsInLine] = styleByte & ~styleMask; + numCharsInLine++; + } + } + ll.chars[numCharsInLine] = 0; + ll.styles[numCharsInLine] = styleByte; // For eolFilled + ll.indicators[numCharsInLine] = 0; + + // Layout the line, determining the position of each character + int startseg = 0; + int startsegx = 0; + ll.positions[0] = 0; + unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars; + + for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { + if ((ll.styles[charInLine] != ll.styles[charInLine + 1]) || + IsControlCharacter(ll.chars[charInLine]) || IsControlCharacter(ll.chars[charInLine + 1])) { + ll.positions[startseg] = 0; + if (IsControlCharacter(ll.chars[charInLine])) { + if (ll.chars[charInLine] == '\t') { + ll.positions[charInLine + 1] = ((((startsegx + 2) / + tabWidth) + 1) * tabWidth) - startsegx; + } else { + const char *ctrlChar = ControlCharacterString(ll.chars[charInLine]); + // +3 For a blank on front and rounded edge each side: + ll.positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, ctrlChar, strlen(ctrlChar)) + 3; + } + } else { + surface->MeasureWidths(vstyle.styles[ll.styles[charInLine]].font, ll.chars + startseg, + charInLine - startseg + 1, ll.positions + startseg + 1); + } + for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { + ll.positions[posToIncrease] += startsegx; + } + startsegx = ll.positions[charInLine + 1]; + startseg = charInLine + 1; + } + } + ll.numCharsInLine = numCharsInLine; +} + +void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout &ll) { + + 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; + + int marks = 0; + Colour markBack = Colour(0, 0, 0); + if (vsDraw.maskInLine) { + marks = pdoc->GetMark(line) & vsDraw.maskInLine; + if (marks) { + for (int markBit = 0; (markBit < 32) && marks; markBit++) { + if (marks & 1) { + markBack = vsDraw.markers[markBit].back.allocated; + } + marks >>= 1; + } + } + marks = pdoc->GetMark(line) & vsDraw.maskInLine; + } + + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + + int selStart = SelectionStart(line); + int selEnd = SelectionEnd(line); + + int styleMask = pdoc->stylingBitsMask; + int startseg = 0; + for (int i = 0; i < ll.numCharsInLine; i++) { + + int iDoc = i + posLineStart; + // If there is the end of a style run for any reason + if ((ll.styles[i] != ll.styles[i + 1]) || + IsControlCharacter(ll.chars[i]) || IsControlCharacter(ll.chars[i + 1]) || + ((selStart != selEnd) && ((iDoc + 1 == selStart) || (iDoc + 1 == selEnd))) || + (i == (theEdge-1))) { + int styleMain = ll.styles[i]; + Colour textBack = vsDraw.styles[styleMain].back.allocated; + Colour textFore = vsDraw.styles[styleMain].fore.allocated; + Font &textFont = vsDraw.styles[styleMain].font; + bool inSelection = (iDoc >= selStart) && (iDoc < selEnd) && (selStart != selEnd); + if (inSelection && !hideSelection) { + if (vsDraw.selbackset) + textBack = vsDraw.selbackground.allocated; + if (vsDraw.selforeset) + textFore = vsDraw.selforeground.allocated; + } else { + if (marks) + textBack = markBack; + if ((edgeState == EDGE_BACKGROUND) && (i >= theEdge) && (ll.chars[i] != '\n') && (ll.chars[i] != '\r')) + textBack = vs.edgecolour.allocated; + } + // Manage tab display + if (ll.chars[i] == '\t') { + rcSegment.left = ll.positions[i] + xStart; + rcSegment.right = ll.positions[i + 1] + xStart; + surface->FillRectangle(rcSegment, textBack); + if (vsDraw.viewWhitespace) { + surface->PenColour(textFore); + PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, + rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); + DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); + } + // Manage control character display + } else if (IsControlCharacter(ll.chars[i])) { + const char *ctrlChar = ControlCharacterString(ll.chars[i]); + rcSegment.left = ll.positions[i] + xStart; + rcSegment.right = ll.positions[i + 1] + xStart; + surface->FillRectangle(rcSegment, textBack); + 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, ctrlChar, strlen(ctrlChar), + textBack, textFore); + // Manage normal display + } else { + rcSegment.left = ll.positions[startseg] + xStart; + rcSegment.right = ll.positions[i + 1] + xStart; + // Only try do 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) { + surface->DrawText(rcSegment, textFont, + rcSegment.top + vsDraw.maxAscent, ll.chars + startseg, + i - startseg + 1, textFore, textBack); + if (vsDraw.viewWhitespace) { + for (int cpos = 0; cpos <= i - startseg; cpos++) { + if (ll.chars[cpos + startseg] == ' ') { + int xmid = (ll.positions[cpos + startseg] + ll.positions[cpos + startseg + 1]) / 2; + PRectangle rcDot(xmid + xStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); + rcDot.right = rcDot.left + 1; + rcDot.bottom = rcDot.top + 1; + surface->FillRectangle(rcDot, textFore); + } + } + } + } + } + startseg = i + 1; + } + } + + // Draw indicators + int indStart[INDIC_MAX + 1] = {0}; + for (int indica = 0; indica <= INDIC_MAX; indica++) + indStart[indica] = 0; + + for (int indicPos = 0; indicPos <= ll.numCharsInLine; indicPos++) { + if (ll.indicators[indicPos] != ll.indicators[indicPos + 1]) { + int mask = 1 << pdoc->stylingBits; + for (int indicnum = 0; mask <= 0x100; indicnum++) { + if ((ll.indicators[indicPos + 1] & mask) && !(ll.indicators[indicPos] & mask)) { + indStart[indicnum] = ll.positions[indicPos + 1]; + } + if (!(ll.indicators[indicPos + 1] & mask) && (ll.indicators[indicPos] & mask)) { + PRectangle rcIndic( + indStart[indicnum] + xStart, + rcLine.top + vsDraw.maxAscent, + ll.positions[indicPos + 1] + xStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[indicnum].Draw(surface, rcIndic); + } + mask = mask << 1; + } + } + } + // End of the drawing of the current line + + // Fill in a PRectangle representing the end of line characters + int xEol = ll.positions[ll.numCharsInLine]; + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + vsDraw.aveCharWidth + xStart; + bool eolInSelection = (posLineEnd > selStart) && (posLineEnd <= selEnd) && (selStart != selEnd); + if (eolInSelection && !hideSelection && vsDraw.selbackset && (line < pdoc->LinesTotal()-1)) { + surface->FillRectangle(rcSegment, vsDraw.selbackground.allocated); + } else if (marks) { + surface->FillRectangle(rcSegment, markBack); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[ll.styles[ll.numCharsInLine] & styleMask].back.allocated); + } + + rcSegment.left = xEol + vsDraw.aveCharWidth + xStart; + rcSegment.right = rcLine.right; + if (marks) { + surface->FillRectangle(rcSegment, markBack); + } 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 (edgeState == EDGE_LINE) { + int edgeX = theEdge * vsDraw.spaceWidth; + rcSegment.left = edgeX + xStart; + rcSegment.right = rcSegment.left + 1; + surface->FillRectangle(rcSegment, vs.edgecolour.allocated); + } +} + +void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { + //Platform::DebugPrintf("Paint %d %d - %d %d\n", rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + RefreshStyleData(); + + PRectangle rcClient = GetClientRectangle(); + //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", + // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); + + if (!pixmapSelPattern.Initialised()) { + pixmapSelPattern.InitPixMap(8, 8, surfaceWindow); + // This complex procedure is to reproduce the checker board 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, 8, 8); + if (vs.selbarlight.desired == Colour(0xff, 0xff, 0xff)) { + pixmapSelPattern.FillRectangle(rcPattern, vs.selbar.allocated); + pixmapSelPattern.PenColour(vs.selbarlight.allocated); + for (int stripe = 0; stripe < 8; stripe++) { + pixmapSelPattern.MoveTo(0, stripe * 2); + pixmapSelPattern.LineTo(8, stripe * 2 - 8); + } + } else { + // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. + pixmapSelPattern.FillRectangle(rcPattern, vs.selbarlight.allocated); + } + } + + if (bufferedDraw) { + if (!pixmapLine.Initialised()) { + pixmapLine.InitPixMap(rcClient.Width(), rcClient.Height(), + surfaceWindow); + pixmapSelMargin.InitPixMap(vs.fixedColumnWidth, + rcClient.Height(), surfaceWindow); + } + } + + surfaceWindow->SetPalette(&palette, true); + pixmapLine.SetPalette(&palette, !wMain.HasFocus()); + + //Platform::DebugPrintf("Paint: (%3d,%3d) ... (%3d,%3d)\n", + // rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); + + 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 statrting 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; + + if (endPosPaint > pdoc->GetEndStyled()) { + // Notify container to do some more styling + NotifyStyleNeeded(endPosPaint); + } + if (needUpdateUI) { + NotifyUpdateUI(); + needUpdateUI = false; + } + + 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 NotifyStyleNeeded or NotifyUpdateUI noticed that painting is needed + // outside the current painting rectangle + //Platform::DebugPrintf("Abandoning paint\n"); + return; + } + //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); + + Surface *surface = 0; + if (rcArea.right > vs.fixedColumnWidth) { + + if (bufferedDraw) { + surface = &pixmapLine; + } else { + surface = surfaceWindow; + } + + int visibleLine = topLine + screenLinePaintFirst; + int line = cs.DocFromDisplay(visibleLine); + + 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); + //GTimer *tim=g_timer_new(); + while (visibleLine <= cs.LinesDisplayed() && yposScreen < rcArea.bottom) { + //g_timer_start(tim); + //Platform::DebugPrintf("Painting line %d\n", line); + + int posLineStart = pdoc->LineStart(line); + int posLineEnd = pdoc->LineStart(line + 1); + //Platform::DebugPrintf("line %d %d - %d\n", line, posLineStart, posLineEnd); + + PRectangle rcLine = rcClient; + rcLine.top = ypos; + rcLine.bottom = ypos + vs.lineHeight; + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + LineLayout ll; + LayoutLine(line, surface, vs, ll); + + // Highlight the current braces if any + if ((braces[0] >= posLineStart) && (braces[0] < posLineEnd)) + ll.styles[braces[0] - posLineStart] = bracesMatchStyle; + if ((braces[1] >= posLineStart) && (braces[1] < posLineEnd)) + ll.styles[braces[1] - posLineStart] = bracesMatchStyle; + + // Draw the line + if (cs.GetVisible(line)) + DrawLine(surface, vs, line, xStart, rcLine, ll); + + if (foldFlags & 2) { + if (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { + PRectangle rcFoldLine = rcLine; + rcFoldLine.bottom = rcFoldLine.top + 1; + surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated); + } + } + + // Draw the Caret + if (line == lineCaret) { + int xposCaret = ll.positions[posCaret - posLineStart] + xStart; + int widthOverstrikeCaret = + ll.positions[posCaret - posLineStart + 1] - ll.positions[posCaret - posLineStart]; + if (posCaret == pdoc->Length()) // At end of document + widthOverstrikeCaret = vs.aveCharWidth; + if ((posCaret - posLineStart) >= ll.numCharsInLine) // At end of line + widthOverstrikeCaret = vs.aveCharWidth; + if (widthOverstrikeCaret < 3) // Make sure its visible + widthOverstrikeCaret = 3; + if (((caret.active && caret.on) || (posDrag >= 0)) && xposCaret >= 0) { + PRectangle rcCaret = rcLine; + if (posDrag >= 0) { + rcCaret.left = xposCaret; + rcCaret.right = xposCaret + 1; + } else { + if (inOverstrike) { + rcCaret.top = rcCaret.bottom - 2; + rcCaret.left = xposCaret + 1; + rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; + } else { + rcCaret.left = xposCaret; + rcCaret.right = xposCaret + 1; + } + } + surface->FillRectangle(rcCaret, vs.caretcolour.allocated); + } + } + + if (cs.GetVisible(line)) { + if (bufferedDraw) { + Point from(vs.fixedColumnWidth, 0); + PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen, + rcClient.right, yposScreen + vs.lineHeight); + surfaceWindow->Copy(rcCopyArea, from, pixmapLine); + } + } + + if (!bufferedDraw) { + ypos += vs.lineHeight; + } + + yposScreen += vs.lineHeight; + visibleLine++; + line = cs.DocFromDisplay(visibleLine); + //gdk_flush(); + //g_timer_stop(tim); + //Platform::DebugPrintf("Paint [%0d] took %g\n", line, g_timer_elapsed(tim, 0)); + } + //g_timer_destroy(tim); + 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 (edgeState == EDGE_LINE) { + int edgeX = theEdge * vs.spaceWidth; + rcBeyondEOF.left = edgeX + xStart; + rcBeyondEOF.right = rcBeyondEOF.left + 1; + surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated); + } + } + } +} + +// Space (3 space characters) between line numbers and text when printing. +#define lineNumberPrintSpace " " + +// 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, FORMATRANGE *pfr) { + if (!pfr) + return 0; + + Surface *surface = new Surface(); + surface->Init(pfr->hdc); + Surface *surfaceMeasure = new Surface(); + surfaceMeasure->Init(pfr->hdcTarget); + + 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].symbol) && (vsPrint.ms[margin].width > 0)) { + lineNumberIndex = margin; + } else { + vsPrint.ms[margin].width = 0; + } + } + vsPrint.showMarkedLines = false; + vsPrint.fixedColumnWidth = 0; + vsPrint.zoomLevel = 0; + // Don't show the selection when printing + vsPrint.selbackset = false; + vsPrint.selforeset = false; + // White background for the line numbers + vsPrint.styles[STYLE_LINENUMBER].back.desired = Colour(0xff,0xff,0xff); + + vsPrint.Refresh(*surfaceMeasure); + // Ensure colours are set up + vsPrint.RefreshColourPalette(palette, true); + vsPrint.RefreshColourPalette(palette, false); + // Determining width must hapen after fonts have been realised in Refresh + int lineNumberWidth = 0; + if (lineNumberIndex >= 0) { + lineNumberWidth = surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, + "9999" lineNumberPrintSpace, 4 + strlen(lineNumberPrintSpace)); + vsPrint.ms[lineNumberIndex].width = lineNumberWidth; + } + + 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 - 1); + 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); + + if (endPosPrint > pdoc->GetEndStyled()) { + // Notify container to do some more styling + NotifyStyleNeeded(endPosPrint); + } + int xStart = vsPrint.fixedColumnWidth + pfr->rc.left + lineNumberWidth; + int ypos = pfr->rc.top; + int line = linePrintStart; + + if (draw) { // Otherwise just measuring + + while (line <= linePrintLast && ypos < pfr->rc.bottom) { + + PRectangle rcLine; + rcLine.left = pfr->rc.left + lineNumberWidth; + rcLine.top = ypos; + rcLine.right = pfr->rc.right; + rcLine.bottom = ypos + vsPrint.lineHeight; + + if (lineNumberWidth) { + char number[100]; + sprintf(number, "%d" lineNumberPrintSpace, line + 1); + PRectangle rcNumber = rcLine; + rcNumber.right = rcNumber.left + lineNumberWidth; + // Right justify + rcNumber.left += lineNumberWidth - + surface->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, number, strlen(number)); + surface->DrawText(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, + ypos + vsPrint.maxAscent, number, strlen(number), + vsPrint.styles[STYLE_LINENUMBER].fore.allocated, + vsPrint.styles[STYLE_LINENUMBER].back.allocated); + } + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + LineLayout ll; + LayoutLine(line, surfaceMeasure, vsPrint, ll); + + // Draw the line + DrawLine(surface, vsPrint, line, xStart, rcLine, ll); + + ypos += vsPrint.lineHeight; + line++; + } + } + + delete surface; + delete surfaceMeasure; + + return endPosPrint; +} + +void Editor::SetScrollBarsTo(PRectangle) { + RefreshStyleData(); + + int nMax = cs.LinesDisplayed(); + int nPage = cs.LinesDisplayed() - MaxScrollPos() + 1; + bool modified = ModifyScrollBars(nMax, nPage); + + // 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) + Redraw(); + //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); +} + +void Editor::SetScrollBars() { + PRectangle rsClient = GetClientRectangle(); + SetScrollBarsTo(rsClient); +} + +void Editor::AddChar(char ch) { + bool wasSelection = currentPos != anchor; + ClearSelection(); + if (inOverstrike && !wasSelection) { + if (currentPos < (pdoc->Length() - 1)) { + if ((pdoc->CharAt(currentPos) != '\r') && (pdoc->CharAt(currentPos) != '\n')) { + pdoc->DelChar(currentPos); + } + } + } + pdoc->InsertChar(currentPos, ch); + SetEmptySelection(currentPos + 1); + EnsureCaretVisible(); + SetLastXChosen(); + NotifyChar(ch); +} + +void Editor::ClearSelection() { + if (selType == selRectangle) { + pdoc->BeginUndoAction(); + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int startPos = SelectionStart(); + int line; + for (line=lineStart; line <= lineEnd; line++) { + startPos = SelectionStart(line); + unsigned int chars = SelectionEnd(line) - startPos; + if (0 != chars) { + pdoc->DeleteChars(startPos, chars); + } + } + SetEmptySelection(startPos); + selType = selStream; + pdoc->EndUndoAction(); + } else { + int startPos = SelectionStart(); + unsigned int chars = SelectionEnd() - startPos; + SetEmptySelection(startPos); + if (0 != chars) { + pdoc->DeleteChars(startPos, chars); + } + } +} + +void Editor::ClearAll() { + if (0 != pdoc->Length()) { + pdoc->DeleteChars(0, pdoc->Length()); + } + cs.Clear(); + anchor = 0; + currentPos = 0; + SetTopLine(0); + SetVerticalScrollPos(); +} + +void Editor::Cut() { + Copy(); + ClearSelection(); +} + +void Editor::PasteRectangular(int pos, const char *ptr, int len) { + currentPos = pos; + int insertPos = currentPos; + int xInsert = XFromPosition(currentPos); + int line = pdoc->LineFromPosition(currentPos); + bool prevCr = false; + for (int i=0; i= pdoc->LinesTotal()) { + if (pdoc->eolMode != SC_EOL_LF) + pdoc->InsertChar(pdoc->Length(), '\r'); + if (pdoc->eolMode != SC_EOL_CR) + pdoc->InsertChar(pdoc->Length(), '\n'); + } + currentPos = PositionFromLineX(line, xInsert); + prevCr = ptr[i] == '\r'; + } else { + pdoc->InsertString(currentPos, ptr+i, 1); + currentPos++; + insertPos = currentPos; + prevCr = false; + } + } + SetEmptySelection(insertPos); +} + +void Editor::Clear() { + if (currentPos == anchor) { + DelChar(); + } else { + ClearSelection(); + } + SetEmptySelection(currentPos); +} + +void Editor::SelectAll() { + SetSelection(0, pdoc->Length()); + Redraw(); +} + +void Editor::Undo() { + if (pdoc->CanUndo()) { + int newPos = pdoc->Undo(); + SetEmptySelection(newPos); + EnsureCaretVisible(); + } +} + +void Editor::Redo() { + if (pdoc->CanRedo()) { + int newPos = pdoc->Redo(); + SetEmptySelection(newPos); + EnsureCaretVisible(); + } +} + +void Editor::DelChar() { + pdoc->DelChar(currentPos); +} + +void Editor::DelCharBack() { + if (currentPos == anchor) { + int newPos = pdoc->DelCharBack(currentPos); + SetEmptySelection(newPos); + } else { + ClearSelection(); + SetEmptySelection(currentPos); + } +} + +void Editor::NotifyFocus(bool) { +} + +void Editor::NotifyStyleNeeded(int endStyleNeeded) { + SCNotification scn; + scn.nmhdr.code = SCN_STYLENEEDED; + scn.position = endStyleNeeded; + NotifyParent(scn); +} + +void Editor::NotifyChar(char ch) { + SCNotification scn; + scn.nmhdr.code = SCN_CHARADDED; + scn.ch = ch; + NotifyParent(scn); +#ifdef MACRO_SUPPORT + if (recordingMacro) { + char txt[2]; + txt[0] = ch; + txt[1] = '\0'; + NotifyMacroRecord(EM_REPLACESEL, 0, (LPARAM) txt); + } +#endif +} + +void Editor::NotifySavePoint(bool isSavePoint) { + SCNotification scn; + if (isSavePoint) { + scn.nmhdr.code = SCN_SAVEPOINTREACHED; + } else { + scn.nmhdr.code = SCN_SAVEPOINTLEFT; + } + NotifyParent(scn); +} + +void Editor::NotifyModifyAttempt() { + SCNotification scn; + scn.nmhdr.code = SCN_MODIFYATTEMPTRO; + NotifyParent(scn); +} + +void Editor::NotifyDoubleClick(Point, bool) { + SCNotification scn; + scn.nmhdr.code = SCN_DOUBLECLICK; + NotifyParent(scn); +} + +void Editor::NotifyUpdateUI() { + SCNotification scn; + scn.nmhdr.code = SCN_UPDATEUI; + 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; + 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; + scn.nmhdr.code = SCN_NEEDSHOWN; + scn.position = pos; + scn.length = len; + NotifyParent(scn); +} + +// Notifications from document +void Editor::NotifyModifyAttempt(Document*, void *) { + //Platform::DebugPrintf("** Modify Attempt\n"); + NotifyModifyAttempt(); +} + +void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) { + //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); + NotifySavePoint(atSavePoint); +} + +void Editor::NotifyModified(Document*, DocModification mh, void *) { + needUpdateUI = true; + if (paintState == painting) { + CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); + } else if (paintState == notPainting) { + if (mh.modificationType & SC_MOD_CHANGESTYLE) { + if (mh.position < pdoc->LineStart(topLine)) { + // Styling performed before this view + Redraw(); + } else { + InvalidateRange(mh.position, mh.position + mh.length); + } + } else { + // Move selection and brace highlights + if (mh.modificationType & SC_MOD_INSERTTEXT) { + if (currentPos > mh.position) { + currentPos += mh.length; + } + if (anchor > mh.position) { + anchor += mh.length; + } + if (braces[0] > mh.position) { + braces[0] += mh.length; + } + if (braces[1] > mh.position) { + braces[1] += mh.length; + } + } else { // SC_MOD_DELETETEXT + int endPos = mh.position + mh.length; + if (currentPos > mh.position) { + if (currentPos > endPos) { + currentPos -= mh.length; + } else { + currentPos = endPos; + } + } + if (anchor > mh.position) { + if (anchor > endPos) { + anchor -= mh.length; + } else { + anchor = endPos; + } + } + if (braces[0] > mh.position) { + if (braces[0] > endPos) { + braces[0] -= mh.length; + } else { + braces[0] = endPos; + } + } + if (braces[1] > mh.position) { + if (braces[1] > endPos) { + braces[1] -= mh.length; + } else { + braces[1] = endPos; + } + } + } + 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) { + NotifyNeedShown(mh.position, mh.length); + cs.InsertLines(lineOfPos, mh.linesAdded); + } else { + cs.DeleteLines(lineOfPos, -mh.linesAdded); + } + // Avoid scrolling of display if change before current display + if (mh.position < posTopLine) { + 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); + Redraw(); + } else { + //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, + // mh.position, mh.position + mh.length); + InvalidateRange(mh.position, mh.position + mh.length); + } + } + } // else paintState == paintAbandoned so no need to do anything + + if (mh.linesAdded != 0) { + SetScrollBars(); + } + + // If client wants to see this modification + if (mh.modificationType & modEventMask) { + if ((mh.modificationType & SC_MOD_CHANGESTYLE) == 0) { + // Real modification made to text of document. + NotifyChange(); // Send EN_CHANGE + } + SCNotification scn; + 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; + NotifyParent(scn); + } +} + +void Editor::NotifyDeleted(Document *document, void *userData) { + /* Do nothing */ +} + +#ifdef MACRO_SUPPORT +void Editor::NotifyMacroRecord(UINT iMessage, WPARAM wParam, LPARAM lParam) { + + // Enumerates all macroable messages + switch (iMessage) { + case WM_CUT: + case WM_COPY: + case WM_PASTE: + case WM_CLEAR: + case EM_REPLACESEL: + case SCI_ADDTEXT: + case SCI_INSERTTEXT: + 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_LINEUP: + case SCI_LINEUPEXTEND: + 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_HOME: + case SCI_HOMEEXTEND: + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + case SCI_DOCUMENTSTART: + case SCI_DOCUMENTSTARTEXTEND: + case SCI_DOCUMENTEND: + case SCI_DOCUMENTENDEXTEND: + 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_DELWORDLEFT: + case SCI_DELWORDRIGHT: + break; + + // Filter out all others (display changes, etc) + default: +// printf("Filtered out %ld of macro recording\n", iMessage); + return; + } + + // Send notification + SCNotification scn; + scn.nmhdr.code = SCN_MACRORECORD; + scn.message = iMessage; + scn.wParam = wParam; + scn.lParam = lParam; + NotifyParent(scn); +} +#endif + +// Force scroll and keep position relative to top of window +void Editor::PageMove(int direction, bool extend) { + Point pt = LocationFromPosition(currentPos); + int topLineNew = Platform::Clamp( + topLine + direction * LinesToScroll(), 0, MaxScrollPos()); + int newPos = PositionFromLocation( + Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll()))); + if (topLineNew != topLine) { + SetTopLine(topLineNew); + MovePositionTo(newPos, extend); + Redraw(); + SetVerticalScrollPos(); + } else { + MovePositionTo(newPos, extend); + } +} + +int Editor::KeyCommand(UINT iMessage) { + Point pt = LocationFromPosition(currentPos); + + switch (iMessage) { + case SCI_LINEDOWN: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y + vs.lineHeight))); + break; + case SCI_LINEDOWNEXTEND: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y + vs.lineHeight)), true); + break; + case SCI_LINEUP: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y - vs.lineHeight))); + break; + case SCI_LINEUPEXTEND: + MovePositionTo(PositionFromLocation( + Point(lastXChosen, pt.y - vs.lineHeight)), true); + break; + case SCI_CHARLEFT: + if (SelectionEmpty()) { + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1)); + } else { + MovePositionTo(SelectionStart()); + } + SetLastXChosen(); + break; + case SCI_CHARLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), true); + SetLastXChosen(); + break; + case SCI_CHARRIGHT: + if (SelectionEmpty()) { + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1)); + } else { + MovePositionTo(SelectionEnd()); + } + SetLastXChosen(); + break; + case SCI_CHARRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), true); + SetLastXChosen(); + break; + case SCI_WORDLEFT: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1)); + SetLastXChosen(); + break; + case SCI_WORDLEFTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), true); + SetLastXChosen(); + break; + case SCI_WORDRIGHT: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1)); + SetLastXChosen(); + break; + case SCI_WORDRIGHTEXTEND: + MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), true); + SetLastXChosen(); + break; + case SCI_HOME: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos))); + SetLastXChosen(); + break; + case SCI_HOMEEXTEND: + MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), true); + SetLastXChosen(); + break; + case SCI_LINEEND: + MovePositionTo(pdoc->LineEndPosition(currentPos)); + SetLastXChosen(); + break; + case SCI_LINEENDEXTEND: + MovePositionTo(pdoc->LineEndPosition(currentPos), true); + SetLastXChosen(); + break; + case SCI_DOCUMENTSTART: + MovePositionTo(0); + SetLastXChosen(); + break; + case SCI_DOCUMENTSTARTEXTEND: + MovePositionTo(0, true); + SetLastXChosen(); + break; + case SCI_DOCUMENTEND: + MovePositionTo(pdoc->Length()); + SetLastXChosen(); + break; + case SCI_DOCUMENTENDEXTEND: + MovePositionTo(pdoc->Length(), true); + SetLastXChosen(); + break; + case SCI_PAGEUP: + PageMove( -1); + break; + case SCI_PAGEUPEXTEND: + PageMove( -1, true); + break; + case SCI_PAGEDOWN: + PageMove(1); + break; + case SCI_PAGEDOWNEXTEND: + PageMove(1, true); + break; + case SCI_EDITTOGGLEOVERTYPE: + inOverstrike = !inOverstrike; + DropCaret(); + ShowCaretAtCurrentPosition(); + break; + case SCI_CANCEL: // Cancel any modes - handled in subclass + // Also unselect text + SetEmptySelection(currentPos); + break; + case SCI_DELETEBACK: + DelCharBack(); + EnsureCaretVisible(); + break; + case SCI_TAB: + Indent(true); + break; + case SCI_BACKTAB: + Indent(false); + break; + case SCI_NEWLINE: + ClearSelection(); + if (pdoc->eolMode == SC_EOL_CRLF) { + pdoc->InsertString(currentPos, "\r\n"); + SetEmptySelection(currentPos + 2); + NotifyChar('\r'); + NotifyChar('\n'); + } else if (pdoc->eolMode == SC_EOL_CR) { + pdoc->InsertChar(currentPos, '\r'); + SetEmptySelection(currentPos + 1); + NotifyChar('\r'); + } else if (pdoc->eolMode == SC_EOL_LF) { + pdoc->InsertChar(currentPos, '\n'); + SetEmptySelection(currentPos + 1); + NotifyChar('\n'); + } + SetLastXChosen(); + EnsureCaretVisible(); + break; + case SCI_FORMFEED: + AddChar('\f'); + break; + case SCI_VCHOME: + MovePositionTo(pdoc->VCHomePosition(currentPos)); + SetLastXChosen(); + break; + case SCI_VCHOMEEXTEND: + MovePositionTo(pdoc->VCHomePosition(currentPos), true); + SetLastXChosen(); + break; + case SCI_ZOOMIN: + if (vs.zoomLevel < 20) + vs.zoomLevel++; + InvalidateStyleRedraw(); + break; + case SCI_ZOOMOUT: + if (vs.zoomLevel > -10) + vs.zoomLevel--; + InvalidateStyleRedraw(); + break; + case SCI_DELWORDLEFT: { + int startWord = pdoc->NextWordStart(currentPos, -1); + pdoc->DeleteChars(startWord, currentPos - startWord); + MovePositionTo(startWord); + } + break; + case SCI_DELWORDRIGHT: { + int endWord = pdoc->NextWordStart(currentPos, 1); + pdoc->DeleteChars(currentPos, endWord - currentPos); + } + break; + } + return 0; +} + +int Editor::KeyDefault(int, int) { + return 0; +} + +int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt) { + int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | + (alt ? SCI_ALT : 0); + int msg = kmap.Find(key, modifiers); + if (msg) + return WndProc(msg, 0, 0); + else + return KeyDefault(key, modifiers); +} + +void Editor::SetWhitespaceVisible(bool view) { + vs.viewWhitespace = view; +} + +bool 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) { + ClearSelection(); + pdoc->InsertChar(currentPos, '\t'); + //pdoc->InsertChar(currentPos++, '\t'); + SetEmptySelection(currentPos + 1); + } 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)); + } + } +} + +long Editor::FindText(UINT iMessage, WPARAM wParam, LPARAM lParam) { + FINDTEXTEX *ft = reinterpret_cast(lParam); + int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, + wParam & FR_MATCHCASE, wParam & FR_WHOLEWORD); + if (pos != -1) { + if (iMessage == EM_FINDTEXTEX) { + ft->chrgText.cpMin = pos; + ft->chrgText.cpMax = pos + strlen(ft->lpstrText); + } + } + 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 SearchAnchor first. +// Accepts both SCI_SEARCHNEXT and SCI_SEARCHPREV. +// wParam contains search modes : ORed FR_MATCHCASE and FR_WHOLEWORD. +// lParam contains the text to search for. +long Editor::SearchText(UINT iMessage, WPARAM wParam, LPARAM lParam) { + const char *txt = reinterpret_cast(lParam); + int pos; + + if (iMessage == SCI_SEARCHNEXT) { + pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, + wParam & FR_MATCHCASE, + wParam & FR_WHOLEWORD); + } else { + pos = pdoc->FindText(searchAnchor, 0, txt, + wParam & FR_MATCHCASE, + wParam & FR_WHOLEWORD); + } + + if (pos != -1) { + SetSelection(pos, pos + strlen(txt)); + } + + 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; +} + +int Editor::SelectionRangeLength() { + if (selType == selRectangle) { + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int totalSize = 0; + for (int line=lineStart; line <= lineEnd; line++) { + totalSize += SelectionEnd(line) - SelectionStart(line) + 1; + if (pdoc->eolMode == SC_EOL_CRLF) + totalSize++; + } + return totalSize; + } else { + return SelectionEnd() - SelectionStart(); + } +} + +char *Editor::CopySelectionRange() { + if (selType == selRectangle) { + char *text = 0; + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + int totalSize = SelectionRangeLength(); + if (totalSize > 0) { + text = new char[totalSize + 1]; + if (text) { + int j = 0; + for (int line=lineStart; line <= lineEnd; line++) { + for (int i=SelectionStart(line);iCharAt(i); + } + if (pdoc->eolMode != SC_EOL_LF) + text[j++] = '\r'; + if (pdoc->eolMode != SC_EOL_CR) + text[j++] = '\n'; + } + text[totalSize] = '\0'; + } + } + return text; + } else { + return CopyRange(SelectionStart(), SelectionEnd()); + } +} + +void Editor::CopySelectionIntoDrag() { + delete []dragChars; + dragChars = 0; + lenDrag = SelectionRangeLength(); + dragChars = CopySelectionRange(); + dragIsRectangle = selType == selRectangle; + if (!dragChars) { + lenDrag = 0; + } +} + +void Editor::SetDragPosition(int newPos) { + if (newPos >= 0) { + newPos = pdoc->MovePositionOutsideChar(newPos, 1); + posDrop = newPos; + } + if (posDrag != newPos) { + caret.on = true; + SetTicking(true); + InvalidateCaret(); + posDrag = newPos; + InvalidateCaret(); + } +} + +void Editor::StartDrag() { + // Always handled by subclasses + //SetMouseCapture(true); + //wDraw.SetCursor(Window::cursorArrow); +} + +void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) { + //Platform::DebugPrintf("DropAt %d\n", inDragDrop); + if (inDragDrop) + dropWentOutside = false; + + int positionWasInSelection = PositionInSelection(position); + + if ((!inDragDrop) || !(0 == positionWasInSelection)) { + + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + + pdoc->BeginUndoAction(); + + int positionAfterDeletion = position; + if (inDragDrop && moving) { + // Remove dragged out text + if (rectangular) { + int lineStart = pdoc->LineFromPosition(SelectionStart()); + int lineEnd = pdoc->LineFromPosition(SelectionEnd()); + for (int line=lineStart; line <= lineEnd; line++) { + int startPos = SelectionStart(line); + int endPos = SelectionEnd(line); + if (position >= startPos) { + if (position > endPos) { + positionAfterDeletion -= endPos - startPos; + } else { + positionAfterDeletion -= position - startPos; + } + } + } + } else { + if (position > selStart) { + positionAfterDeletion -= selEnd - selStart; + } + } + ClearSelection(); + } + position = positionAfterDeletion; + + if (rectangular) { + PasteRectangular(position, value, strlen(value)); + pdoc->EndUndoAction(); + // Should try to select new rectangle but it may not be a rectangle now so just select the drop position + SetSelection(position, position); + } else { + position = pdoc->MovePositionOutsideChar(position, currentPos - position); + pdoc->InsertString(position, value); + pdoc->EndUndoAction(); + SetSelection(position + strlen(value), position); + } + } else if (inDragDrop) { + SetSelection(position, position); + } +} + +static int BeforeInOrAfter(int val, int minim, int maxim) { + if (val < minim) + return -1; + else if (val > maxim) + return 1; + else + return 0; +} + +int Editor::PositionInSelection(int pos) { + pos = pdoc->MovePositionOutsideChar(pos, currentPos - pos); + if (selType == selRectangle) { + if (pos < SelectionStart()) + return -1; + if (pos > SelectionEnd()) + return 1; + int linePos = pdoc->LineFromPosition(pos); + return BeforeInOrAfter(pos, SelectionStart(linePos), SelectionEnd(linePos)); + } else { + if (currentPos > anchor) { + return BeforeInOrAfter(pos, anchor, currentPos); + } else if (currentPos < anchor) { + return BeforeInOrAfter(pos, currentPos, anchor); + } + } + return 1; +} + +bool Editor::PointInSelection(Point pt) { + // TODO: fix up for rectangular selection + int pos = PositionFromLocation(pt); + if (0 == PositionInSelection(pos)) { + if (pos == SelectionStart()) { + // see if just before selection + Point locStart = LocationFromPosition(pos); + if (pt.x < locStart.x) + return false; + } + if (pos == SelectionEnd()) { + // 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::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + //Platform::DebugPrintf("Scintilla:ButtonDown %d %d = %d alt=%d\n", curTime, lastClickTime, curTime - lastClickTime, alt); + ptMouseLast = pt; + int newPos = PositionFromLocation(pt); + newPos = pdoc->MovePositionOutsideChar(newPos, currentPos - newPos); + inDragDrop = false; + + bool processed = NotifyMarginClick(pt, shift, ctrl, alt); + if (processed) + return; + + if (shift) { + 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 (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); + } else { // Single click + if (PointInSelMargin(pt)) { + if (ctrl) { + SelectAll(); + lastClickTime = curTime; + return; + } + lineAnchor = LineFromLocation(pt); + // While experimenting with folding turn off line selection + if (!shift) { + // Single click in margin: select whole line + SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor)); + } else { + // Single shift+click in margin: select from anchor to beginning of clicked line + SetSelection(pdoc->LineStart(lineAnchor), anchor); + } + SetDragPosition(invalidPosition); + SetMouseCapture(true); + selectionType = selLine; + } else { + if (!shift) { + inDragDrop = PointInSelection(pt); + } + if (inDragDrop) { + SetMouseCapture(false); + SetDragPosition(newPos); + CopySelectionIntoDrag(); + StartDrag(); + } else { + selType = alt ? selRectangle : selStream; + xStartSelect = pt.x - vs.fixedColumnWidth + xOffset; + xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + SetDragPosition(invalidPosition); + SetMouseCapture(true); + if (!shift) + SetEmptySelection(newPos); + selectionType = selChar; + originalAnchorPos = currentPos; + } + } + } + lastClickTime = curTime; + lastXChosen = pt.x; + ShowCaretAtCurrentPosition(); +} + +void Editor::ButtonMove(Point pt) { + //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); + if (HaveMouseCapture()) { + xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + ptMouseLast = pt; + int movePos = PositionFromLocation(pt); + movePos = pdoc->MovePositionOutsideChar(movePos, currentPos - movePos); + if (posDrag >= 0) { + SetDragPosition(movePos); + } else { + if (selectionType == selChar) { + SetSelection(movePos); + } else if (selectionType == selWord) { + // Continue selecting by word + if (currentPos > 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); + if (lineAnchor < lineMove) { + SetSelection(pdoc->LineStart(lineMove + 1), + pdoc->LineStart(lineAnchor)); + } else { + SetSelection(pdoc->LineStart(lineMove), + pdoc->LineStart(lineAnchor + 1)); + } + } + } + EnsureCaretVisible(false); + } else { + if (vs.fixedColumnWidth > 0) { // There is a margin + if (PointInSelMargin(pt)) { + wDraw.SetCursor(Window::cursorReverseArrow); + return; // No need to test for selection + } + } + // Display regular (drag) cursor over selection + if (PointInSelection(pt)) + wDraw.SetCursor(Window::cursorArrow); + else + wDraw.SetCursor(Window::cursorText); + } + +} + +void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { + //Platform::DebugPrintf("ButtonUp %d\n", HaveMouseCapture()); + if (HaveMouseCapture()) { + if (PointInSelMargin(pt)) { + wDraw.SetCursor(Window::cursorReverseArrow); + } else { + wDraw.SetCursor(Window::cursorText); + } + xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; + ptMouseLast = pt; + SetMouseCapture(false); + int newPos = PositionFromLocation(pt); + newPos = pdoc->MovePositionOutsideChar(newPos, currentPos - newPos); + if (inDragDrop) { + int selStart = SelectionStart(); + int selEnd = SelectionEnd(); + if (selStart < selEnd) { + if (dragChars && lenDrag) { + if (ctrl) { + pdoc->InsertString(newPos, dragChars, lenDrag); + SetSelection(newPos, newPos + lenDrag); + } else if (newPos < selStart) { + pdoc->DeleteChars(selStart, lenDrag); + pdoc->InsertString(newPos, dragChars, lenDrag); + SetSelection(newPos, newPos + lenDrag); + } else if (newPos > selEnd) { + pdoc->DeleteChars(selStart, lenDrag); + newPos -= lenDrag; + pdoc->InsertString(newPos, dragChars, lenDrag); + SetSelection(newPos, newPos + lenDrag); + } else { + SetEmptySelection(newPos); + } + delete []dragChars; + dragChars = 0; + lenDrag = 0; + } + selectionType = selChar; + } + } else { + if (selectionType == selChar) { + SetSelection(newPos); + } + } + lastClickTime = curTime; + lastClick = pt; + lastXChosen = pt.x; + inDragDrop = false; + 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; + InvalidateCaret(); + } + } +} + +static bool IsIn(int a, int minimum, int maximum) { + return (a >= minimum) && (a <= maximum); +} + +static bool IsOverlap(int mina, int maxa, int minb, int maxb) { + return + IsIn(mina, minb, maxb) || + IsIn(maxa, minb, maxb) || + IsIn(minb, mina, maxa) || + IsIn(maxb, mina, maxa); +} + +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 rcText = GetTextRectangle(); + // Determine number of lines displayed including a possible partially displayed last line + int linesDisplayed = (rcText.bottom - rcText.top - 1) / vs.lineHeight + 1; + int bottomLine = topLine + linesDisplayed - 1; + + int lineRangeStart = cs.DisplayFromDoc(pdoc->LineFromPosition(r.start)); + int lineRangeEnd = cs.DisplayFromDoc(pdoc->LineFromPosition(r.end)); + if (!IsOverlap(topLine, bottomLine, lineRangeStart, lineRangeEnd)) { + //Platform::DebugPrintf("No overlap (%d-%d) with window(%d-%d)\n", + // lineRangeStart, lineRangeEnd, topLine, bottomLine); + return; + } + + // Assert rcPaint contained within or equal to rcText + if (rcPaint.top > rcText.top) { + // does range intersect rcText.top .. rcPaint.top + int paintTopLine = ((rcPaint.top - rcText.top-1) / vs.lineHeight) + topLine; + // paintTopLine is the top line of the paint rectangle or the line just above if that line is completely inside the paint rectangle + if (IsOverlap(topLine, paintTopLine, lineRangeStart, lineRangeEnd)) { + //Platform::DebugPrintf("Change (%d-%d) in top npv(%d-%d)\n", + // lineRangeStart, lineRangeEnd, topLine, paintTopLine); + paintState = paintAbandoned; + return; + } + } + if (rcPaint.bottom < rcText.bottom) { + // does range intersect rcPaint.bottom .. rcText.bottom + int paintBottomLine = ((rcPaint.bottom - rcText.top-1) / vs.lineHeight + 1) + topLine; + // paintTopLine is the bottom line of the paint rectangle or the line just below if that line is completely inside the paint rectangle + if (IsOverlap(paintBottomLine, bottomLine, lineRangeStart, lineRangeEnd)) { + //Platform::DebugPrintf("Change (%d-%d) in bottom npv(%d-%d)\n", + // lineRangeStart, lineRangeEnd, paintBottomLine, bottomLine); + paintState = paintAbandoned; + return; + } + } + } +} + +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 +// TODO: may need to make DBCS safe +// so should be moved into Document +int Editor::BraceMatch(int position, int maxReStyle) { + char chBrace = pdoc->CharAt(position); + char chSeek = BraceOpposite(chBrace); + if (!chSeek) + return - 1; + char styBrace = pdoc->StyleAt(position) & pdoc->stylingBitsMask; + int direction = -1; + if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') + direction = 1; + int depth = 1; + position = position + direction; + while ((position >= 0) && (position < pdoc->Length())) { + char chAtPos = pdoc->CharAt(position); + char styAtPos = pdoc->StyleAt(position) & pdoc->stylingBitsMask; + if ((position > pdoc->GetEndStyled()) || (styAtPos == styBrace)) { + if (chAtPos == chBrace) + depth++; + if (chAtPos == chSeek) + depth--; + if (depth == 0) + return position; + } + position = position + direction; + } + return - 1; +} + +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::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(); + pdoc->AddWatcher(this, 0); + Redraw(); + SetScrollBars(); +} + +// 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 (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) { + if (cs.GetExpanded(line)) { + int lineMaxSubord = pdoc->GetLastChild(line); + cs.SetExpanded(line, 0); + if (lineMaxSubord > line) { + cs.SetVisible(line+1, lineMaxSubord, false); + SetScrollBars(); + Redraw(); + } + } else { + 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 line) { + if (!cs.GetVisible(line)) { + int lineParent = pdoc->GetFoldParent(line); + if (lineParent >= 0) { + if (line != lineParent) + EnsureLineVisible(lineParent); + if (!cs.GetExpanded(lineParent)) { + cs.SetExpanded(lineParent, 1); + Expand(lineParent, true); + } + } + SetScrollBars(); + Redraw(); + } +} + +LRESULT Editor::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { + //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); + + // Optional macro recording hook +#ifdef MACRO_SUPPORT + if (recordingMacro) + NotifyMacroRecord(iMessage, wParam, lParam); +#endif + + switch (iMessage) { + + case WM_GETTEXT: + { + if (lParam == 0) + return 0; + char *ptr = reinterpret_cast(lParam); + unsigned int iChar = 0; + for (; iChar < wParam-1; iChar++) + ptr[iChar] = pdoc->CharAt(iChar); + ptr[iChar] = '\0'; + return iChar; + } + + case WM_SETTEXT: + { + if (lParam == 0) + return FALSE; + pdoc->DeleteChars(0, pdoc->Length()); + SetEmptySelection(0); + pdoc->InsertString(0, reinterpret_cast(lParam)); + return TRUE; + } + + case WM_GETTEXTLENGTH: + return pdoc->Length(); + + case WM_NOTIFY: + //Platform::DebugPrintf("S notify %d %d\n", wParam, lParam); + break; + + case WM_CUT: + Cut(); + SetLastXChosen(); + break; + + case WM_COPY: + Copy(); + break; + + case WM_PASTE: + Paste(); + SetLastXChosen(); + break; + + case WM_CLEAR: + Clear(); + SetLastXChosen(); + break; + + case WM_UNDO: + Undo(); + SetLastXChosen(); + break; + + // Edit control mesages + + // Not supported (no-ops): + // EM_GETWORDBREAKPROC + // EM_GETWORDBREAKPROCEX + // EM_SETWORDBREAKPROC + // EM_SETWORDBREAKPROCEX + // EM_GETWORDWRAPMODE + // EM_SETWORDWRAPMODE + // EM_LIMITTEXT + // EM_EXLIMITTEXT + // EM_SETRECT + // EM_SETRECTNP + // EM_FMTLINES + // EM_GETHANDLE + // EM_SETHANDLE + // EM_GETPASSWORDCHAR + // EM_SETPASSWORDCHAR + // EM_SETTABSTOPS + // EM_FINDWORDBREAK + // EM_GETCHARFORMAT + // EM_SETCHARFORMAT + // EM_GETOLEINTERFACE + // EM_SETOLEINTERFACE + // EM_SETOLECALLBACK + // EM_GETPARAFORMAT + // EM_SETPARAFORMAT + // EM_PASTESPECIAL + // EM_REQUESTRESIZE + // EM_GETBKGNDCOLOR + // EM_SETBKGNDCOLOR + // EM_STREAMIN + // EM_STREAMOUT + // EM_GETIMECOLOR + // EM_SETIMECOLOR + // EM_GETIMEOPTIONS + // EM_SETIMEOPTIONS + // EM_GETOPTIONS + // EM_SETOPTIONS + // EM_GETPUNCTUATION + // EM_SETPUNCTUATION + // EM_GETTHUMB + + // Not supported but should be: + // EM_GETEVENTMASK + // EM_SETEVENTMASK + // For printing: + // EM_DISPLAYBAND + // EM_SETTARGETDEVICE + + case EM_CANUNDO: + return pdoc->CanUndo() ? TRUE : FALSE; + + case EM_UNDO: + Undo(); + break; + + case EM_EMPTYUNDOBUFFER: + pdoc->DeleteUndoHistory(); + return 0; + + case EM_GETFIRSTVISIBLELINE: + return topLine; + + case EM_GETLINE: { + if (lParam == 0) + return 0; + int lineStart = pdoc->LineStart(wParam); + int lineEnd = pdoc->LineStart(wParam + 1); + char *ptr = reinterpret_cast(lParam); + WORD *pBufSize = reinterpret_cast(lParam); + if (*pBufSize < lineEnd - lineStart) { + ptr[0] = '\0'; // If no characters copied have to put a NUL into buffer + return 0; + } + int iPlace = 0; + for (int iChar = lineStart; iChar < lineEnd; iChar++) + ptr[iPlace++] = pdoc->CharAt(iChar); + return iPlace; + } + + case EM_GETLINECOUNT: + if (pdoc->LinesTotal() == 0) + return 1; + else + return pdoc->LinesTotal(); + + case EM_GETMODIFY: + return !pdoc->IsSavePoint(); + + case EM_SETMODIFY: + // Not really supported now that there is the save point stuff + //pdoc->isModified = wParam; + //return pdoc->isModified; + return false; + + case EM_GETRECT: + if (lParam == 0) + return 0; + *(reinterpret_cast(lParam)) = GetClientRectangle(); + break; + + case EM_GETSEL: + if (wParam) + *reinterpret_cast(wParam) = SelectionStart(); + if (lParam) + *reinterpret_cast(lParam) = SelectionEnd(); + return MAKELONG(SelectionStart(), SelectionEnd()); + + case EM_EXGETSEL: { + if (lParam == 0) + return 0; + CHARRANGE *pCR = reinterpret_cast(lParam); + pCR->cpMin = SelectionStart(); + pCR->cpMax = SelectionEnd(); + } + break; + + case EM_SETSEL: { + int nStart = static_cast(wParam); + int nEnd = static_cast(lParam); + if (nEnd < 0) + nEnd = pdoc->Length(); + if (nStart < 0) + nStart = nEnd; // Remove selection + SetSelection(nEnd, nStart); + EnsureCaretVisible(); + } + break; + + case EM_EXSETSEL: { + if (lParam == 0) + return 0; + CHARRANGE *pCR = reinterpret_cast(lParam); + if (pCR->cpMax == -1) { + SetSelection(pCR->cpMin, pdoc->Length()); + } else { + SetSelection(pCR->cpMin, pCR->cpMax); + } + EnsureCaretVisible(); + return pdoc->LineFromPosition(SelectionStart()); + } + + case EM_GETSELTEXT: { + if (lParam == 0) + return 0; + char *ptr = reinterpret_cast(lParam); + int selSize = SelectionRangeLength(); + char *text = CopySelectionRange(); + int iChar = 0; + if (text) { + for (; iChar < selSize; iChar++) + ptr[iChar] = text[iChar]; + ptr[iChar] = '\0'; + delete []text; + } + return iChar; + } + + case EM_GETWORDBREAKPROC: + return 0; + + case EM_SETWORDBREAKPROC: + break; + + case EM_LIMITTEXT: + // wParam holds the number of characters control should be limited to + break; + + case EM_GETLIMITTEXT: + return 0xffffffff; + + case EM_GETOLEINTERFACE: + return 0; + + case EM_LINEFROMCHAR: + if (static_cast(wParam) < 0) + wParam = SelectionStart(); + return pdoc->LineFromPosition(wParam); + + case EM_EXLINEFROMCHAR: + if (static_cast(lParam) < 0) + lParam = SelectionStart(); // Not specified, but probably OK + return pdoc->LineFromPosition(lParam); + + case EM_LINEINDEX: + 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); + + case EM_LINELENGTH: + { + if (static_cast(wParam) < 0) // Who use this anyway? + return 0; // Should be... Too complex to describe here, see MS specs! + if (static_cast(wParam) > pdoc->Length()) // Useful test, anyway... + return 0; + int line = pdoc->LineFromPosition(wParam); + int charsOnLine = 0; + for (int pos = pdoc->LineStart(line); pos < pdoc->LineStart(line + 1); pos++) { + if ((pdoc->CharAt(pos) != '\r') && (pdoc->CharAt(pos) != '\n')) + charsOnLine++; + } + return charsOnLine; + } + + // 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 EM_REPLACESEL: { + if (lParam == 0) + return 0; + pdoc->BeginUndoAction(); + ClearSelection(); + char *replacement = reinterpret_cast(lParam); + pdoc->InsertString(currentPos, replacement); + pdoc->EndUndoAction(); + SetEmptySelection(currentPos + strlen(replacement)); + EnsureCaretVisible(); + } + break; + + case EM_LINESCROLL: + ScrollTo(topLine + lParam); + HorizontalScrollTo(xOffset + wParam * vs.spaceWidth); + return TRUE; + + case EM_SCROLLCARET: + EnsureCaretVisible(); + break; + + case EM_SETREADONLY: + pdoc->SetReadOnly(wParam); + return TRUE; + + case EM_SETRECT: + break; + + case EM_CANPASTE: + return 1; + + case EM_CHARFROMPOS: { + if (lParam == 0) + return 0; + Point *ppt = reinterpret_cast(lParam); + int pos = PositionFromLocation(*ppt); + int line = pdoc->LineFromPosition(pos); + return MAKELONG(pos, line); + } + + case EM_POSFROMCHAR: { + // The MS specs for this have changed 3 times: using the RichEdit 3 version + if (wParam == 0) + return 0; + Point *ppt = reinterpret_cast(wParam); + if (lParam < 0) { + *ppt = Point(0, 0); + } else { + *ppt = LocationFromPosition(lParam); + } + return 0; + } + + case EM_FINDTEXT: + return FindText(iMessage, wParam, lParam); + + case EM_FINDTEXTEX: + return FindText(iMessage, wParam, lParam); + + case EM_GETTEXTRANGE: { + if (lParam == 0) + return 0; + TEXTRANGE *tr = reinterpret_cast(lParam); + int cpMax = tr->chrg.cpMax; + if (cpMax == -1) + 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 EM_SELECTIONTYPE: + if (currentPos == anchor) + return SEL_EMPTY; + else + return SEL_TEXT; + + case EM_HIDESELECTION: + hideSelection = wParam; + Redraw(); + break; + + case EM_FORMATRANGE: + return FormatRange(wParam, reinterpret_cast(lParam)); + + case EM_GETMARGINS: + return MAKELONG(vs.leftMarginWidth, vs.rightMarginWidth); + + case EM_SETMARGINS: + if (wParam & EC_LEFTMARGIN) { + vs.leftMarginWidth = LOWORD(lParam); + } + if (wParam & EC_RIGHTMARGIN) { + vs.rightMarginWidth = HIWORD(lParam); + } + if (wParam == EC_USEFONTINFO) { + vs.leftMarginWidth = vs.aveCharWidth / 2; + vs.rightMarginWidth = vs.aveCharWidth / 2; + } + InvalidateStyleRedraw(); + break; + + // Control specific mesages + + case SCI_ADDTEXT: { + if (lParam == 0) + return 0; + pdoc->InsertString(CurrentPosition(), reinterpret_cast(lParam), wParam); + SetEmptySelection(currentPos + wParam); + return 0; + } + + case SCI_ADDSTYLEDTEXT: { + if (lParam == 0) + return 0; + pdoc->InsertStyledString(CurrentPosition() * 2, reinterpret_cast(lParam), wParam); + SetEmptySelection(currentPos + wParam / 2); + return 0; + } + + case SCI_INSERTTEXT: { + if (lParam == 0) + return 0; + int insertPos = wParam; + if (static_cast(wParam) == -1) + insertPos = CurrentPosition(); + int newCurrent = CurrentPosition(); + int newAnchor = anchor; + char *sz = reinterpret_cast(lParam); + pdoc->InsertString(insertPos, sz); + if (newCurrent > insertPos) + newCurrent += strlen(sz); + if (newAnchor > insertPos) + newAnchor += strlen(sz); + SetEmptySelection(newCurrent); + return 0; + } + + case SCI_CLEARALL: + ClearAll(); + return 0; + + case SCI_SETUNDOCOLLECTION: + pdoc->SetUndoCollection(static_cast(wParam)); + return 0; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_APPENDUNDOSTARTACTION: + pdoc->AppendUndoStartAction(); + return 0; +#endif + + 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: { + if (lParam == 0) + return 0; + pdoc->SetWordChars(reinterpret_cast(lParam)); + } + break; + + case SCI_GETLENGTH: + return pdoc->Length(); + + case SCI_GETCHARAT: + return pdoc->CharAt(wParam); + + case SCI_GETCURRENTPOS: + return currentPos; + + case SCI_GETANCHOR: + return anchor; + + 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(); + NotifySavePoint(true); + 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() ? TRUE : FALSE; + + 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 = wParam; + Redraw(); + break; + + case SCI_GOTOLINE: + GoToLine(wParam); + break; + + case SCI_GOTOPOS: + SetEmptySelection(wParam); + EnsureCaretVisible(); + Redraw(); + break; + + case SCI_SETANCHOR: + SetSelection(currentPos, wParam); + break; + + case SCI_GETCURLINE: { + if (lParam == 0) + return 0; + int lineCurrentPos = pdoc->LineFromPosition(currentPos); + int lineStart = pdoc->LineStart(lineCurrentPos); + unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1); + char *ptr = reinterpret_cast(lParam); + unsigned int iPlace = 0; + for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam; 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, lParam); + break; + + case SCI_SETSTYLING: + pdoc->SetStyleFor(wParam, lParam); + break; + + case SCI_SETSTYLINGEX: // Specify a complete styling buffer + if (lParam == 0) + return 0; + pdoc->SetStyles(wParam, reinterpret_cast(lParam)); + break; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETMARGINWIDTH: + if (wParam < 100) { + vs.ms[1].width = wParam; + } + InvalidateStyleRedraw(); + break; +#endif + + case SCI_SETBUFFEREDDRAW: + bufferedDraw = wParam; + break; + + case SCI_SETTABWIDTH: + if (wParam > 0) + pdoc->tabInChars = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETCODEPAGE: + pdoc->dbcsCodePage = wParam; + break; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETLINENUMBERWIDTH: + if (wParam < 200) { + vs.ms[0].width = wParam; + } + InvalidateStyleRedraw(); + break; +#endif + + case SCI_SETUSEPALETTE: + palette.allowRealization = wParam; + InvalidateStyleRedraw(); + break; + + // Marker definition and setting + case SCI_MARKERDEFINE: + if (wParam <= MARKER_MAX) + vs.markers[wParam].markType = lParam; + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERSETFORE: + if (wParam <= MARKER_MAX) + vs.markers[wParam].fore.desired = Colour(lParam); + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERSETBACK: + if (wParam <= MARKER_MAX) + vs.markers[wParam].back.desired = Colour(lParam); + InvalidateStyleData(); + RedrawSelMargin(); + break; + case SCI_MARKERADD: { + int markerID = pdoc->AddMark(wParam, lParam); + RedrawSelMargin(); + return markerID; + } + + case SCI_MARKERDELETE: + pdoc->DeleteMark(wParam, lParam); + RedrawSelMargin(); + break; + + case SCI_MARKERDELETEALL: + pdoc->DeleteAllMarks(static_cast(wParam)); + RedrawSelMargin(); + 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_SETMARGINTYPEN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].symbol = (lParam == SC_MARGIN_SYMBOL); + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINTYPEN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].symbol ? SC_MARGIN_SYMBOL : SC_MARGIN_NUMBER; + else + return 0; + + case SCI_SETMARGINWIDTHN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].width = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINWIDTHN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].width; + else + return 0; + + case SCI_SETMARGINMASKN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].mask = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINMASKN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].mask; + else + return 0; + + case SCI_SETMARGINSENSITIVEN: + if (wParam >= 0 && wParam < ViewStyle::margins) { + vs.ms[wParam].sensitive = lParam; + InvalidateStyleRedraw(); + } + break; + + case SCI_GETMARGINSENSITIVEN: + if (wParam >= 0 && wParam < ViewStyle::margins) + return vs.ms[wParam].sensitive ? 1 : 0; + else + return 0; + + case SCI_STYLECLEARALL: + vs.ClearStyles(); + InvalidateStyleRedraw(); + break; + + case SCI_STYLESETFORE: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].fore.desired = Colour(lParam); + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETBACK: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].back.desired = Colour(lParam); + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETBOLD: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].bold = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETITALIC: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].italic = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETEOLFILLED: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].eolFilled = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETSIZE: + if (wParam <= STYLE_MAX) { + vs.styles[wParam].size = lParam; + InvalidateStyleRedraw(); + } + break; + case SCI_STYLESETFONT: + if (lParam == 0) + return 0; + if (wParam <= STYLE_MAX) { + strcpy(vs.styles[wParam].fontName, reinterpret_cast(lParam)); + InvalidateStyleRedraw(); + } + break; + + case SCI_STYLERESETDEFAULT: + vs.ResetDefaultStyle(); + InvalidateStyleRedraw(); + break; + + case SCI_SETSTYLEBITS: + 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(); + + // Folding messages + + case SCI_VISIBLEFROMDOCLINE: + return cs.DisplayFromDoc(wParam); + + case SCI_DOCLINEFROMVISIBLE: + return cs.DocFromDisplay(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: + cs.SetVisible(wParam, lParam, false); + SetScrollBars(); + Redraw(); + break; + + case SCI_GETLINEVISIBLE: + return cs.GetVisible(wParam); + + case SCI_SETFOLDEXPANDED: + if (cs.SetExpanded(wParam, lParam)) { + 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); + break; + + case SCI_SEARCHANCHOR: + SearchAnchor(); + break; + + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + return SearchText(iMessage, wParam, lParam); + break; + + case SCI_SETCARETPOLICY: + caretPolicy = wParam; + caretSlop = lParam; + break; + +#ifdef INCLUDE_DEPRECATED_FEATURES + case SCI_SETFORE: + vs.styles[STYLE_DEFAULT].fore.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETBACK: + vs.styles[STYLE_DEFAULT].back.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETBOLD: + vs.styles[STYLE_DEFAULT].bold = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETITALIC: + vs.styles[STYLE_DEFAULT].italic = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETSIZE: + vs.styles[STYLE_DEFAULT].size = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_SETFONT: + if (wParam == 0) + return 0; + strcpy(vs.styles[STYLE_DEFAULT].fontName, reinterpret_cast(wParam)); + InvalidateStyleRedraw(); + break; +#endif + + case SCI_SETSELFORE: + vs.selforeset = wParam; + vs.selforeground.desired = Colour(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETSELBACK: + vs.selbackset = wParam; + vs.selbackground.desired = Colour(lParam); + InvalidateStyleRedraw(); + break; + + case SCI_SETCARETFORE: + vs.caretcolour.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_ASSIGNCMDKEY: + kmap.AssignCmdKey(LOWORD(wParam), HIWORD(wParam), lParam); + break; + + case SCI_CLEARCMDKEY: + kmap.AssignCmdKey(LOWORD(wParam), HIWORD(wParam), WM_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 = Colour(lParam); + InvalidateStyleRedraw(); + } + break; + + case SCI_INDICGETFORE: + return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0; + + case SCI_LINEDOWN: + case SCI_LINEDOWNEXTEND: + case SCI_LINEUP: + case SCI_LINEUPEXTEND: + 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_HOME: + case SCI_HOMEEXTEND: + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + case SCI_DOCUMENTSTART: + case SCI_DOCUMENTSTARTEXTEND: + case SCI_DOCUMENTEND: + case SCI_DOCUMENTENDEXTEND: + 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_ZOOMIN: + case SCI_ZOOMOUT: + case SCI_DELWORDLEFT: + case SCI_DELWORDRIGHT: + 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 BraceMatch(wParam, lParam); + + case SCI_GETVIEWEOL: + return vs.viewEOL; + + case SCI_SETVIEWEOL: + vs.viewEOL = wParam; + Redraw(); + break; + + case SCI_GETEDGECOLUMN: + return theEdge; + + case SCI_SETEDGECOLUMN: + theEdge = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEDGEMODE: + return edgeState; + + case SCI_SETEDGEMODE: + edgeState = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_GETEDGECOLOUR: + return vs.edgecolour.desired.AsLong(); + + case SCI_SETEDGECOLOUR: + vs.edgecolour.desired = Colour(wParam); + InvalidateStyleRedraw(); + break; + + case SCI_GETDOCPOINTER: + return reinterpret_cast(pdoc); + + case SCI_SETDOCPOINTER: + SetDocPointer(reinterpret_cast(lParam)); + return 0; + + case SCI_SETMODEVENTMASK: + modEventMask = wParam; + return 0; + + case SCI_CONVERTEOLS: + pdoc->ConvertLineEnds(wParam); + SetSelection(currentPos, anchor); // Ensure selection inside document + return 0; + +#ifdef MACRO_SUPPORT + case SCI_STARTRECORD: + recordingMacro = 1; + return 0; + + case SCI_STOPRECORD: + recordingMacro = 0; + return 0; +#endif + + default: + return DefWndProc(iMessage, wParam, lParam); + } + //Platform::DebugPrintf("end wnd proc\n"); + return 0l; +} diff --git a/src/stc/scintilla/src/Editor.h b/src/stc/scintilla/src/Editor.h new file mode 100644 index 0000000000..4ff334767a --- /dev/null +++ b/src/stc/scintilla/src/Editor.h @@ -0,0 +1,281 @@ +// Scintilla source code edit control +// Editor.h - defines the main editor class +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITOR_H +#define EDITOR_H + +class Caret { +public: + bool active; + bool on; + int period; + + Caret(); +}; + +class Timer { + +public: + bool ticking; + int ticksToWait; + enum {tickSize = 100}; + int tickerID; + + Timer(); +}; + +class LineLayout { +public: + // Drawing is only performed for maxLineLength characters on each line. + enum {maxLineLength = 4000}; + int numCharsInLine; + char chars[maxLineLength]; + char styles[maxLineLength]; + char indicators[maxLineLength]; + int positions[maxLineLength]; +}; + +class Editor : public DocWatcher { +protected: // ScintillaBase subclass needs access to much of Editor + + // On GTK+, Scintilla is a container widget holding two scroll bars and a drawing area + // whereas on Windows there is just one window with both scroll bars turned on. + // Therefore, on GTK+ the following are separate windows but only one window on Windows. + Window wMain; // The Scintilla parent window + Window wDraw; // The text drawing area + + // 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; + + bool hideSelection; + bool inOverstrike; + + // 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; + + int xOffset; // Horizontal scrolled amount in pixels + int xCaretMargin; // Ensure this many pixels visible on both sides of caret + + Surface pixmapLine; + Surface pixmapSelMargin; + Surface pixmapSelPattern; + // Intellimouse support - currently only implemented for Windows + unsigned int ucWheelScrollLines; + short cWheelDelta; //wheel delta from roll + + KeyMap kmap; + + Caret caret; + Timer timer; + + Point lastClick; + unsigned int lastClickTime; + enum { selChar, selWord, selLine } selectionType; + Point ptMouseLast; + bool firstExpose; + bool inDragDrop; + bool dropWentOutside; + int posDrag; + int posDrop; + int lastXChosen; + int lineAnchor; + int originalAnchorPos; + int currentPos; + int anchor; + int topLine; + int posTopLine; + + bool needUpdateUI; + Position braces[2]; + int bracesMatchStyle; + + int edgeState; + int theEdge; + + enum { notPainting, painting, paintAbandoned } paintState; + PRectangle rcPaint; + bool paintingAllText; + + int modEventMask; + + char *dragChars; + int lenDrag; + bool dragIsRectangle; + enum { selStream, selRectangle, selRectangleFixed } selType; + int xStartSelect; + int xEndSelect; + + int caretPolicy; + int caretSlop; + + int searchAnchor; + +#ifdef MACRO_SUPPORT + int recordingMacro; +#endif + + int foldFlags; + ContractionState cs; + + 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(); + + PRectangle GetClientRectangle(); + PRectangle GetTextRectangle(); + + int LinesOnScreen(); + int LinesToScroll(); + int MaxScrollPos(); + Point LocationFromPosition(unsigned int pos); + int XFromPosition(unsigned int pos); + int PositionFromLocation(Point pt); + int PositionFromLineX(int line, int x); + int LineFromLocation(Point pt); + void SetTopLine(int topLineNew); + + void RedrawRect(PRectangle rc); + void Redraw(); + void RedrawSelMargin(); + PRectangle RectangleFromRange(int start, int end); + void InvalidateRange(int start, int end); + + int CurrentPosition(); + bool SelectionEmpty(); + int SelectionStart(int line=-1); + int SelectionEnd(int line=-1); + void SetSelection(int currentPos_, int anchor_); + void SetSelection(int currentPos_); + void SetEmptySelection(int currentPos_); + int MovePositionTo(int newPos, bool extend = false); + int MovePositionSoVisible(int pos, int moveDir); + void SetLastXChosen(); + + void ScrollTo(int line); + virtual void ScrollText(int linesToMove); + void HorizontalScrollTo(int xPos); + void EnsureCaretVisible(bool useMargin=true); + void ShowCaretAtCurrentPosition(); + void DropCaret(); + void InvalidateCaret(); + + void PaintSelMargin(Surface *surface, PRectangle &rc); + void LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout &ll); + void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout &ll); + void Paint(Surface *surfaceWindow, PRectangle rcArea); + long FormatRange(bool draw, FORMATRANGE *pfr); + + virtual void SetVerticalScrollPos() = 0; + virtual void SetHorizontalScrollPos() = 0; + virtual bool ModifyScrollBars(int nMax, int nPage) = 0; + void SetScrollBarsTo(PRectangle rsClient); + void SetScrollBars(); + + virtual void AddChar(char ch); + void ClearSelection(); + void ClearAll(); + void Cut(); + void PasteRectangular(int pos, const char *ptr, int len); + virtual void Copy() = 0; + virtual void Paste() = 0; + void Clear(); + void SelectAll(); + void Undo(); + void Redo(); + void DelChar(); + void DelCharBack(); + virtual void ClaimSelection() = 0; + + virtual void NotifyChange() = 0; + virtual void NotifyFocus(bool focus); + virtual void NotifyParent(SCNotification scn) = 0; + virtual void NotifyStyleNeeded(int endStyleNeeded); + void NotifyChar(char ch); + void NotifySavePoint(bool isSavePoint); + void NotifyModifyAttempt(); + virtual void NotifyDoubleClick(Point pt, bool shift); + void NotifyUpdateUI(); + bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt); + void NotifyNeedShown(int pos, int len); + + void NotifyModifyAttempt(Document *document, void *userData); + void NotifySavePoint(Document *document, void *userData, bool atSavePoint); + void NotifyModified(Document *document, DocModification mh, void *userData); + void NotifyDeleted(Document *document, void *userData); + +#ifdef MACRO_SUPPORT + void NotifyMacroRecord(UINT iMessage, WPARAM wParam, LPARAM lParam); +#endif + + void PageMove(int direction, bool extend=false); + virtual int KeyCommand(UINT iMessage); + virtual int KeyDefault(int /* key */, int /*modifiers*/); + int KeyDown(int key, bool shift, bool ctrl, bool alt); + + bool GetWhitespaceVisible(); + void SetWhitespaceVisible(bool view); + + void Indent(bool forwards); + + long FindText(UINT iMessage,WPARAM wParam,LPARAM lParam); + void SearchAnchor(); + long SearchText(UINT iMessage,WPARAM wParam,LPARAM lParam); + void GoToLine(int lineNo); + + char *CopyRange(int start, int end); + int SelectionRangeLength(); + char *CopySelectionRange(); + void CopySelectionIntoDrag(); + void SetDragPosition(int newPos); + 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); + 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(); + virtual void SetTicking(bool on) = 0; + virtual void SetMouseCapture(bool on) = 0; + virtual bool HaveMouseCapture() = 0; + + void CheckForChangeOutsidePaint(Range r); + int BraceMatch(int position, int maxReStyle); + void SetBraceHighlight(Position pos0, Position pos1, int matchStyle); + + void SetDocPointer(Document *document); + + void Expand(int &line, bool doExpand); + void ToggleContraction(int line); + void EnsureLineVisible(int line); + + virtual LRESULT DefWndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) = 0; + +public: + // Public so scintilla_send_message can use it + virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); + // Public so scintilla_set_id can use it + int ctrlID; +}; + +#endif diff --git a/src/stc/scintilla/src/Indicator.cxx b/src/stc/scintilla/src/Indicator.cxx new file mode 100644 index 0000000000..fb6ad09157 --- /dev/null +++ b/src/stc/scintilla/src/Indicator.cxx @@ -0,0 +1,45 @@ +// Scintilla source code edit control +// Indicator.cxx - defines the style of indicators which are text decorations such as underlining +// Copyright 1998-2000 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" + +void Indicator::Draw(Surface *surface, PRectangle &rc) { + 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 { // Either INDIC_PLAIN or unknown + surface->MoveTo(rc.left, ymid); + surface->LineTo(rc.right, ymid); + } +} + diff --git a/src/stc/scintilla/src/Indicator.h b/src/stc/scintilla/src/Indicator.h new file mode 100644 index 0000000000..2472cedc14 --- /dev/null +++ b/src/stc/scintilla/src/Indicator.h @@ -0,0 +1,18 @@ +// Scintilla source code edit control +// Indicator.h - defines the style of indicators which are text decorations such as underlining +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef INDICATOR_H +#define INDICATOR_H + +class Indicator { +public: + int style; + ColourPair fore; + Indicator() : style(INDIC_PLAIN), fore(Colour(0,0,0)) { + } + void Draw(Surface *surface, PRectangle &rc); +}; + +#endif diff --git a/src/stc/scintilla/src/KeyMap.cxx b/src/stc/scintilla/src/KeyMap.cxx new file mode 100644 index 0000000000..f339cd2750 --- /dev/null +++ b/src/stc/scintilla/src/KeyMap.cxx @@ -0,0 +1,111 @@ +// Scintilla source code edit control +// KeyMap.cxx - defines a mapping between keystrokes and commands +// Copyright 1998-2000 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" + +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, UINT msg) { + if ((len+1) >= alloc) { + KeyToCommand *ktcNew = new KeyToCommand[alloc + 5]; + if (!ktcNew) + return; + for (int k=0;k +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef KEYTOCOMMAND_H +#define KEYTOCOMMAND_H + +#define SCI_NORM 0 +#define SCI_SHIFT SHIFT_PRESSED +#define SCI_CTRL LEFT_CTRL_PRESSED +#define SCI_ALT LEFT_ALT_PRESSED +#define SCI_CSHIFT (SCI_CTRL | SCI_SHIFT) + +class KeyToCommand { +public: + int key; + int modifiers; + UINT msg; +}; + +class KeyMap { + KeyToCommand *kmap; + int len; + int alloc; + static KeyToCommand MapDefault[]; +public: + KeyMap(); + ~KeyMap(); + void Clear(); + void AssignCmdKey(int key, int modifiers, UINT msg); + UINT Find(int key, int modifiers); // 0 returned on failure +}; + +#endif diff --git a/src/stc/scintilla/src/KeyWords.cxx b/src/stc/scintilla/src/KeyWords.cxx new file mode 100644 index 0000000000..20f6762470 --- /dev/null +++ b/src/stc/scintilla/src/KeyWords.cxx @@ -0,0 +1,2217 @@ +// SciTE - Scintilla based Text Editor +// KeyWords.cxx - colourise for particular languages +// Copyright 1998-2000 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" + +inline bool IsLeadByte(int codePage, char ch) { +#if PLAT_GTK + // TODO: support DBCS under GTK+ + return false; +#elif PLAT_WIN + return codePage && IsDBCSLeadByteEx(codePage, ch); +#elif PLAT_WX + return false; +#endif +} + +inline bool iswordchar(char ch) { + return isalnum(ch) || ch == '.' || ch == '_'; +} + +inline bool iswordstart(char ch) { + return isalnum(ch) || ch == '_'; +} + +enum { wsSpace = 1, wsTab = 2, wsSpaceTab = 4, wsInconsistent=8}; + +static int IndentAmount(StylingContext &styler, int line, int *flags) { + int end = styler.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 = styler.LineStart(line); + char ch = styler[pos]; + int indent = 0; + bool inPrevPrefix = line > 0; + int posPrev = inPrevPrefix ? styler.LineStart(line-1) : 0; + while ((ch == ' ' || ch == '\t') && (pos < end)) { + if (inPrevPrefix) { + char chPrev = styler[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 = styler[++pos]; + } + + *flags = spaceFlags; + indent += SC_FOLDLEVELBASE; + if (isspace(ch)) // Completely empty line + return indent | SC_FOLDLEVELWHITEFLAG; + else + return indent; +} + +inline bool isoperator(char ch) { + if (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; +} + +static void classifyWordCpp(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_C_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_C_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_C_WORD; + } + styler.ColourSegment(start, end, chAttr); +} + +static void ColouriseCppDoc(int codePage, int startPos, int length, + int initStyle, WordList &keywords, StylingContext &styler) { + + bool fold = styler.GetPropSet().GetInt("fold"); + int lineCurrent = styler.GetLine(startPos); + int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; + int levelCurrent = levelPrev; + + int state = initStyle; + char chPrev = ' '; + char chNext = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + int visChars = 0; + for (unsigned int i = startPos; i <= lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if ((fold) && ((ch == '\r' && chNext != '\n') || (ch == '\n'))) { + int lev = levelPrev; + if (visChars == 0) + lev |= SC_FOLDLEVELWHITEFLAG; + if ((levelCurrent > levelPrev) && (visChars > 0)) + lev |= SC_FOLDLEVELHEADERFLAG; + styler.SetLevel(lineCurrent, lev); + lineCurrent++; + visChars = 0; + levelPrev = levelCurrent; + } + if (!isspace(ch)) + visChars++; + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_C_STRINGEOL) { + if (ch != '\r' && ch != '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } + if (state == SCE_C_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_WORD; + startSeg = i; + } else if (ch == '/' && chNext == '*') { + styler.ColourSegment(startSeg, i - 1, state); + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_C_COMMENTDOC; + else + state = SCE_C_COMMENT; + startSeg = i; + } else if (ch == '/' && chNext == '/') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRING; + startSeg = i; + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_CHARACTER; + startSeg = i; + } else if (ch == '#') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_PREPROCESSOR; + startSeg = i; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_C_OPERATOR); + startSeg = i + 1; + if ((ch == '{') || (ch == '}')) { + levelCurrent += (ch == '{') ? 1 : -1; + } + } + } else if (state == SCE_C_WORD) { + if (!iswordchar(ch)) { + classifyWordCpp(startSeg, i - 1, keywords, styler); + state = SCE_C_DEFAULT; + startSeg = i; + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_C_COMMENTDOC; + else + state = SCE_C_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } else if (ch == '\'') { + state = SCE_C_CHARACTER; + } else if (ch == '#') { + state = SCE_C_PREPROCESSOR; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + if ((ch == '{') || (ch == '}')) { + levelCurrent += (ch == '{') ? 1 : -1; + } + } + } + } else { + if (state == SCE_C_PREPROCESSOR) { + if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_COMMENT) { + if (ch == '/' && chPrev == '*' && ( + (i > startSeg + 2) || ((initStyle == SCE_C_COMMENT) && (startSeg == startPos)))) { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_C_COMMENTDOC) { + if (ch == '/' && chPrev == '*' && ( + (i > startSeg + 3) || ((initStyle == SCE_C_COMMENTDOC) && (startSeg == startPos)))) { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_C_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_STRING) { + if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRINGEOL; + startSeg = i; + } else if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_C_CHARACTER) { + if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRINGEOL; + startSeg = i; + } else if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } + if (state == SCE_C_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_C_COMMENTDOC; + else + state = SCE_C_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } else if (ch == '\'') { + state = SCE_C_CHARACTER; + } else if (ch == '#') { + state = SCE_C_PREPROCESSOR; + } else if (iswordstart(ch)) { + state = SCE_C_WORD; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + if ((ch == '{') || (ch == '}')) { + levelCurrent += (ch == '{') ? 1 : -1; + } + } + } + } + chPrev = ch; + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc - 1, state); + // Fill in the real level of the next line, keeping the current flags as they will be filled in later + if (fold) { + int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; + //styler.SetLevel(lineCurrent, levelCurrent | flagsNext); + styler.SetLevel(lineCurrent, levelPrev | flagsNext); + + } +} + +inline bool isPerlOperator(char ch) { + if (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 == '.' || ch == '~') + return true; + return false; +} + +static int classifyWordPerl(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_PL_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_PL_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_PL_WORD; + } + styler.ColourSegment(start, end, chAttr); + return chAttr; +} + +static bool isEndVar(char ch) { + return !isalnum(ch) && ch != '#' && ch != '$' && + ch != '_' && ch != '\''; +} + +static bool isMatch(StylingContext &styler, int lengthDoc, int pos, const char *val) { + if ((pos + static_cast(strlen(val))) >= lengthDoc) { + return false; + } + while (*val) { + if (*val != styler[pos++]) { + return false; + } + val++; + } + return true; +} + +static bool isOKQuote(char ch) { + if (isalnum(ch)) + return false; + if (isspace(ch)) + return false; + if (iscntrl(ch)) + return false; + return true; +} + +static char opposite(char ch) { + if (ch == '(') + return ')'; + if (ch == '[') + return ']'; + if (ch == '{') + return '}'; + if (ch == '<') + return '>'; + return ch; +} + +static void ColourisePerlDoc(int codePage, int startPos, int length, int initStyle, + WordList &keywords, StylingContext &styler) { + char sooked[100]; + int quotes = 0; + char quoteDown = 'd'; + char quoteUp = 'd'; + int quoteRep = 1; + int sookedpos = 0; + bool preferRE = true; + sooked[sookedpos] = '\0'; + int state = initStyle; + int lengthDoc = startPos + length; + // If in a long distance lexical state, seek to the beginning to find quote characters + if (state == SCE_PL_HERE || state == SCE_PL_REGEX || + state == SCE_PL_REGSUBST || state == SCE_PL_LONGQUOTE) { + while ((startPos > 1) && (styler.StyleAt(startPos - 1) == state)) { + startPos--; + } + state = SCE_PL_DEFAULT; + } + styler.StartAt(startPos); + char chPrev = ' '; + char chNext = styler[startPos]; + int startSeg = startPos; + for (int i = startPos; i <= lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + char chNext2 = styler.SafeGetCharAt(i + 2); + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_PL_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + if (ch == 's' && !isalnum(chNext)) { + state = SCE_PL_REGSUBST; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 2; + startSeg = i; + } else if (ch == 'm' && !isalnum(chNext)) { + state = SCE_PL_REGEX; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 1; + startSeg = i; + } else if (ch == 't' && chNext == 'r' && !isalnum(chNext2)) { + state = SCE_PL_REGSUBST; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 2; + startSeg = i; + i++; + chNext = chNext2; + } else if (ch == 'q' && (chNext == 'q' || chNext == 'r' || chNext == 'w' || chNext == 'x') && !isalnum(chNext2)) { + state = SCE_PL_LONGQUOTE; + startSeg = i; + i++; + chNext = chNext2; + quotes = 0; + quoteUp = '\0'; + quoteDown = '\0'; + quoteRep = 1; + } else { + state = SCE_PL_WORD; + startSeg = i; + preferRE = false; + } + } else if (ch == '#') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_STRING; + startSeg = i; + } else if (ch == '\'') { + if (chPrev == '&') { + // Archaic call + styler.ColourSegment(i, i, state); + startSeg = i + 1; + } else { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_CHARACTER; + startSeg = i; + } + } else if (ch == '`') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_BACKTICKS; + startSeg = i; + } else if (ch == '$') { + preferRE = false; + styler.ColourSegment(startSeg, i - 1, state); + if (isalnum(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { + state = SCE_PL_SCALAR; + startSeg = i; + } else if (chNext != '{' && chNext != '[') { + styler.ColourSegment(i - 1, i, SCE_PL_SCALAR); + i++; + startSeg = i + 1; + ch = ' '; + chNext = ' '; + } else { + styler.ColourSegment(i, i, SCE_PL_SCALAR); + startSeg = i + 1; + } + } else if (ch == '@') { + preferRE = false; + styler.ColourSegment(startSeg, i - 1, state); + if (isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { + state = SCE_PL_ARRAY; + startSeg = i; + } else if (chNext != '{' && chNext != '[') { + styler.ColourSegment(i - 1, i, SCE_PL_ARRAY); + i++; + startSeg = i + 1; + ch = ' '; + } else { + styler.ColourSegment(i, i, SCE_PL_ARRAY); + startSeg = i + 1; + } + } else if (ch == '%') { + preferRE = false; + styler.ColourSegment(startSeg, i - 1, state); + if (isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { + state = SCE_PL_HASH; + startSeg = i; + } else if (chNext != '{' && chNext != '[') { + styler.ColourSegment(i - 1, i, SCE_PL_HASH); + i++; + startSeg = i + 1; + ch = ' '; + } else { + styler.ColourSegment(i, i, SCE_PL_HASH); + startSeg = i + 1; + } + } else if (ch == '*') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_SYMBOLTABLE; + startSeg = i; + } else if (ch == '/' && preferRE) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_REGEX; + quoteUp = '/'; + quoteDown = '/'; + quotes = 1; + quoteRep = 1; + startSeg = i; + } else if (ch == '<' && chNext == '<') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_HERE; + startSeg = i; + i++; + ch = chNext; + chNext = chNext2; + quotes = 0; + sookedpos = 0; + sooked[sookedpos] = '\0'; + } else if (ch == '=' && isalpha(chNext)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_POD; + startSeg = i; + quotes = 0; + sookedpos = 0; + sooked[sookedpos] = '\0'; + } else if (isPerlOperator(ch)) { + if (ch == ')' || ch == ']') + preferRE = false; + else + preferRE = true; + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_PL_OPERATOR); + startSeg = i + 1; + } + } else if (state == SCE_PL_WORD) { + if (!iswordchar(ch) && ch != '\'') { // Archaic Perl has quotes inside names + if (isMatch(styler, lengthDoc, startSeg, "__DATA__")) { + styler.ColourSegment(startSeg, i, SCE_PL_DATASECTION); + state = SCE_PL_DATASECTION; + } else if (isMatch(styler, lengthDoc, startSeg, "__END__")) { + styler.ColourSegment(startSeg, i, SCE_PL_DATASECTION); + state = SCE_PL_DATASECTION; + } else { + if (classifyWordPerl(startSeg, i - 1, keywords, styler) == SCE_PL_WORD) + preferRE = true; + state = SCE_PL_DEFAULT; + startSeg = i; + if (ch == '#') { + state = SCE_PL_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_PL_STRING; + } else if (ch == '\'') { + state = SCE_PL_CHARACTER; + } else if (ch == '<' && chNext == '<') { + state = SCE_PL_HERE; + quotes = 0; + startSeg = i; + sookedpos = 0; + sooked[sookedpos] = '\0'; + } else if (isPerlOperator(ch)) { + if (ch == ')' || ch == ']') + preferRE = false; + else + preferRE = true; + styler.ColourSegment(startSeg, i, SCE_PL_OPERATOR); + state = SCE_PL_DEFAULT; + startSeg = i + 1; + } + } + } + } else { + if (state == SCE_PL_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_PL_DEFAULT; + startSeg = i; + } + } else if (state == SCE_PL_HERE) { + if (isalnum(ch) && quotes < 2) { + sooked[sookedpos++] = ch; + sooked[sookedpos] = '\0'; + if (quotes == 0) + quotes = 1; + } else { + quotes++; + } + + if (quotes > 1 && isMatch(styler, lengthDoc, i, sooked)) { + styler.ColourSegment(startSeg, i + sookedpos - 1, SCE_PL_HERE); + state = SCE_PL_DEFAULT; + i += sookedpos; + startSeg = i; + chNext = ' '; + } + } else if (state == SCE_PL_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_PL_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_PL_CHARACTER) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_PL_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_PL_BACKTICKS) { + if (ch == '`') { + styler.ColourSegment(startSeg, i, state); + state = SCE_PL_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } else if (state == SCE_PL_POD) { + if (ch == '=') { + if (isMatch(styler, lengthDoc, i, "=cut")) { + styler.ColourSegment(startSeg, i - 1 + 4, state); + i += 4; + startSeg = i; + state = SCE_PL_DEFAULT; + chNext = ' '; + ch = ' '; + } + } + } else if (state == SCE_PL_SCALAR) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_ARRAY) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_HASH) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_SYMBOLTABLE) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_REF) { + if (isEndVar(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + state = SCE_PL_DEFAULT; + } + } else if (state == SCE_PL_REGEX) { + if (!quoteUp && !isspace(ch)) { + quoteUp = ch; + quoteDown = opposite(ch); + quotes++; + } else { + if (ch == quoteDown && chPrev != '\\') { + quotes--; + if (quotes == 0) { + quoteRep--; + if (quoteUp == quoteDown) { + quotes++; + } + } + if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + } else if (ch == quoteUp && chPrev != '\\') { + quotes++; + } else if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + } + } else if (state == SCE_PL_REGSUBST) { + if (!quoteUp && !isspace(ch)) { + quoteUp = ch; + quoteDown = opposite(ch); + quotes++; + } else { + if (ch == quoteDown && chPrev != '\\') { + quotes--; + if (quotes == 0) { + quoteRep--; + } + if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + if (quoteUp == quoteDown) { + quotes++; + } + } else if (ch == quoteUp && chPrev != '\\') { + quotes++; + } else if (!isalpha(chNext)) { + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + } + } + } else if (state == SCE_PL_LONGQUOTE) { + if (!quoteDown && !isspace(ch)) { + quoteUp = ch; + quoteDown = opposite(quoteUp); + quotes++; + } else if (ch == quoteDown) { + quotes--; + if (quotes == 0) { + quoteRep--; + if (quoteRep <= 0) { + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + state = SCE_PL_DEFAULT; + ch = ' '; + } + if (quoteUp == quoteDown) { + quotes++; + } + } + } else if (ch == quoteUp) { + quotes++; + } + } + + if (state == SCE_PL_DEFAULT) { // One of the above succeeded + if (ch == '#') { + state = SCE_PL_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_PL_STRING; + } else if (ch == '\'') { + state = SCE_PL_CHARACTER; + } else if (iswordstart(ch)) { + state = SCE_PL_WORD; + preferRE = false; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_PL_OPERATOR); + startSeg = i + 1; + } + } + } + chPrev = ch; + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc, state); +} + + +static int classifyWordVB(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } + char chAttr = SCE_C_DEFAULT; + if (wordIsNumber) + chAttr = SCE_C_NUMBER; + else { + if (keywords.InList(s)) { + chAttr = SCE_C_WORD; + if (strcmp(s, "rem") == 0) + chAttr = SCE_C_COMMENTLINE; + } + } + styler.ColourSegment(start, end, chAttr); + if (chAttr == SCE_C_COMMENTLINE) + return SCE_C_COMMENTLINE; + else + return SCE_C_DEFAULT; +} + +static void ColouriseVBDoc(int codePage, int startPos, int length, int initStyle, + WordList &keywords, StylingContext &styler) { + int state = initStyle; + char chNext = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + for (int i = startPos; i < lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + i += 1; + continue; + } + + if (state == SCE_C_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_WORD; + startSeg = i; + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRING; + startSeg = i; + } + } else if (state == SCE_C_WORD) { + if (!iswordchar(ch)) { + state = classifyWordVB(startSeg, i - 1, keywords, styler); + if (state == SCE_C_DEFAULT) { + startSeg = i; + if (ch == '\'') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } + } + } + } else { + if (state == SCE_C_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_STRING) { + // VB doubles quotes to preserve them + if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + startSeg = i; + } + } + if (state == SCE_C_DEFAULT) { // One of the above succeeded + if (ch == '\'') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_C_STRING; + } else if (iswordstart(ch)) { + state = SCE_C_WORD; + } + } + } + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc, state); +} + +static void classifyWordPy(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler, char *prevWord) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_P_IDENTIFIER; + if (0 == strcmp(prevWord, "class")) + chAttr = SCE_P_CLASSNAME; + else if (0 == strcmp(prevWord, "def")) + chAttr = SCE_P_DEFNAME; + else if (wordIsNumber) + chAttr = SCE_P_NUMBER; + else if (keywords.InList(s)) + chAttr = SCE_P_WORD; + styler.ColourSegment(start, end, chAttr); + strcpy(prevWord, s); +} + +static void ColourisePyDoc(int codePage, int startPos, int length, int initStyle, WordList &keywords, StylingContext &styler) { + //Platform::DebugPrintf("Python coloured\n"); + bool fold = styler.GetPropSet().GetInt("fold"); + int whingeLevel = styler.GetPropSet().GetInt("tab.timmy.whinge.level"); + char prevWord[200]; + prevWord[0] = '\0'; + if (length == 0) + return ; + int lineCurrent = styler.GetLine(startPos); + int spaceFlags = 0; + // TODO: Need to check previous line for indentation for both folding and bad indentation + int indentCurrent = IndentAmount(styler, lineCurrent, &spaceFlags); + + int state = initStyle & 31; + char chPrev = ' '; + char chPrev2 = ' '; + char chNext = styler[startPos]; + char chNext2 = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + bool atStartLine = true; + for (int i = startPos; i <= lengthDoc; i++) { + + if (atStartLine) { + if (whingeLevel == 1) { + styler.SetFlags((spaceFlags & wsInconsistent) ? 64 : 0, state); + } else if (whingeLevel == 2) { + styler.SetFlags((spaceFlags & wsSpaceTab) ? 64 : 0, state); + } else if (whingeLevel == 3) { + styler.SetFlags((spaceFlags & wsSpace) ? 64 : 0, state); + } else if (whingeLevel == 4) { + styler.SetFlags((spaceFlags & wsTab) ? 64 : 0, state); + } + atStartLine = false; + } + + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + chNext2 = styler.SafeGetCharAt(i + 2); + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + if ((state == SCE_P_DEFAULT) || (state == SCE_P_TRIPLE) || (state == SCE_P_TRIPLEDOUBLE)) { + // Perform colourisation of white space and triple quoted strings at end of each line to allow + // tab marking to work inside white space and triple quoted strings + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + } + + int lev = indentCurrent; + int indentNext = IndentAmount(styler, lineCurrent + 1, &spaceFlags); + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { + // Only non whitespace lines can be headers + if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + } + indentCurrent = indentNext; + if (fold) { + styler.SetLevel(lineCurrent, lev); + } + lineCurrent++; + atStartLine = true; + } + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + chPrev2 = ' '; + i += 1; + continue; + } + + if (state == SCE_P_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_P_WORD; + startSeg = i; + } else if (ch == '#') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_P_COMMENTLINE; + startSeg = i; + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_P_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_STRING; + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + startSeg = i; + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_P_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_P_OPERATOR); + startSeg = i + 1; + } + } else if (state == SCE_P_WORD) { + if (!iswordchar(ch)) { + classifyWordPy(startSeg, i - 1, keywords, styler, prevWord); + state = SCE_P_DEFAULT; + startSeg = i; + if (ch == '#') { + state = SCE_P_COMMENTLINE; + } else if (ch == '\"') { + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_P_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_STRING; + } + } else if (ch == '\'') { + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_P_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_P_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_P_OPERATOR); + startSeg = i + 1; + } + } + } else { + if (state == SCE_P_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_P_DEFAULT; + startSeg = i; + } + } else if (state == SCE_P_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_P_CHARACTER) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_P_TRIPLE) { + if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } else if (state == SCE_P_TRIPLEDOUBLE) { + if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { + styler.ColourSegment(startSeg, i, state); + state = SCE_P_DEFAULT; + startSeg = i + 1; + } + } + } + chPrev2 = chPrev; + chPrev = ch; + } + if (startSeg <= lengthDoc) { + if (state == SCE_P_DEFAULT) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_WORD) { + classifyWordPy(startSeg, lengthDoc, keywords, styler, prevWord); + } else if (state == SCE_P_COMMENTLINE) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_STRING) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_CHARACTER) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_TRIPLE) { + styler.ColourSegment(startSeg, lengthDoc, state); + } else if (state == SCE_P_TRIPLEDOUBLE) { + styler.ColourSegment(startSeg, lengthDoc, state); + } + } +} + +static void ColouriseBatchLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + if (0 == strncmp(lineBuffer, "REM", 3)) { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (0 == strncmp(lineBuffer, "rem", 3)) { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (0 == strncmp(lineBuffer, "SET", 3)) { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if (0 == strncmp(lineBuffer, "set", 3)) { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if (lineBuffer[0] == ':') { + styler.ColourSegment(0, lengthLine - 1, 3); + } else { + styler.ColourSegment(0, lengthLine - 1, 0); + } +} + +static void ColouriseBatchDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i < startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + ColouriseBatchLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColouriseBatchLine(lineBuffer, linePos, styler); +} + +enum { eScriptNone, eScriptJS, eScriptVBS, eScriptPython }; +static int segIsScriptingIndicator(StylingContext &styler, unsigned int start, unsigned int end, int prevValue) { + char s[100]; + s[0] = '\0'; + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } +Platform::DebugPrintf("Scripting indicator [%s]\n", s); + if (strstr(s, "vbs")) + return eScriptVBS; + if (strstr(s, "pyth")) + return eScriptPython; + if (strstr(s, "javas")) + return eScriptJS; + if (strstr(s, "jscr")) + return eScriptJS; + + return prevValue; +} + +static void classifyAttribHTML(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.') || + (styler[start] == '-') || (styler[start] == '#'); + char chAttr = SCE_H_ATTRIBUTEUNKNOWN; + if (wordIsNumber) { + chAttr = SCE_H_NUMBER; + } else { + char s[100]; + s[0] = '\0'; + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } + if (keywords.InList(s)) + chAttr = SCE_H_ATTRIBUTE; + } + styler.ColourTo(end, chAttr); +} + +static int classifyTagHTML(unsigned int start, unsigned int end, + WordList &keywords, StylingContext &styler) { + char s[100]; + // Copy after the '<' + unsigned int i = 0; + for (int cPos=start; cPos <= end && i < 30; cPos++) { + char ch = styler[cPos]; + if (ch != '<') + s[i++] = tolower(ch); + } + s[i] = '\0'; + char chAttr = SCE_H_TAGUNKNOWN; + if (s[0] == '!' && s[1] == '-' && s[2] == '-') { //Comment + chAttr = SCE_H_COMMENT; + } else if (s[0] == '/') { // Closing tag + if (keywords.InList(s + 1)) + chAttr = SCE_H_TAG; + } else { + if (keywords.InList(s)) { + chAttr = SCE_H_TAG; + if (0 == strcmp(s, "script")) + chAttr = SCE_H_SCRIPT; + } + } + styler.ColourTo(end, chAttr); + return chAttr; +} + +static void classifyWordHTJS(unsigned int start, unsigned int end, + WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_HJ_WORD; + if (wordIsNumber) + chAttr = SCE_HJ_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_HJ_KEYWORD; + } + styler.ColourTo(end, chAttr); +} + +static int classifyWordHTVB(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = tolower(styler[start + i]); + s[i + 1] = '\0'; + } + char chAttr = SCE_HB_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_HB_NUMBER; + else { + if (keywords.InList(s)) { + chAttr = SCE_HB_WORD; + if (strcmp(s, "rem") == 0) + chAttr = SCE_HB_COMMENTLINE; + } + } + styler.ColourTo(end, chAttr); + if (chAttr == SCE_HB_COMMENTLINE) + return SCE_HB_COMMENTLINE; + else + return SCE_HB_DEFAULT; +} + +static void classifyWordHTPy(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler, char *prevWord) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = styler[start + i]; + s[i + 1] = '\0'; + } + char chAttr = SCE_HP_IDENTIFIER; + if (0 == strcmp(prevWord, "class")) + chAttr = SCE_HP_CLASSNAME; + else if (0 == strcmp(prevWord, "def")) + chAttr = SCE_HP_DEFNAME; + else if (wordIsNumber) + chAttr = SCE_HP_NUMBER; + else if (keywords.InList(s)) + chAttr = SCE_HP_WORD; + styler.ColourTo(end, chAttr); + strcpy(prevWord, s); +} + +inline bool ishtmlwordchar(char ch) { + return isalnum(ch) || ch == '.' || ch == '-' || ch == '_' || ch == ':' || ch == '!' || ch == '#'; +} + +static bool InTagState(int state) { + return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN || + state == SCE_H_SCRIPT || + state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN || + state == SCE_H_NUMBER || state == SCE_H_OTHER || + state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING; +} + +static bool isLineEnd(char ch) { + return ch == '\r' || ch == '\n'; +} + +static void ColouriseHyperTextDoc(int codePage, int startPos, int length, + int initStyle, WordList &keywords, WordList &keywords2, WordList &keywords3, WordList &keywords4, + StylingContext &styler) { + + styler.StartAt(startPos, 63); + bool lastTagWasScript = false; + char prevWord[200]; + prevWord[0] = '\0'; + int scriptLanguage = eScriptJS; + int state = initStyle; + // If inside a tag, it may be a script tage, so reread from the start to ensure any language tas are seen + if (InTagState(state)) { + while ((startPos > 1) && (InTagState(styler.StyleAt(startPos - 1)))) { + startPos--; + } + state = SCE_H_DEFAULT; + } + styler.StartAt(startPos, 63); + + int lineState = eScriptVBS; + int lineCurrent = styler.GetLine(startPos); + if (lineCurrent > 0) + lineState = styler.GetLineState(lineCurrent); + int defaultScript = lineState &0xff; + int beforeASP = (lineState >> 8) &0xff; + int inASP = (lineState >> 16) &0xff; + + char chPrev = ' '; + char chPrev2 = ' '; + styler.StartSegment(startPos); + int lengthDoc = startPos + length; + for (int i = startPos; i <= lengthDoc; i++) { + char ch = styler[i]; + char chNext = styler.SafeGetCharAt(i + 1); + char chNext2 = styler.SafeGetCharAt(i + 2); + + if (IsLeadByte(codePage, ch)) { // dbcs + chPrev2 = ' '; + chPrev = ' '; + i += 1; + continue; + } + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + // New line -> record any line state onto /next/ line + lineCurrent++; + styler.SetLineState(lineCurrent, + defaultScript | (beforeASP << 8) | (inASP << 16)); + } + + // Handle ASP even within other constructs as it is a preprocessor + if ((ch == '<') && (chNext == '%')) { + beforeASP = state; + styler.ColourTo(i - 1, state); + if (chNext2 == '@') { + styler.ColourTo(i + 2, SCE_H_ASP); + state = SCE_H_ASPAT; + i+=2; + } else { + if (defaultScript == eScriptVBS) + state = SCE_HB_START; + else if (defaultScript == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + if (chNext2 == '=') { + styler.ColourTo(i + 2, SCE_H_ASP); + i+=2; + } else { + styler.ColourTo(i + 1, SCE_H_ASP); + i++; + } + } + inASP = 1; + continue; + } + if (inASP && (ch == '%') && (chNext == '>')) { + if (state == SCE_H_ASPAT) + defaultScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i-1, defaultScript); + // Bounce out of any ASP mode + styler.ColourTo(i - 1, state); + //if (state == SCE_H_ASPAT) + // styler.ColourTo(i+1, SCE_H_ASPAT); + //else + styler.ColourTo(i+1, SCE_H_ASP); + i++; + state = beforeASP; + beforeASP = SCE_H_DEFAULT; + inASP = 0; + continue; + } + + if (state == SCE_H_DEFAULT) { + if (ch == '<') { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + if (chNext == '?') { + styler.ColourTo(i + 1, SCE_H_XMLSTART); + i++; + ch = chNext; + } + } else if (ch == '&') { + styler.ColourTo(i - 1, SCE_H_DEFAULT); + state = SCE_H_ENTITY; + } + } else if (state == SCE_H_COMMENT) { + if ((ch == '>') && (chPrev == '-')) { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_ENTITY) { + if (ch == ';') { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_TAGUNKNOWN) { + if (!ishtmlwordchar(ch) && ch != '/' && ch != '-') { + int eClass = classifyTagHTML(styler.GetStartSegment(), i - 1, keywords, styler); + lastTagWasScript = eClass == SCE_H_SCRIPT; + if (lastTagWasScript) { + scriptLanguage = eScriptJS; + eClass = SCE_H_TAG; + } + if (ch == '>') { + styler.ColourTo(i, SCE_H_TAG); + if (lastTagWasScript) { + if (scriptLanguage == eScriptVBS) + state = SCE_HB_START; + else if (scriptLanguage == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + } else { + state = SCE_H_DEFAULT; + } + } else { + if (eClass == SCE_H_COMMENT) { + state = SCE_H_COMMENT; + } else { + state = SCE_H_OTHER; + } + } + } + } else if (state == SCE_H_ATTRIBUTE) { + if (!ishtmlwordchar(ch) && ch != '/' && ch != '-') { + if (lastTagWasScript) + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i-1, scriptLanguage); + classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler); + if (ch == '>') { + styler.ColourTo(i, SCE_H_TAG); + if (lastTagWasScript) { + if (scriptLanguage == eScriptVBS) + state = SCE_HB_START; + else if (scriptLanguage == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + } else { + state = SCE_H_DEFAULT; + } + } else { + state = SCE_H_OTHER; + } + } + } else if (state == SCE_H_ASP) { + if ((ch == '>') && (chPrev == '%')) { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_ASPAT) { + if ((ch == '>') && (chPrev == '%')) { + styler.ColourTo(i, state); + state = SCE_H_DEFAULT; + } + } else if (state == SCE_H_OTHER) { + if (ch == '>') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_H_TAG); + if (lastTagWasScript) { + if (scriptLanguage == eScriptVBS) + state = SCE_HB_START; + else if (scriptLanguage == eScriptPython) + state = SCE_HP_START; + else + state = SCE_HJ_START; + } else { + state = SCE_H_DEFAULT; + } + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + state = SCE_H_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + state = SCE_H_SINGLESTRING; + } else if (ch == '/' && chNext == '>') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } else if (ch == '?' && chNext == '>') { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_XMLEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } else if (ishtmlwordchar(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_H_ATTRIBUTE; + } + } else if (state == SCE_H_DOUBLESTRING) { + if (ch == '\"') { + if (lastTagWasScript) + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); + styler.ColourTo(i, SCE_H_DOUBLESTRING); + state = SCE_H_OTHER; + } + } else if (state == SCE_H_SINGLESTRING) { + if (ch == '\'') { + if (lastTagWasScript) + scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); + styler.ColourTo(i, SCE_H_SINGLESTRING); + state = SCE_H_OTHER; + } + } else if (state == SCE_HJ_DEFAULT || state == SCE_HJ_START) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HJ_WORD; + } else if (ch == '/' && chNext == '*') { + styler.ColourTo(i - 1, state); + if (chNext2 == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_SINGLESTRING; + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, state); + state = SCE_HJ_COMMENTLINE; + } else if (isoperator(ch)) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_HJ_SYMBOLS); + state = SCE_HJ_DEFAULT; + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HJ_START) { + styler.ColourTo(i - 1, state); + state = SCE_HJ_DEFAULT; + } + } + } else if (state == SCE_HJ_WORD) { + if (!iswordchar(ch)) { + classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler); + //styler.ColourTo(i - 1, eHTJSKeyword); + state = SCE_HJ_DEFAULT; + if (ch == '/' && chNext == '*') { + if (chNext2 == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + state = SCE_HJ_SINGLESTRING; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HJ_SYMBOLS); + state = SCE_HJ_DEFAULT; + } + } + } else if (state == SCE_HJ_COMMENT) { + if (ch == '/' && chPrev == '*') { + state = SCE_HJ_DEFAULT; + styler.ColourTo(i, SCE_HJ_COMMENT); + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } + } else if (state == SCE_HJ_COMMENTDOC) { + if (ch == '/' && chPrev == '*') { + state = SCE_HJ_DEFAULT; + styler.ColourTo(i, SCE_HJ_COMMENTDOC); + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i + 1, SCE_H_TAGEND); + i++; + ch = chNext; + state = SCE_H_DEFAULT; + } + } else if (state == SCE_HJ_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, SCE_HJ_COMMENTLINE); + state = SCE_HJ_DEFAULT; + } else if ((ch == '<') && (chNext == '/')) { + // Common to hide end script tag in comment + styler.ColourTo(i - 1, SCE_HJ_COMMENTLINE); + state = SCE_H_TAGUNKNOWN; + } + } else if (state == SCE_HJ_DOUBLESTRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + } + } else if (ch == '\"') { + styler.ColourTo(i, SCE_HJ_DOUBLESTRING); + state = SCE_HJ_DEFAULT; + i++; + ch = chNext; + } else if (isLineEnd(ch)) { + styler.ColourTo(i-1, state); + state = SCE_HJ_STRINGEOL; + } + } else if (state == SCE_HJ_SINGLESTRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + } + } else if (ch == '\'') { + styler.ColourTo(i, SCE_HJ_SINGLESTRING); + state = SCE_HJ_DEFAULT; + i++; + ch = chNext; + } else if (isLineEnd(ch)) { + styler.ColourTo(i-1, state); + state = SCE_HJ_STRINGEOL; + } + } else if (state == SCE_HJ_STRINGEOL) { + if (!isLineEnd(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HJ_DEFAULT; + } + } else if (state == SCE_HB_DEFAULT || state == SCE_HB_START) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HB_WORD; + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + state = SCE_HB_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + state = SCE_HB_STRING; + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, state); + state = SCE_HB_COMMENTLINE; + } else if (isoperator(ch)) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_HB_DEFAULT); + state = SCE_HB_DEFAULT; + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HB_START) { + styler.ColourTo(i - 1, state); + state = SCE_HB_DEFAULT; + } + } + } else if (state == SCE_HB_WORD) { + if (!iswordchar(ch)) { + state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler); + if (state == SCE_HB_DEFAULT) { + if (ch == '\"') { + state = SCE_HB_STRING; + } else if (ch == '\'') { + state = SCE_HB_COMMENTLINE; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HB_DEFAULT); + state = SCE_HB_DEFAULT; + } + } + } + } else if (state == SCE_HB_STRING) { + if (ch == '\"') { + styler.ColourTo(i, state); + state = SCE_HB_DEFAULT; + i++; + ch = chNext; + } else if (ch == '\r' || ch == '\n') { + styler.ColourTo(i-1, state); + state = SCE_HB_STRINGEOL; + } + } else if (state == SCE_HB_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, state); + state = SCE_HB_DEFAULT; + } else if ((ch == '<') && (chNext == '/')) { + // Common to hide end script tag in comment + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } + } else if (state == SCE_HB_STRINGEOL) { + if (!isLineEnd(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HB_DEFAULT; + } + } else if (state == SCE_HP_DEFAULT || state == SCE_HP_START) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, state); + state = SCE_HP_WORD; + } else if ((ch == '<') && (chNext == '/')) { + styler.ColourTo(i - 1, state); + state = SCE_H_TAGUNKNOWN; + } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && + styler.SafeGetCharAt(i + 3) == '-') { + styler.ColourTo(i - 1, state); + state = SCE_HP_COMMENTLINE; + } else if (ch == '#') { + styler.ColourTo(i - 1, state); + state = SCE_HP_COMMENTLINE; + } else if (ch == '\"') { + styler.ColourTo(i - 1, state); + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_HP_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_STRING; + } + } else if (ch == '\'') { + styler.ColourTo(i - 1, state); + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_HP_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourTo(i - 1, state); + styler.ColourTo(i, SCE_HP_OPERATOR); + } else if ((ch == ' ') || (ch == '\t')) { + if (state == SCE_HP_START) { + styler.ColourTo(i - 1, state); + state = SCE_HP_DEFAULT; + } + } + } else if (state == SCE_HP_WORD) { + if (!iswordchar(ch)) { + classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord); + state = SCE_HP_DEFAULT; + if (ch == '#') { + state = SCE_HP_COMMENTLINE; + } else if (ch == '\"') { + if (chNext == '\"' && chNext2 == '\"') { + i += 2; + state = SCE_HP_TRIPLEDOUBLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_STRING; + } + } else if (ch == '\'') { + if (chNext == '\'' && chNext2 == '\'') { + i += 2; + state = SCE_HP_TRIPLE; + ch = ' '; + chPrev = ' '; + chNext = styler.SafeGetCharAt(i + 1); + } else { + state = SCE_HP_CHARACTER; + } + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HP_OPERATOR); + } + } + } else { + if (state == SCE_HP_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_STRING) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\"') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_CHARACTER) { + if (ch == '\\') { + if (chNext == '\"' || chNext == '\'' || chNext == '\\') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } else if (ch == '\'') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_TRIPLE) { + if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } else if (state == SCE_HP_TRIPLEDOUBLE) { + if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { + styler.ColourTo(i, state); + state = SCE_HP_DEFAULT; + } + } + } + if (state == SCE_HB_DEFAULT) { // One of the above succeeded + if (ch == '\"') { + state = SCE_HB_STRING; + } else if (ch == '\'') { + state = SCE_HB_COMMENTLINE; + } else if (iswordstart(ch)) { + state = SCE_HB_WORD; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HB_DEFAULT); + } + } + if (state == SCE_HJ_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + if (styler.SafeGetCharAt(i + 2) == '*') + state = SCE_HJ_COMMENTDOC; + else + state = SCE_HJ_COMMENT; + } else if (ch == '/' && chNext == '/') { + state = SCE_HJ_COMMENTLINE; + } else if (ch == '\"') { + state = SCE_HJ_DOUBLESTRING; + } else if (ch == '\'') { + state = SCE_HJ_SINGLESTRING; + } else if (iswordstart(ch)) { + state = SCE_HJ_WORD; + } else if (isoperator(ch)) { + styler.ColourTo(i, SCE_HJ_SYMBOLS); + } + } + chPrev2 = chPrev; + chPrev = ch; + } + styler.ColourTo(lengthDoc - 1, state); +} + +static void ColourisePropsLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + int i = 0; + while (isspace(lineBuffer[i]) && (i < lengthLine)) // Skip initial spaces + i++; + if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (lineBuffer[i] == '[') { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if (lineBuffer[i] == '@') { + styler.ColourSegment(0, i, 4); + if (lineBuffer[++i] == '=') + styler.ColourSegment(i, i, 3); + if (++i < lengthLine) + styler.ColourSegment(i, lengthLine - 1, 0); + } else { + while (lineBuffer[i] != '=' && (i < lengthLine)) // Search the '=' character + i++; + if (lineBuffer[i] == '=') { + styler.ColourSegment(0, i - 1, 0); + styler.ColourSegment(i, i, 3); + if (++i < lengthLine) + styler.ColourSegment(i, lengthLine - 1, 0); + } else + styler.ColourSegment(0, lengthLine - 1, 0); + } +} + +static void ColourisePropsDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i <= startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + lineBuffer[linePos] = '\0'; + ColourisePropsLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColourisePropsLine(lineBuffer, linePos, styler); +} + +static void ColouriseMakeLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + int i = 0; + while (isspace(lineBuffer[i]) && (i < lengthLine)) + i++; + if (lineBuffer[i] == '#' || lineBuffer[i] == '!') { + styler.ColourSegment(0, lengthLine - 1, 1); + } else { + styler.ColourSegment(0, lengthLine - 1, 0); + } +} + +static void ColouriseMakeDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i <= startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + ColouriseMakeLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColouriseMakeLine(lineBuffer, linePos, styler); +} + +static void ColouriseErrorListLine(char *lineBuffer, int lengthLine, StylingContext &styler) { + if (lineBuffer[0] == '>') { + // Command or return status + styler.ColourSegment(0, lengthLine - 1, 4); + } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) { + styler.ColourSegment(0, lengthLine - 1, 1); + } else if (0 == strncmp(lineBuffer, "Error ", strlen("Error "))) { + // Borland error message + styler.ColourSegment(0, lengthLine - 1, 5); + } else if (0 == strncmp(lineBuffer, "Warning ", strlen("Warning "))) { + // Borland warning message + styler.ColourSegment(0, lengthLine - 1, 5); + } else { + // Look for ::message + // Look for (line)message + // Look for (line,pos)message + int state = 0; + for (int i = 0; i < lengthLine; i++) { + if (state == 0 && lineBuffer[i] == ':' && isdigit(lineBuffer[i + 1])) { + state = 1; + } else if (state == 0 && lineBuffer[i] == '(') { + state = 10; + } else if (state == 1 && isdigit(lineBuffer[i])) { + state = 2; + } else if (state == 2 && lineBuffer[i] == ':') { + state = 3; + break; + } else if (state == 2 && !isdigit(lineBuffer[i])) { + state = 99; + } else if (state == 10 && isdigit(lineBuffer[i])) { + state = 11; + } else if (state == 11 && lineBuffer[i] == ',') { + state = 14; + } else if (state == 11 && lineBuffer[i] == ')') { + state = 12; + break; + } else if (state == 12 && lineBuffer[i] == ':') { + state = 13; + } else if (state == 14 && lineBuffer[i] == ')') { + state = 15; + break; + } else if (((state == 11) || (state == 14)) && !((lineBuffer[i] == ' ') || isdigit(lineBuffer[i]))) { + state = 99; + } + } + if (state == 3) { + styler.ColourSegment(0, lengthLine - 1, 2); + } else if ((state == 14) || (state == 15)) { + styler.ColourSegment(0, lengthLine - 1, 3); + } else { + styler.ColourSegment(0, lengthLine - 1, 0); + } + } +} + +static void ColouriseErrorListDoc(int startPos, int length, int, StylingContext &styler) { + char lineBuffer[1024]; + unsigned int linePos = 0; + for (int i = startPos; i <= startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (styler[i] == '\r' || styler[i] == '\n' || (linePos >= sizeof(lineBuffer) - 1)) { + ColouriseErrorListLine(lineBuffer, linePos, styler); + linePos = 0; + } + } + if (linePos > 0) + ColouriseErrorListLine(lineBuffer, linePos, styler); +} + +static void classifyWordSQL(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) { + char s[100]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { + s[i] = toupper(styler[start + i]); + s[i + 1] = '\0'; + } + char chAttr = SCE_C_IDENTIFIER; + if (wordIsNumber) + chAttr = SCE_C_NUMBER; + else { + if (keywords.InList(s)) + chAttr = SCE_C_WORD; + } + styler.ColourSegment(start, end, chAttr); +} + +static void ColouriseSQLDoc(int codePage, int startPos, int length, + int initStyle, WordList &keywords, StylingContext &styler) { + + bool fold = styler.GetPropSet().GetInt("fold"); + int lineCurrent = styler.GetLine(startPos); + int spaceFlags = 0; + int indentCurrent = 0; + + int state = initStyle; + char chPrev = ' '; + char chNext = styler[startPos]; + int startSeg = startPos; + int lengthDoc = startPos + length; + bool prevCr = false; + for (int i = startPos; i <= lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + indentCurrent = IndentAmount(styler, lineCurrent, &spaceFlags); + int lev = indentCurrent; + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { + // Only non whitespace lines can be headers + int indentNext = IndentAmount(styler, lineCurrent + 1, &spaceFlags); + if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + } + if (fold) { + styler.SetLevel(lineCurrent, lev); + } + } + + if (IsLeadByte(codePage, ch)) { // dbcs + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + if (state == SCE_C_DEFAULT) { + if (iswordstart(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_WORD; + startSeg = i; + } else if (ch == '/' && chNext == '*') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENT; + startSeg = i; + } else if (ch == '-' && chNext == '-') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_COMMENTLINE; + startSeg = i; + } else if (ch == '\'') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_STRING; + startSeg = i; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i - 1, state); + styler.ColourSegment(i, i, SCE_C_OPERATOR); + startSeg = i + 1; + } + } else if (state == SCE_C_WORD) { + if (!iswordchar(ch)) { + classifyWordSQL(startSeg, i - 1, keywords, styler); + state = SCE_C_DEFAULT; + startSeg = i; + if (ch == '/' && chNext == '*') { + state = SCE_C_COMMENT; + } else if (ch == '-' && chNext == '-') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\'') { + state = SCE_C_STRING; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + } + } + } else { + if (state == SCE_C_COMMENT) { + if (ch == '/' && chPrev == '*' && ( + (i > startSeg + 2) || ((initStyle == SCE_C_COMMENT) && (startSeg == startPos)))) { + state = SCE_C_DEFAULT; + styler.ColourSegment(startSeg, i, state); + startSeg = i + 1; + } + } else if (state == SCE_C_COMMENTLINE) { + if (ch == '\r' || ch == '\n') { + styler.ColourSegment(startSeg, i - 1, state); + state = SCE_C_DEFAULT; + startSeg = i; + } + } else if (state == SCE_C_STRING) { + if (ch == '\'') { + if ( chNext == '\'' ) { + i++; + } else { + styler.ColourSegment(startSeg, i, state); + state = SCE_C_DEFAULT; + i++; + startSeg = i; + } + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } + } + if (state == SCE_C_DEFAULT) { // One of the above succeeded + if (ch == '/' && chNext == '*') { + state = SCE_C_COMMENT; + } else if (ch == '-' && chNext == '-') { + state = SCE_C_COMMENTLINE; + } else if (ch == '\'') { + state = SCE_C_STRING; + } else if (iswordstart(ch)) { + state = SCE_C_WORD; + } else if (isoperator(ch)) { + styler.ColourSegment(startSeg, i, SCE_C_OPERATOR); + startSeg = i + 1; + } + } + } + chPrev = ch; + } + if (startSeg < lengthDoc) + styler.ColourSegment(startSeg, lengthDoc - 1, state); +} + +void ColouriseDoc(int codePage, int startPos, int lengthDoc, int initStyle, + int language, WordList *keywordlists[], StylingContext &styler) { + //Platform::DebugPrintf("ColouriseDoc <%s>\n", language); + if (language == SCLEX_PYTHON) { + // Python uses a different mask because bad indentation is marked by oring with 32 + styler.StartAt(startPos, 127); + ColourisePyDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_PERL) { + // Lexer for perl often has to backtrack to start of current style to determine + // which characters are being used as quotes, how deeply nested is the + // start position and what the termination string is for here documents + ColourisePerlDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if ((language == SCLEX_HTML) || (language == SCLEX_XML)) { + // Lexer for HTML requires more lexical states (6 bits worth) than most lexers + ColouriseHyperTextDoc(codePage, startPos, lengthDoc, initStyle, + *keywordlists[0], *keywordlists[1], *keywordlists[2], *keywordlists[3], styler); + } else { + styler.StartAt(startPos); + if (language == SCLEX_CPP) { + ColouriseCppDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_SQL) { + ColouriseSQLDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_VB) { + ColouriseVBDoc(codePage, startPos, lengthDoc, initStyle, *keywordlists[0], styler); + } else if (language == SCLEX_PROPERTIES) { + ColourisePropsDoc(startPos, lengthDoc, initStyle, styler); + } else if (language == SCLEX_ERRORLIST) { + ColouriseErrorListDoc(startPos, lengthDoc, initStyle, styler); + } else if (language == SCLEX_MAKEFILE) { + ColouriseMakeDoc(startPos, lengthDoc, initStyle, styler); + } else if (language == SCLEX_BATCH) { + ColouriseBatchDoc(startPos, lengthDoc, initStyle, styler); + } else { + // Null language means all style bytes are 0 so just mark the end - no need to fill in. + styler.StartAt(startPos + lengthDoc - 1); + styler.ColourSegment(0, 0, 0); + } + } +} diff --git a/src/stc/scintilla/src/LineMarker.cxx b/src/stc/scintilla/src/LineMarker.cxx new file mode 100644 index 0000000000..9afccb8227 --- /dev/null +++ b/src/stc/scintilla/src/LineMarker.cxx @@ -0,0 +1,125 @@ +// Scintilla source code edit control +// LineMarker.cxx - defines the look of a line marker in the margin +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include "Platform.h" + +#include "Scintilla.h" +#include "LineMarker.h" + +void LineMarker::Draw(Surface *surface, PRectangle &rc) { + 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; + 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) { + int armSize = dimOn2-2; + Point xpts[] = { + Point(centreX - armSize, centreY), + Point(centreX, centreY), + Point(centreX, centreY - armSize), + Point(centreX, centreY - armSize), + Point(centreX, centreY), + Point(centreX + armSize, centreY), + Point(centreX + armSize, centreY), + Point(centreX, centreY), + Point(centreX, centreY + armSize), + Point(centreX, centreY + armSize), + Point(centreX, centreY), + Point(centreX - armSize, centreY), + }; + 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) { + int armSize = dimOn2-2; + Point pts[] = { + Point(centreX - armSize, centreY - 1), + Point(centreX + armSize, centreY -1), + Point(centreX + armSize, centreY +1), + Point(centreX - armSize, centreY + 1), + }; + Point xpts[] = { + Point(centreX - armSize, centreY), + Point(centreX + armSize, centreY), + Point(centreX + armSize, centreY), + Point(centreX - armSize, centreY), + }; + 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) { + // An invisible marker so don't draw anything + } else { // 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); + } +} diff --git a/src/stc/scintilla/src/LineMarker.h b/src/stc/scintilla/src/LineMarker.h new file mode 100644 index 0000000000..f22241bb19 --- /dev/null +++ b/src/stc/scintilla/src/LineMarker.h @@ -0,0 +1,22 @@ +// Scintilla source code edit control +// LineMarker.h - defines the look of a line marker in the margin +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef LINEMARKER_H +#define LINEMARKER_H + +class LineMarker { +public: + int markType; + ColourPair fore; + ColourPair back; + LineMarker() { + markType = SC_MARK_CIRCLE; + fore = Colour(0,0,0); + back = Colour(0xff,0xff,0xff); + } + void Draw(Surface *surface, PRectangle &rc); +}; + +#endif diff --git a/src/stc/scintilla/src/PropSet.cxx b/src/stc/scintilla/src/PropSet.cxx new file mode 100644 index 0000000000..7e2a906a47 --- /dev/null +++ b/src/stc/scintilla/src/PropSet.cxx @@ -0,0 +1,399 @@ +// SciTE - Scintilla based Text Editor +// PropSet.cxx - a java style properties file module +// Copyright 1998-2000 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 + +#include "Platform.h" + +#include "PropSet.h" + +bool EqualCaseInsensitive(const char *a, const char *b) { +#if PLAT_GTK + return 0 == strcasecmp(a, b); +#elif PLAT_WIN + return 0 == stricmp(a, b); +#elif PLAT_WX + return 0 == wxStricmp(a, b); +#endif +} + +// Get a line of input. If end of line escaped with '\\' then continue reading. +static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) { + bool continuation = true; + while ((len > 1) && lenData > 0) { + char ch = *fpc; + fpc++; + lenData--; + if ((ch == '\r') || (ch == '\n')) { + if (!continuation) { + if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) { + // munch the second half of a crlf + fpc++; + lenData--; + } + *s++ = '\0'; + return true; + } + } else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) { + continuation = true; + } else { + continuation = false; + *s++ = ch; + len--; + } + } + return false; +} + +PropSet::PropSet() { + superPS = 0; + size = 10; + used = 0; + vals = new char * [size]; +} + +PropSet::~PropSet() { + superPS = 0; + Clear(); + delete []vals; +} + +void PropSet::EnsureCanAddEntry() { + if (used >= size - 2) { + int newsize = size + 10; + char **newvals = new char * [newsize]; + + for (int i = 0; i < used; i++) { + newvals[i] = vals[i]; + } + delete []vals; + vals = newvals; + size = newsize; + } +} + +void PropSet::Set(const char *key, const char *val) { + EnsureCanAddEntry(); + for (int i = 0; i < used; i += 2) { + if (EqualCaseInsensitive(vals[i], key)) { + // Replace current value + delete [](vals[i + 1]); + vals[i + 1] = StringDup(val); + return; + } + } + // Not found + vals[used++] = StringDup(key); + vals[used++] = StringDup(val); +} + +void PropSet::Set(char *keyval) { + char *eqat = strchr(keyval, '='); + if (eqat) { + *eqat = '\0'; + Set(keyval, eqat + 1); + *eqat = '='; + } +} + +SString PropSet::Get(const char *key) { + for (int i = 0; i < used; i += 2) { + if (EqualCaseInsensitive(vals[i], key)) { + return vals[i + 1]; + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->Get(key); + } else { + return ""; + } +} + +int PropSet::GetInt(const char *key, int defaultValue) { + SString val = Get(key); + if (val.length()) + return Get(key).value(); + else + return defaultValue; +} + +bool isprefix(const char *target, const char *prefix) { + while (*target && *prefix) { + if (toupper(*target) != toupper(*prefix)) + return false; + target++; + prefix++; + } + if (*prefix) + return false; + else + return true; +} + +bool issuffix(const char *target, const char *suffix) { + int lentarget = strlen(target); + int lensuffix = strlen(suffix); + if (lensuffix > lentarget) + return false; + for (int i = lensuffix - 1; i >= 0; i--) { + if (toupper(target[i + lentarget - lensuffix]) != toupper(suffix[i])) + return false; + } + return true; +} + +SString PropSet::GetWild(const char *keybase, const char *filename) { + for (int i = 0; i < used; i += 2) { + if (isprefix(vals[i], keybase)) { + char *orgkeyfile = vals[i] + strlen(keybase); + char *keyfile = NULL; + + if (strstr(orgkeyfile, "$(") == orgkeyfile) { + char *cpendvar = strchr(orgkeyfile, ')'); + if (cpendvar) { + int lenvar = cpendvar - orgkeyfile - 2; // Subtract the $() + char *var = static_cast(malloc(lenvar + 1)); + strncpy(var, orgkeyfile + 2, lenvar); + var[lenvar] = '\0'; + SString s = Get(var); + free(var); + keyfile = strdup(s.c_str()); + } + } + char *keyptr = keyfile; + + if (keyfile == NULL) + keyfile = orgkeyfile; + + for (; ; ) { + char *del = strchr(keyfile, ';'); + if (del == NULL) + del = keyfile + strlen(keyfile); + char delchr = *del; + *del = '\0'; + if (*keyfile == '*') { + if (issuffix(filename, keyfile + 1)) { + *del = delchr; + free(keyptr); + return vals[i + 1]; + } + } else if (EqualCaseInsensitive(keyfile, filename)) { + *del = delchr; + free(keyptr); + return vals[i + 1]; + } + if (delchr == '\0') + break; + *del = delchr; + keyfile = del + 1; + } + free(keyptr); + + if (EqualCaseInsensitive(vals[i], keybase)) { + return vals[i + 1]; + } + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->GetWild(keybase, filename); + } else { + return ""; + } +} + +SString PropSet::GetNewExpand(const char *keybase, const char *filename) { + char *base = StringDup(GetWild(keybase, filename).c_str()); + char *cpvar = strstr(base, "$("); + while (cpvar) { + char *cpendvar = strchr(cpvar, ')'); + if (cpendvar) { + int lenvar = cpendvar - cpvar - 2; // Subtract the $() + char *var = new char[lenvar + 1]; + strncpy(var, cpvar + 2, lenvar); + var[lenvar] = '\0'; + SString val = GetWild(var, filename); + int newlenbase = strlen(base) + val.length() - lenvar; + char *newbase = new char[newlenbase]; + strncpy(newbase, base, cpvar - base); + strcpy(newbase + (cpvar - base), val.c_str()); + strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1); + delete []var; + delete []base; + base = newbase; + } + cpvar = strstr(base, "$("); + } + SString sret = base; + delete []base; + return sret; +} + +void PropSet::Clear() { + for (int i = 0; i < used; i++) { + delete [](vals[i]); + vals[i] = 0; + } + used = 0; +} + +void PropSet::ReadFromMemory(const char *data, int len) { + if (len > 0) { + const char *pd = data; + char linebuf[60000]; + while (GetFullLine(pd, len, linebuf, sizeof(linebuf))) { + if (isalpha(linebuf[0])) + Set(linebuf); + } + } +} + +void PropSet::Read(const char *filename) { + //printf("Opening properties <%s>\n", filename); + Clear(); + char propsData[60000]; + FILE *rcfile = fopen(filename, "rb"); + if (rcfile) { + int lenFile = fread(propsData, 1, sizeof(propsData), rcfile); + fclose(rcfile); + ReadFromMemory(propsData, lenFile); + } else { + //printf("Could not open <%s>\n", filename); + } +} + +static bool iswordsep(char ch, bool onlyLineEnds) { + if (!isspace(ch)) + return false; + if (!onlyLineEnds) + return true; + return ch == '\r' || ch == '\n'; +} + +// Creates an array that points into each word in the string and puts \0 terminators +// after each word. +static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) { + char prev = '\n'; + int words = 0; + for (int j = 0; wordlist[j]; j++) { + if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds)) + words++; + prev = wordlist[j]; + } + char **keywords = new char * [words + 1]; + if (keywords) { + words = 0; + prev = '\0'; + int len = strlen(wordlist); + for (int k = 0; k < len; k++) { + if (!iswordsep(wordlist[k], onlyLineEnds)) { + if (!prev) { + keywords[words] = &wordlist[k]; + words++; + } + } else { + wordlist[k] = '\0'; + } + prev = wordlist[k]; + } + keywords[words] = &wordlist[len]; + } + return keywords; +} + +void WordList::Clear() { + if (words) { + delete []words; + delete []list; + } + words = 0; + list = 0; + len = 0; +} + +void WordList::Set(const char *s) { + len = 0; + list = StringDup(s); + words = ArrayFromWordList(list, onlyLineEnds); +} + +char *WordList::Allocate(int size) { + list = new char[size + 1]; + list[size] = '\0'; + return list; +} + +void WordList::SetFromAllocated() { + len = 0; + words = ArrayFromWordList(list, onlyLineEnds); +} + +// Shell sort based upon public domain C implementation by Raymond Gardner 1991 +// Used here because of problems with mingw qsort. +static void SortWordList(char **words, unsigned int len) { + unsigned int gap = len / 2; + + while (gap > 0) { + unsigned int i = gap; + while (i < len) { + unsigned int j = i; + char **a = words + j; + do { + j -= gap; + char **b = a; + a -= gap; + if (strcmp(*a, *b) > 0) { + char *tmp = *a; + *a = *b; + *b = tmp; + } else { + break; + } + } while (j >= gap); + i++; + } + gap = gap / 2; + } +} + +bool WordList::InList(const char *s) { + if (0 == words) + return false; + if (len == 0) { + for (int i = 0; words[i][0]; i++) + len++; + SortWordList(words, len); + for (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) { + 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++; + } + } + return false; +} diff --git a/src/stc/scintilla/src/SVector.h b/src/stc/scintilla/src/SVector.h new file mode 100644 index 0000000000..7bc948738a --- /dev/null +++ b/src/stc/scintilla/src/SVector.h @@ -0,0 +1,110 @@ +// Scintilla source code edit control +// SVector.h - a simple expandable vector +// Copyright 1998-1999 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SVECTOR_H +#define SVECTOR_H + +// A simple expandable vector. +// T must support assignment. +// 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. +template +class SVector { + T *v; + unsigned int size; // Number of elements allocated + unsigned int len; // Number of elements in vector + bool allocFailure; // A memory allocation call has failed + + // Internally allocate more elements than the user wants to avoid + // thrashng the memory allocator + void SizeTo(int newSize) { + if (newSize < sizeIncrement) + newSize += sizeIncrement; + else + newSize = (newSize * 3) / 2; + T* newv = new T[newSize]; + if (!newv) { + allocFailure = true; + return; + } + size = newSize; + for (int i=0; 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]; + } + void Free() { + delete []v; + v = 0; + size = 0; + len = 0; + } + void SetLength(int newLen) { + if (newLength > len) { + if (newLength >= size) { + SizeTo(newLength); + } + } + len = newLen; + } + int Length() const { + return len; + } +}; + +#endif diff --git a/src/stc/scintilla/src/ScintillaBase.cxx b/src/stc/scintilla/src/ScintillaBase.cxx new file mode 100644 index 0000000000..eb68904b79 --- /dev/null +++ b/src/stc/scintilla/src/ScintillaBase.cxx @@ -0,0 +1,399 @@ +// Scintilla source code edit control +// ScintillaBase.cxx - an enhanced subclass of Editor with calltips, autocomplete and context menu +// Copyright 1998-2000 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" +#ifdef SCI_LEXER +#include "SciLexer.h" +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#endif +#include "ContractionState.h" +#include "SVector.h" +#include "CellBuffer.h" +#include "CallTip.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "AutoComplete.h" +#include "Document.h" +#include "Editor.h" +#include "ScintillaBase.h" + +ScintillaBase::ScintillaBase() { +#ifdef SCI_LEXER + lexLanguage = SCLEX_CONTAINER; + for (int wl=0;wl= rcClient.right - widthLB) { + HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB); + Redraw(); + pt = LocationFromPosition(currentPos); + } + PRectangle rcac; + rcac.left = pt.x - 5; + if (pt.y >= rcClient.bottom - heightLB && // Wont fit below. + pt.y >= (rcClient.bottom + rcClient.top) / 2) { // and there is more room above. + rcac.top = pt.y - heightLB; + if (rcac.top < 0) { + heightLB += rcac.top; + rcac.top = 0; + } + } else { + rcac.top = pt.y + vs.lineHeight; + } + rcac.right = rcac.left + widthLB; + rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcClient.bottom); + ac.lb.SetPositionRelative(rcac, wMain); + ac.lb.SetFont(vs.styles[0].font); + + int maxStrLen = 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.GetPosition(); + int heightAlloced = rcList.bottom - rcList.top; + // Make an allowance for large strings in list + rcList.left = pt.x - 5; + rcList.right = rcList.left + Platform::Maximum(widthLB, maxStrLen * 8 + 16); + if (pt.y >= rcClient.bottom - heightLB && // Wont fit below. + pt.y >= (rcClient.bottom + rcClient.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); + //lbAutoComplete.SetPosition(rcList); + ac.Show(); +} + +void ScintillaBase::AutoCompleteCancel() { + ac.Cancel(); +} + +void ScintillaBase::AutoCompleteMove(int delta) { + ac.Move(delta); +} + +void ScintillaBase::AutoCompleteChanged(char ch) { + if (currentPos <= ac.posStart) { + ac.Cancel(); + } else if (ac.IsStopChar(ch)) { + ac.Cancel(); + } else { + char wordCurrent[1000]; + int i; + int startWord = ac.posStart - ac.startLen; + for (i = startWord; i < currentPos; i++) + wordCurrent[i - startWord] = pdoc->CharAt(i); + wordCurrent[i - startWord] = '\0'; + ac.Select(wordCurrent); + } +} + +void ScintillaBase::AutoCompleteCompleted() { + int item = ac.lb.GetSelection(); + char selected[200]; + if (item != -1) { + ac.lb.GetValue(item, selected, sizeof(selected)); + } + ac.Cancel(); + if (currentPos != ac.posStart) { + pdoc->DeleteChars(ac.posStart, currentPos - ac.posStart); + } + SetEmptySelection(ac.posStart); + if (item != -1) { + pdoc->InsertString(currentPos, selected + ac.startLen); + SetEmptySelection(currentPos + strlen(selected + ac.startLen)); + } +} + +void ScintillaBase::ContextMenu(Point pt) { + popup.CreatePopUp(); + AddToPopUp("Undo", idcmdUndo, pdoc->CanUndo()); + AddToPopUp("Redo", idcmdRedo, pdoc->CanRedo()); + AddToPopUp(""); + AddToPopUp("Cut", idcmdCut, currentPos != anchor); + AddToPopUp("Copy", idcmdCopy, currentPos != anchor); + AddToPopUp("Paste", idcmdPaste, WndProc(EM_CANPASTE, 0, 0)); + AddToPopUp("Delete", idcmdDelete, currentPos != anchor); + AddToPopUp(""); + AddToPopUp("Select All", idcmdSelectAll); + popup.Show(pt, wMain); +} + +void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { + AutoCompleteCancel(); + ct.CallTipCancel(); + Editor::ButtonDown(pt, curTime, shift, ctrl, alt); +} + +#ifdef SCI_LEXER +void ScintillaBase::Colourise(int start, int end) { + int lengthDoc = Platform::SendScintilla(wMain.GetID(), SCI_GETLENGTH, 0, 0); + if (end == -1) + end = lengthDoc; + int len = end - start; + + PropSet props; + + StylingContext styler(wMain.GetID(), props); + + int styleStart = 0; + if (start > 0) + styleStart = styler.StyleAt(start - 1); + + ColouriseDoc(pdoc->dbcsCodePage, start, len, styleStart, lexLanguage, keyWordLists, styler); + styler.Flush(); +} +#endif + +void ScintillaBase::NotifyStyleNeeded(int endStyleNeeded) { +#ifdef SCI_LEXER + if (lexLanguage != SCLEX_CONTAINER) { + int endStyled = Platform::SendScintilla(wMain.GetID(), SCI_GETENDSTYLED, 0, 0); + int lineEndStyled = Platform::SendScintilla(wMain.GetID(), EM_LINEFROMCHAR, endStyled, 0); + endStyled = Platform::SendScintilla(wMain.GetID(), EM_LINEINDEX, lineEndStyled, 0); + Colourise(endStyled, endStyleNeeded); + return; + } +#endif + Editor::NotifyStyleNeeded(endStyleNeeded); +} + +LRESULT ScintillaBase::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { + switch (iMessage) { + case SCI_AUTOCSHOW: + AutoCompleteStart(wParam, reinterpret_cast(lParam)); + break; + + case SCI_AUTOCCANCEL: + AutoCompleteCancel(); + break; + + case SCI_AUTOCACTIVE: + return ac.Active(); + + case SCI_AUTOCPOSSTART: + return ac.posStart; + + case SCI_AUTOCCOMPLETE: + AutoCompleteCompleted(); + break; + + case SCI_AUTOCSTOPS: + ac.SetStopChars(reinterpret_cast(lParam)); + break; + + case SCI_CALLTIPSHOW: { + AutoCompleteCancel(); + if (!ct.wCallTip.Created()) { + PRectangle rc = ct.CallTipStart(currentPos, LocationFromPosition(wParam), + reinterpret_cast(lParam), + vs.styles[0].fontName, vs.styles[0].size); + // 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, wDraw); + ct.wCallTip.Show(); + } + } + 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 = Colour(wParam); + InvalidateStyleRedraw(); + break; + +#ifdef SCI_LEXER + case SCI_SETLEXER: + lexLanguage = wParam; + break; + + case SCI_GETLEXER: + return lexLanguage; + + case SCI_COLOURISE: + Colourise(wParam, lParam); + break; + + case SCI_SETPROPERTY: + props.Set(reinterpret_cast(wParam), + reinterpret_cast(lParam)); + break; + + case SCI_SETKEYWORDS: + if ((wParam >= 0) && (wParam < numWordLists)) { + keyWordLists[wParam]->Clear(); + keyWordLists[wParam]->Set(reinterpret_cast(lParam)); + } + break; +#endif + + default: + return Editor::WndProc(iMessage, wParam, lParam); + } + return 0l; +} diff --git a/src/stc/scintilla/src/ScintillaBase.h b/src/stc/scintilla/src/ScintillaBase.h new file mode 100644 index 0000000000..e9f8f28d03 --- /dev/null +++ b/src/stc/scintilla/src/ScintillaBase.h @@ -0,0 +1,68 @@ +// Scintilla source code edit control +// ScintillaBase.h - defines an enhanced subclass of Editor with calltips, autocomplete and context menu +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SCINTILLABASE_H +#define SCINTILLABASE_H + +class ScintillaBase : public Editor { +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 + }; + + Menu popup; + AutoComplete ac; + + CallTip ct; + +#ifdef SCI_LEXER + int lexLanguage; + PropSet props; + enum {numWordLists=5}; + WordList *keyWordLists[numWordLists]; + 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 AddChar(char ch); + void Command(int cmdId); + virtual int KeyCommand(UINT iMessage); + + void AutoCompleteStart(int lenEntered, const char *list); + void AutoCompleteCancel(); + void AutoCompleteMove(int delta); + void AutoCompleteChanged(char ch=0); + void AutoCompleteCompleted(); + + 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 NotifyStyleNeeded(int endStyleNeeded); +public: + // Public so scintilla_send_message can use it + virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam); +}; + +#endif diff --git a/src/stc/scintilla/src/Style.cxx b/src/stc/scintilla/src/Style.cxx new file mode 100644 index 0000000000..56312314ff --- /dev/null +++ b/src/stc/scintilla/src/Style.cxx @@ -0,0 +1,63 @@ +// Scintilla source code edit control +// Style.cxx - defines the font and colour style for a class of text +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#include + +#include "Platform.h" + +#include "Style.h" + +Style::Style() { + Clear(); +} + +Style::~Style() { + font.Release(); +} + +Style &Style::operator=(const Style &source) { + if (this == &source) + return *this; + Clear(); + fore.desired = source.fore.desired; + back.desired = source.back.desired; + bold = source.bold; + italic = source.italic; + size = source.size; + strcpy(fontName, source.fontName); + eolFilled = source.eolFilled; + return *this; +} + +void Style::Clear(Colour fore_, Colour back_, int size_, const char *fontName_, + bool bold_, bool italic_, bool eolFilled_) { + fore.desired = fore_; + back.desired = back_; + bold = bold_; + italic = italic_; + size = size_; + strcpy(fontName, fontName_); + eolFilled = eolFilled_; + font.Release(); +} + +void Style::Realise(Surface &surface, int zoomLevel) { + int sizeZoomed = size + zoomLevel; + if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2; + + int deviceHeight = (sizeZoomed * surface.LogPixelsY()) / 72; + font.Create(fontName, deviceHeight, bold, italic); + + 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/src/stc/scintilla/src/Style.h b/src/stc/scintilla/src/Style.h new file mode 100644 index 0000000000..916b646315 --- /dev/null +++ b/src/stc/scintilla/src/Style.h @@ -0,0 +1,37 @@ +// Scintilla source code edit control +// Style.h - defines the font and colour style for a class of text +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef STYLE_H +#define STYLE_H + +class Style { +public: + ColourPair fore; + ColourPair back; + bool bold; + bool italic; + int size; + char fontName[100]; + bool eolFilled; + + Font font; + unsigned int lineHeight; + unsigned int ascent; + unsigned int descent; + unsigned int externalLeading; + unsigned int aveCharWidth; + unsigned int spaceWidth; + + Style(); + ~Style(); + Style &operator=(const Style &source); + void Clear(Colour fore_=Colour(0,0,0), Colour back_=Colour(0xff,0xff,0xff), + int size_=Platform::DefaultFontSize(), + const char *fontName_=Platform::DefaultFont(), + bool bold_=false, bool italic_=false, bool eolFilled_=false); + void Realise(Surface &surface, int zoomLevel); +}; + +#endif diff --git a/src/stc/scintilla/src/ViewStyle.cxx b/src/stc/scintilla/src/ViewStyle.cxx new file mode 100644 index 0000000000..001ecdb319 --- /dev/null +++ b/src/stc/scintilla/src/ViewStyle.cxx @@ -0,0 +1,183 @@ +// Scintilla source code edit control +// ViewStyle.cxx - store information on how the document is to be viewed +// Copyright 1998-2000 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 "Indicator.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" + +MarginStyle::MarginStyle() : + symbol(false), width(16), mask(0xffffffff), sensitive(false) { +} + +ViewStyle::ViewStyle() { + Init(); +} + +ViewStyle::ViewStyle(const ViewStyle &source) { + Init(); + for (int sty=0;sty<=STYLE_MAX;sty++) { + styles[sty] = source.styles[sty]; + } + for (int mrk=0;mrk<=MARKER_MAX;mrk++) { + markers[mrk] = source.markers[mrk]; + } + for (int ind=0;ind<=INDIC_MAX;ind++) { + indicators[ind] = source.indicators[ind]; + } + + selforeset = source.selforeset; + selforeground.desired = source.selforeground.desired; + selbackset = source.selbackset; + selbackground.desired = source.selbackground.desired; + selbar.desired = source.selbar.desired; + selbarlight.desired = source.selbarlight.desired; + caretcolour.desired = source.caretcolour.desired; + edgecolour.desired = source.edgecolour.desired; + leftMarginWidth = source.leftMarginWidth; + rightMarginWidth = source.rightMarginWidth; + for (int i=0;i < margins; i++) { + ms[i] = source.ms[i]; + } + symbolMargin = source.symbolMargin; + maskInLine = source.maskInLine; + fixedColumnWidth = source.fixedColumnWidth; + zoomLevel = source.zoomLevel; + viewWhitespace = source.viewWhitespace; + viewEOL = source.viewEOL; + showMarkedLines = source.showMarkedLines; +} + +ViewStyle::~ViewStyle() { +} + +void ViewStyle::Init() { + indicators[0].style = INDIC_SQUIGGLE; + indicators[0].fore = Colour(0, 0x7f, 0); + indicators[1].style = INDIC_TT; + indicators[1].fore = Colour(0, 0, 0xff); + indicators[2].style = INDIC_PLAIN; + indicators[2].fore = Colour(0xff, 0, 0); + + lineHeight = 1; + maxAscent = 1; + maxDescent = 1; + aveCharWidth = 8; + spaceWidth = 8; + + selforeset = false; + selforeground.desired = Colour(0xff, 0, 0); + selbackset = true; + selbackground.desired = Colour(0xc0, 0xc0, 0xc0); + selbar.desired = Platform::Chrome(); + selbarlight.desired = Platform::ChromeHighlight(); + styles[STYLE_LINENUMBER].fore.desired = Colour(0, 0, 0); + styles[STYLE_LINENUMBER].back.desired = Platform::Chrome(); + //caretcolour.desired = Colour(0xff, 0, 0); + caretcolour.desired = Colour(0, 0, 0); + edgecolour.desired = Colour(0xc0, 0xc0, 0xc0); + + leftMarginWidth = 1; + rightMarginWidth = 1; + ms[0].symbol = false; + ms[0].width = 0; + ms[0].mask = 0; + ms[1].symbol = true; + ms[1].width = 16; + ms[1].mask = ~SC_MASK_FOLDERS; + ms[2].symbol = true; + ms[2].width = 14; // Nice width for arrows + ms[2].mask = SC_MASK_FOLDERS; + ms[2].width = 0; // Nice width for arrows + ms[2].mask = 0; + fixedColumnWidth = leftMarginWidth; + symbolMargin = false; + maskInLine = 0xffffffff; + for (int margin=0; margin < margins; margin++) { + fixedColumnWidth += ms[margin].width; + symbolMargin = symbolMargin || ms[margin].symbol; + if (ms[margin].width > 0) + maskInLine &= ~ms[margin].mask; + } + zoomLevel = 0; + viewWhitespace = false; + viewEOL = false; + showMarkedLines = true; +} + +void ViewStyle::RefreshColourPalette(Palette &pal, bool want) { + unsigned int i; + for (i=0;i<(sizeof(styles)/sizeof(styles[0]));i++) { + pal.WantFind(styles[i].fore, want); + pal.WantFind(styles[i].back, want); + } + for (i=0;i<(sizeof(indicators)/sizeof(indicators[0]));i++) { + pal.WantFind(indicators[i].fore, want); + } + for (i=0;i<(sizeof(markers)/sizeof(markers[0]));i++) { + pal.WantFind(markers[i].fore, want); + pal.WantFind(markers[i].back, want); + } + pal.WantFind(selforeground, want); + pal.WantFind(selbackground, want); + pal.WantFind(selbar, want); + pal.WantFind(selbarlight, want); + pal.WantFind(caretcolour, want); + pal.WantFind(edgecolour, want); +} + +void ViewStyle::Refresh(Surface &surface) { + selbar.desired = Platform::Chrome(); + selbarlight.desired = Platform::ChromeHighlight(); + maxAscent = 1; + maxDescent = 1; + for (unsigned int i=0;i<(sizeof(styles)/sizeof(styles[0]));i++) { + styles[i].Realise(surface, zoomLevel); + if (maxAscent < styles[i].ascent) + maxAscent = styles[i].ascent; + if (maxDescent < styles[i].descent) + maxDescent = styles[i].descent; + } + + lineHeight = maxAscent + maxDescent; + aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth; + spaceWidth = styles[STYLE_DEFAULT].spaceWidth; + + fixedColumnWidth = leftMarginWidth; + symbolMargin = false; + maskInLine = 0xffffffff; + for (int margin=0; margin < margins; margin++) { + fixedColumnWidth += ms[margin].width; + symbolMargin = symbolMargin || ms[margin].symbol; + if (ms[margin].width > 0) + maskInLine &= ~ms[margin].mask; + } +} + +void ViewStyle::ResetDefaultStyle() { + styles[STYLE_DEFAULT].Clear(); +} + +void ViewStyle::ClearStyles() { + // Reset all styles to be like the default style + for (int i=0; i<=STYLE_MAX; i++) { + if (i != STYLE_DEFAULT) { + styles[i].Clear( + styles[STYLE_DEFAULT].fore.desired, + styles[STYLE_DEFAULT].back.desired, + styles[STYLE_DEFAULT].size, + styles[STYLE_DEFAULT].fontName, + styles[STYLE_DEFAULT].bold, + styles[STYLE_DEFAULT].italic); + } + } + styles[STYLE_LINENUMBER].back.desired = Platform::Chrome(); +} + diff --git a/src/stc/scintilla/src/ViewStyle.h b/src/stc/scintilla/src/ViewStyle.h new file mode 100644 index 0000000000..944872095a --- /dev/null +++ b/src/stc/scintilla/src/ViewStyle.h @@ -0,0 +1,59 @@ +// Scintilla source code edit control +// ViewStyle.h - store information on how the document is to be viewed +// Copyright 1998-2000 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef VIEWSTYLE_H +#define VIEWSTYLE_H + +class MarginStyle { +public: + bool symbol; + int width; + int mask; + bool sensitive; + MarginStyle(); +}; + +class ViewStyle { +public: + Style styles[STYLE_MAX + 1]; + 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 selbar; + ColourPair selbarlight; + // Margins are ordered: Line Numbers, Selection Margin, Spacing Margin + int leftMarginWidth; // Spacing margin on left of text + int rightMarginWidth; // Spacing margin on left of text + enum { margins=3 }; + 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; + bool viewWhitespace; + bool viewEOL; + bool showMarkedLines; + ColourPair caretcolour; + ColourPair edgecolour; + + ViewStyle(); + ViewStyle(const ViewStyle &source); + ~ViewStyle(); + void Init(); + void RefreshColourPalette(Palette &pal, bool want); + void Refresh(Surface &surface); + void ResetDefaultStyle(); + void ClearStyles(); +}; + +#endif diff --git a/src/stc/stc.cpp b/src/stc/stc.cpp new file mode 100644 index 0000000000..d4b02e8e6d --- /dev/null +++ b/src/stc/stc.cpp @@ -0,0 +1,1386 @@ +//////////////////////////////////////////////////////////////////////////// +// Name: stc.cpp +// Purpose: A wxWindows implementation of Scintilla. This class is the +// one meant to be used directly by wx applications. It does not +// derive directly from the Scintilla classes, but instead +// delegates most things to the real Scintilla class. +// This allows the use of Scintilla without polluting the +// namespace with all the classes and itentifiers from Scintilla. +// +// Author: Robin Dunn +// +// Created: 13-Jan-2000 +// RCS-ID: $Id$ +// Copyright: (c) 2000 by Total Control Software +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#include "wx/stc/stc.h" +#include "ScintillaWX.h" + +#include + +//---------------------------------------------------------------------- + +const wxChar* wxSTCNameStr = "stcwindow"; + +BEGIN_EVENT_TABLE(wxStyledTextCtrl, wxControl) + EVT_PAINT (wxStyledTextCtrl::OnPaint) + EVT_SCROLLWIN (wxStyledTextCtrl::OnScrollWin) + EVT_SIZE (wxStyledTextCtrl::OnSize) + EVT_LEFT_DOWN (wxStyledTextCtrl::OnMouseLeftDown) + EVT_MOTION (wxStyledTextCtrl::OnMouseMove) + EVT_LEFT_UP (wxStyledTextCtrl::OnMouseLeftUp) + EVT_RIGHT_UP (wxStyledTextCtrl::OnMouseRightUp) + EVT_CHAR (wxStyledTextCtrl::OnChar) + EVT_KILL_FOCUS (wxStyledTextCtrl::OnLoseFocus) + EVT_SET_FOCUS (wxStyledTextCtrl::OnGainFocus) + EVT_SYS_COLOUR_CHANGED (wxStyledTextCtrl::OnSysColourChanged) + EVT_ERASE_BACKGROUND (wxStyledTextCtrl::OnEraseBackground) + EVT_MENU_RANGE (-1, -1, wxStyledTextCtrl::OnMenu) +END_EVENT_TABLE() + +//---------------------------------------------------------------------- +// Constructor and Destructor + +wxStyledTextCtrl::wxStyledTextCtrl(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) : + wxControl(parent, id, pos, size, + style | wxVSCROLL | wxHSCROLL | wxWANTS_CHARS, + wxDefaultValidator, name) +{ + m_swx = new ScintillaWX(this); + // m_keywords = new WordList; + m_stopWatch.Start(); + m_readOnly = false; + m_undoType = wxSTC_UndoCollectAutoStart; +} + + +wxStyledTextCtrl::~wxStyledTextCtrl() { + delete m_swx; + // delete m_keywords; +} + + +//---------------------------------------------------------------------- + +inline long wxStyledTextCtrl::SendMsg(int msg, long wp, long lp) { + + return m_swx->WndProc(msg, wp, lp); +} + + +//---------------------------------------------------------------------- +// Text retrieval and modification + +wxString wxStyledTextCtrl::GetText() { + wxString text; + int len = GetTextLength(); + char* buff = text.GetWriteBuf(len); + + SendMsg(WM_GETTEXT, len, (long)buff); + text.UngetWriteBuf(); + return text; +} + + +bool wxStyledTextCtrl::SetText(const wxString& text) { + return SendMsg(WM_SETTEXT, 0, (long)text.c_str()) != 0; +} + + +wxString wxStyledTextCtrl::GetLine(int line) { + wxString text; + int len = GetLineLength(line); + char* buff = text.GetWriteBuf(len+1); + + *((WORD*)buff) = len+1; + SendMsg(EM_GETLINE, line, (long)buff); + text.UngetWriteBuf(); + return text; +} + + +void wxStyledTextCtrl::ReplaceSelection(const wxString& text) { + SendMsg(EM_REPLACESEL, 0, (long)text.c_str()); +} + + +void wxStyledTextCtrl::SetReadOnly(bool readOnly) { + SendMsg(EM_SETREADONLY, (long)readOnly); + m_readOnly = readOnly; +} + + +bool wxStyledTextCtrl::GetReadOnly() { + // TODO: need support in Scintilla to do this right, + // until then we'll track it ourselves + return m_readOnly; +} + + +void wxStyledTextCtrl::GetTextRange(int startPos, int endPos, char* buff) { + TEXTRANGE tr; + tr.lpstrText = buff; + tr.chrg.cpMin = startPos; + tr.chrg.cpMax = endPos; + SendMsg(EM_GETTEXTRANGE, 0, (long)&tr); +} + + +wxString wxStyledTextCtrl::GetTextRange(int startPos, int endPos) { + wxString text; + int len = endPos - startPos; + char* buff = text.GetWriteBuf(len); + GetTextRange(startPos, endPos, buff); + text.UngetWriteBuf(); + return text; +} + + +void wxStyledTextCtrl::GetStyledTextRange(int startPos, int endPos, char* buff) { + TEXTRANGE tr; + tr.lpstrText = buff; + tr.chrg.cpMin = startPos; + tr.chrg.cpMax = endPos; + SendMsg(SCI_GETSTYLEDTEXT, 0, (long)&tr); +} + + +wxString wxStyledTextCtrl::GetStyledTextRange(int startPos, int endPos) { + wxString text; + int len = endPos - startPos; + char* buff = text.GetWriteBuf(len*2); + GetStyledTextRange(startPos, endPos, buff); + text.UngetWriteBuf(len*2); + return text; +} + + +void wxStyledTextCtrl::AddText(const wxString& text) { + SendMsg(SCI_ADDTEXT, text.Len(), (long)text.c_str()); +} + + +void wxStyledTextCtrl::AddStyledText(const wxString& text) { + SendMsg(SCI_ADDSTYLEDTEXT, text.Len(), (long)text.c_str()); +} + + +void wxStyledTextCtrl::InsertText(int pos, const wxString& text) { + SendMsg(SCI_INSERTTEXT, pos, (long)text.c_str()); +} + + +void wxStyledTextCtrl::ClearAll() { + SendMsg(SCI_CLEARALL); +} + + +char wxStyledTextCtrl::GetCharAt(int pos) { + return SendMsg(SCI_GETCHARAT, pos); +} + + +char wxStyledTextCtrl::GetStyleAt(int pos) { + return SendMsg(SCI_GETSTYLEAT, pos); +} + + +void wxStyledTextCtrl::SetStyleBits(int bits) { + SendMsg(SCI_SETSTYLEBITS, bits); +} + + +int wxStyledTextCtrl::GetStyleBits() { + return SendMsg(SCI_GETSTYLEBITS); +} + + +//---------------------------------------------------------------------- +// Clipboard + + +void wxStyledTextCtrl::Cut() { + SendMsg(WM_CUT); +} + + +void wxStyledTextCtrl::Copy() { + SendMsg(WM_COPY); +} + + +void wxStyledTextCtrl::Paste() { + SendMsg(WM_PASTE); +} + + +bool wxStyledTextCtrl::CanPaste() { + return SendMsg(EM_CANPASTE) != 0; +} + + +void wxStyledTextCtrl::ClearClipbrd() { + SendMsg(WM_CLEAR); +} + + + +//---------------------------------------------------------------------- +// Undo and Redo + +void wxStyledTextCtrl::Undo() { + SendMsg(WM_UNDO); +} + + +bool wxStyledTextCtrl::CanUndo() { + return SendMsg(EM_CANUNDO) != 0; +} + + +void wxStyledTextCtrl::EmptyUndoBuffer() { + SendMsg(EM_EMPTYUNDOBUFFER); +} + + +void wxStyledTextCtrl::Redo() { + SendMsg(SCI_REDO); +} + + +bool wxStyledTextCtrl::CanRedo() { + return SendMsg(SCI_CANREDO) != 0; +} + + +void wxStyledTextCtrl::SetUndoCollection(wxSTC_UndoType type) { + SendMsg(SCI_SETUNDOCOLLECTION, type); + m_undoType = type; +} + + +wxSTC_UndoType wxStyledTextCtrl::GetUndoCollection() { + // TODO: need support in Scintilla to do this right, + // until then we'll track it ourselves + return m_undoType; +} + + +void wxStyledTextCtrl::BeginUndoAction() { + SendMsg(SCI_BEGINUNDOACTION); +} + + +void wxStyledTextCtrl::EndUndoAction() { + SendMsg(SCI_ENDUNDOACTION); +} + + + + +//---------------------------------------------------------------------- +// Selection and information + + +void wxStyledTextCtrl::GetSelection(int* startPos, int* endPos) { + SendMsg(EM_GETSEL, (long)startPos, (long)endPos); +} + + +void wxStyledTextCtrl::SetSelection(int startPos, int endPos) { + SendMsg(EM_SETSEL, startPos, endPos); +} + + +wxString wxStyledTextCtrl::GetSelectedText() { + wxString text; + int start; + int end; + + GetSelection(&start, &end); + int len = end - start; + char* buff = text.GetWriteBuf(len); + + SendMsg(EM_GETSELTEXT, 0, (long)buff); + text.UngetWriteBuf(); + return text; +} + + +void wxStyledTextCtrl::HideSelection(bool hide) { + SendMsg(EM_HIDESELECTION, hide); +} + + +bool wxStyledTextCtrl::GetHideSelection() { + return m_swx->GetHideSelection(); +} + + +int wxStyledTextCtrl::GetTextLength() { + return SendMsg(WM_GETTEXTLENGTH); +} + + +int wxStyledTextCtrl::GetFirstVisibleLine() { + return SendMsg(EM_GETFIRSTVISIBLELINE); +} + + +int wxStyledTextCtrl::GetLineCount() { + return SendMsg(EM_GETLINECOUNT); +} + + +bool wxStyledTextCtrl::GetModified() { + return SendMsg(EM_GETMODIFY) != 0; +} + + +wxRect wxStyledTextCtrl::GetRect() { + PRectangle pr; + SendMsg(EM_GETRECT, 0, (long)&pr); + + wxRect rect = wxRectFromPRectangle(pr); + return rect; +} + + +int wxStyledTextCtrl::GetLineFromPos(int pos) { + return SendMsg(EM_LINEFROMCHAR, pos); +} + + +int wxStyledTextCtrl::GetLineStartPos(int line) { + return SendMsg(EM_LINEINDEX, line); +} + + +int wxStyledTextCtrl::GetLineLengthAtPos(int pos) { + return SendMsg(EM_LINELENGTH, pos); +} + + +int wxStyledTextCtrl::GetLineLength(int line) { + return SendMsg(SCI_LINELENGTH, line); +} + + +int wxStyledTextCtrl::GetCurrentLine() { + int line = GetLineFromPos(GetCurrentPos()); + return line; +} + + +wxString wxStyledTextCtrl::GetCurrentLineText(int* linePos) { + wxString text; + int len = GetLineLength(GetCurrentLine()); + char* buff = text.GetWriteBuf(len+1); + + int pos = SendMsg(SCI_GETCURLINE, len+1, (long)buff); + text.UngetWriteBuf(); + + if (linePos) + *linePos = pos; + + return text; +} + + +int wxStyledTextCtrl::PositionFromPoint(wxPoint pt) { + Point spt(pt.x, pt.y); + long rv = SendMsg(EM_CHARFROMPOS, 0, (long)&spt); + return LOWORD(rv); +} + + +int wxStyledTextCtrl::LineFromPoint(wxPoint pt) { + Point spt(pt.x, pt.y); + long rv = SendMsg(EM_CHARFROMPOS, 0, (long)&spt); + return HIWORD(rv); +} + + +wxPoint wxStyledTextCtrl::PointFromPosition(int pos) { + Point pt; + SendMsg(EM_POSFROMCHAR, pos, (long)&pt); + return wxPoint(pt.x, pt.y); +} + + +int wxStyledTextCtrl::GetCurrentPos() { + return SendMsg(SCI_GETCURRENTPOS); +} + + +int wxStyledTextCtrl::GetAnchor() { + return SendMsg(SCI_GETANCHOR); +} + + +void wxStyledTextCtrl::SelectAll() { + SendMsg(SCI_SELECTALL); +} + + +void wxStyledTextCtrl::SetCurrentPosition(int pos) { + SendMsg(SCI_GOTOPOS, pos); +} + + +void wxStyledTextCtrl::SetAnchor(int pos) { + SendMsg(SCI_SETANCHOR, pos); +} + + +void wxStyledTextCtrl::GotoPos(int pos) { + SendMsg(SCI_GOTOPOS, pos); +} + + +void wxStyledTextCtrl::GotoLine(int line) { + SendMsg(SCI_GOTOLINE, line); +} + + +void wxStyledTextCtrl::ChangePosition(int delta, bool extendSelection) { + // TODO: Is documented but doesn't seem to be implemented + //SendMsg(SCI_CHANGEPOSITION, delta, extendSelection); +} + + +void wxStyledTextCtrl::PageMove(int cmdKey, bool extendSelection) { + // TODO: Is documented but doesn't seem to be implemented + //SendMsg(SCI_PAGEMOVE, cmdKey, extendSelection); +} + + +void wxStyledTextCtrl::ScrollBy(int columnDelta, int lineDelta) { + SendMsg(EM_LINESCROLL, columnDelta, lineDelta); +} + +void wxStyledTextCtrl::ScrollToLine(int line) { + m_swx->DoScrollToLine(line); +} + + +void wxStyledTextCtrl::ScrollToColumn(int column) { + m_swx->DoScrollToColumn(column); +} + + +void wxStyledTextCtrl::EnsureCaretVisible() { + SendMsg(EM_SCROLLCARET); +} + + +void wxStyledTextCtrl::SetCaretPolicy(int policy, int slop) { + SendMsg(SCI_SETCARETPOLICY, policy, slop); +} + + +int wxStyledTextCtrl::GetSelectionType() { + return SendMsg(EM_SELECTIONTYPE); +} + + + + +//---------------------------------------------------------------------- +// Searching + +int wxStyledTextCtrl::FindText(int minPos, int maxPos, + const wxString& text, + bool caseSensitive, bool wholeWord) { + FINDTEXTEX ft; + int flags = 0; + + flags |= caseSensitive ? FR_MATCHCASE : 0; + flags |= wholeWord ? FR_WHOLEWORD : 0; + ft.chrg.cpMin = minPos; + ft.chrg.cpMax = maxPos; + ft.lpstrText = (char*)text.c_str(); + + return SendMsg(EM_FINDTEXT, flags, (long)&ft); +} + + +void wxStyledTextCtrl::SearchAnchor() { + SendMsg(SCI_SEARCHANCHOR); +} + + +int wxStyledTextCtrl::SearchNext(const wxString& text, bool caseSensitive, bool wholeWord) { + int flags = 0; + flags |= caseSensitive ? FR_MATCHCASE : 0; + flags |= wholeWord ? FR_WHOLEWORD : 0; + + return SendMsg(SCI_SEARCHNEXT, flags, (long)text.c_str()); +} + + +int wxStyledTextCtrl::SearchPrev(const wxString& text, bool caseSensitive, bool wholeWord) { + int flags = 0; + flags |= caseSensitive ? FR_MATCHCASE : 0; + flags |= wholeWord ? FR_WHOLEWORD : 0; + + return SendMsg(SCI_SEARCHPREV, flags, (long)text.c_str()); +} + +//---------------------------------------------------------------------- +// Visible whitespace + + +bool wxStyledTextCtrl::GetViewWhitespace() { + return SendMsg(SCI_GETVIEWWS) != 0; +} + + +void wxStyledTextCtrl::SetViewWhitespace(bool visible) { + SendMsg(SCI_SETVIEWWS, visible); +} + + + +//---------------------------------------------------------------------- +// Line endings + +wxSTC_EOL wxStyledTextCtrl::GetEOLMode() { + return (wxSTC_EOL)SendMsg(SCI_GETEOLMODE); +} + + +void wxStyledTextCtrl::SetEOLMode(wxSTC_EOL mode) { + SendMsg(SCI_SETEOLMODE, mode); +} + + +bool wxStyledTextCtrl::GetViewEOL() { + return SendMsg(SCI_GETVIEWEOL) != 0; +} + + +void wxStyledTextCtrl::SetViewEOL(bool visible) { + SendMsg(SCI_SETVIEWEOL, visible); +} + +void wxStyledTextCtrl::ConvertEOL(wxSTC_EOL mode) { + SendMsg(SCI_CONVERTEOLS, mode); +} + +//---------------------------------------------------------------------- +// Styling + +int wxStyledTextCtrl::GetEndStyled() { + return SendMsg(SCI_GETENDSTYLED); +} + + +void wxStyledTextCtrl::StartStyling(int pos, int mask) { + SendMsg(SCI_STARTSTYLING, pos, mask); +} + + +void wxStyledTextCtrl::SetStyleFor(int length, int style) { + SendMsg(SCI_SETSTYLING, length, style); +} + + +void wxStyledTextCtrl::SetStyleBytes(int length, char* styleBytes) { + SendMsg(SCI_SETSTYLINGEX, length, (long)styleBytes); +} + + +//---------------------------------------------------------------------- +// Style Definition + + +static long wxColourAsLong(const wxColour& co) { + return (((long)co.Blue() << 16) | + ((long)co.Green() << 8) | + ((long)co.Red())); +} + +static wxColour wxColourFromLong(long c) { + wxColour clr; + clr.Set(c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff); + return clr; +} + + +static wxColour wxColourFromSpec(const wxString& spec) { + // spec should be #RRGGBB + char* junk; + int red = strtol(spec.Mid(1,2), &junk, 16); + int green = strtol(spec.Mid(3,2), &junk, 16); + int blue = strtol(spec.Mid(5,2), &junk, 16); + return wxColour(red, green, blue); +} + + +void wxStyledTextCtrl::StyleClearAll() { + SendMsg(SCI_STYLECLEARALL); +} + + +void wxStyledTextCtrl::StyleResetDefault() { + SendMsg(SCI_STYLERESETDEFAULT); +} + + + +// Extract style settings from a spec-string which is composed of one or +// more of the following comma separated elements: +// +// bold turns on bold +// italic turns on italics +// fore:#RRGGBB sets the foreground colour +// back:#RRGGBB sets the background colour +// face:[facename] sets the font face name to use +// size:[num] sets the font size in points +// eol turns on eol filling +// + +void wxStyledTextCtrl::StyleSetSpec(int styleNum, const wxString& spec) { + + wxStringTokenizer tkz(spec, ","); + while (tkz.HasMoreTokens()) { + wxString token = tkz.GetNextToken(); + + wxString option = token.BeforeFirst(':'); + wxString val = token.AfterFirst(':'); + + if (option == "bold") + StyleSetBold(styleNum, true); + + else if (option == "italic") + StyleSetItalic(styleNum, true); + + else if (option == "eol") + StyleSetEOLFilled(styleNum, true); + + else if (option == "size") { + long points; + if (val.ToLong(&points)) + StyleSetSize(styleNum, points); + } + + else if (option == "face") + StyleSetFaceName(styleNum, val); + + else if (option == "fore") + StyleSetForeground(styleNum, wxColourFromSpec(val)); + + else if (option == "back") + StyleSetBackground(styleNum, wxColourFromSpec(val)); + } +} + + +void wxStyledTextCtrl::StyleSetForeground(int styleNum, const wxColour& colour) { + SendMsg(SCI_STYLESETFORE, styleNum, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::StyleSetBackground(int styleNum, const wxColour& colour) { + SendMsg(SCI_STYLESETBACK, styleNum, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::StyleSetFont(int styleNum, wxFont& font) { + int size = font.GetPointSize(); + wxString faceName = font.GetFaceName(); + bool bold = font.GetWeight() == wxBOLD; + bool italic = font.GetStyle() != wxNORMAL; + + StyleSetFontAttr(styleNum, size, faceName, bold, italic); +} + + +void wxStyledTextCtrl::StyleSetFontAttr(int styleNum, int size, + const wxString& faceName, + bool bold, bool italic) { + StyleSetSize(styleNum, size); + StyleSetFaceName(styleNum, faceName); + StyleSetBold(styleNum, bold); + StyleSetItalic(styleNum, italic); +} + + +void wxStyledTextCtrl::StyleSetBold(int styleNum, bool bold) { + SendMsg(SCI_STYLESETBOLD, styleNum, bold); +} + + +void wxStyledTextCtrl::StyleSetItalic(int styleNum, bool italic) { + SendMsg(SCI_STYLESETITALIC, styleNum, italic); +} + + +void wxStyledTextCtrl::StyleSetFaceName(int styleNum, const wxString& faceName) { + SendMsg(SCI_STYLESETFONT, styleNum, (long)faceName.c_str()); +} + + +void wxStyledTextCtrl::StyleSetSize(int styleNum, int pointSize) { + SendMsg(SCI_STYLESETSIZE, styleNum, pointSize); +} + + +void wxStyledTextCtrl::StyleSetEOLFilled(int styleNum, bool fillEOL) { + SendMsg(SCI_STYLESETEOLFILLED, styleNum, fillEOL); +} + + +//---------------------------------------------------------------------- +// Margins in the edit area + +int wxStyledTextCtrl::GetLeftMargin() { + return LOWORD(SendMsg(EM_GETMARGINS)); +} + + +int wxStyledTextCtrl::GetRightMargin() { + return HIWORD(SendMsg(EM_GETMARGINS)); +} + + +void wxStyledTextCtrl::SetMargins(int left, int right) { + int flag = 0; + int val = 0; + + if (right != -1) { + flag |= EC_RIGHTMARGIN; + val = right << 16; + } + if (left != -1) { + flag |= EC_LEFTMARGIN; + val |= (left & 0xffff); + } + + SendMsg(EM_SETMARGINS, flag, val); +} + + +//---------------------------------------------------------------------- +// Margins for selection, markers, etc. + +void wxStyledTextCtrl::SetMarginType(int margin, int type) { + SendMsg(SCI_SETMARGINTYPEN, margin, type); +} + + +int wxStyledTextCtrl::GetMarginType(int margin) { + return SendMsg(SCI_GETMARGINTYPEN, margin); +} + + +void wxStyledTextCtrl::SetMarginWidth(int margin, int pixelWidth) { + SendMsg(SCI_SETMARGINWIDTHN, margin, pixelWidth); +} + + +int wxStyledTextCtrl::GetMarginWidth(int margin) { + return SendMsg(SCI_GETMARGINWIDTHN, margin); +} + + +void wxStyledTextCtrl::SetMarginMask(int margin, int mask) { + SendMsg(SCI_SETMARGINMASKN, margin, mask); +} + + +int wxStyledTextCtrl::GetMarginMask(int margin) { + return SendMsg(SCI_GETMARGINMASKN, margin); +} + + +void wxStyledTextCtrl::SetMarginSensitive(int margin, bool sensitive) { + SendMsg(SCI_SETMARGINSENSITIVEN, margin, sensitive); +} + + +bool wxStyledTextCtrl::GetMarginSensitive(int margin) { + return SendMsg(SCI_GETMARGINSENSITIVEN, margin); +} + + + + +//---------------------------------------------------------------------- +// Selection and Caret styles + + +void wxStyledTextCtrl::SetSelectionForeground(const wxColour& colour) { + SendMsg(SCI_SETSELFORE, 0, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::SetSelectionBackground(const wxColour& colour) { + SendMsg(SCI_SETSELBACK, 0, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::SetCaretForeground(const wxColour& colour) { + SendMsg(SCI_SETCARETFORE, 0, wxColourAsLong(colour)); +} + + +int wxStyledTextCtrl::GetCaretPeriod() { + return SendMsg(SCI_GETCARETPERIOD); +} + + +void wxStyledTextCtrl::SetCaretPeriod(int milliseconds) { + SendMsg(SCI_SETCARETPERIOD, milliseconds); +} + + + +//---------------------------------------------------------------------- +// Other settings + + +void wxStyledTextCtrl::SetBufferedDraw(bool isBuffered) { + SendMsg(SCI_SETBUFFEREDDRAW, isBuffered); +} + + +void wxStyledTextCtrl::SetTabWidth(int numChars) { + SendMsg(SCI_SETTABWIDTH, numChars); +} + + +void wxStyledTextCtrl::SetWordChars(const wxString& wordChars) { + SendMsg(SCI_SETTABWIDTH, 0, (long)wordChars.c_str()); +} + + +//---------------------------------------------------------------------- +// Brace highlighting + + +void wxStyledTextCtrl::BraceHighlight(int pos1, int pos2) { + SendMsg(SCI_BRACEHIGHLIGHT, pos1, pos2); +} + + +void wxStyledTextCtrl::BraceBadlight(int pos) { + SendMsg(SCI_BRACEBADLIGHT, pos); +} + + +int wxStyledTextCtrl::BraceMatch(int pos, int maxReStyle) { + return SendMsg(SCI_BRACEMATCH, pos, maxReStyle); +} + + + +//---------------------------------------------------------------------- +// Markers + +void wxStyledTextCtrl::MarkerDefine(int markerNumber, int markerSymbol, + const wxColour& foreground, + const wxColour& background) { + MarkerSetType(markerNumber, markerSymbol); + MarkerSetForeground(markerNumber, foreground); + MarkerSetBackground(markerNumber, background); +} + + +void wxStyledTextCtrl::MarkerSetType(int markerNumber, int markerSymbol) { + SendMsg(SCI_MARKERDEFINE, markerNumber, markerSymbol); +} + + +void wxStyledTextCtrl::MarkerSetForeground(int markerNumber, const wxColour& colour) { + SendMsg(SCI_MARKERSETFORE, markerNumber, wxColourAsLong(colour)); +} + + +void wxStyledTextCtrl::MarkerSetBackground(int markerNumber, const wxColour& colour) { + SendMsg(SCI_MARKERSETBACK, markerNumber, wxColourAsLong(colour)); +} + + +int wxStyledTextCtrl::MarkerAdd(int line, int markerNumber) { + return SendMsg(SCI_MARKERADD, line, markerNumber); +} + + +void wxStyledTextCtrl::MarkerDelete(int line, int markerNumber) { + SendMsg(SCI_MARKERDELETE, line, markerNumber); +} + + +void wxStyledTextCtrl::MarkerDeleteAll(int markerNumber) { + SendMsg(SCI_MARKERDELETEALL, markerNumber); +} + + +int wxStyledTextCtrl::MarkerGet(int line) { + return SendMsg(SCI_MARKERGET); +} + + +int wxStyledTextCtrl::MarkerGetNextLine(int lineStart, int markerMask) { + return SendMsg(SCI_MARKERNEXT, lineStart, markerMask); +} + + +int wxStyledTextCtrl::MarkerGetPrevLine(int lineStart, int markerMask) { +// return SendMsg(SCI_MARKERPREV, lineStart, markerMask); + return 0; +} + + +int wxStyledTextCtrl::MarkerLineFromHandle(int handle) { + return SendMsg(SCI_MARKERLINEFROMHANDLE, handle); +} + + +void wxStyledTextCtrl::MarkerDeleteHandle(int handle) { + SendMsg(SCI_MARKERDELETEHANDLE, handle); +} + + + +//---------------------------------------------------------------------- +// Indicators + + +void wxStyledTextCtrl::IndicatorSetStyle(int indicNum, int indicStyle) { + SendMsg(SCI_INDICSETSTYLE, indicNum, indicStyle); +} + + +int wxStyledTextCtrl::IndicatorGetStyle(int indicNum) { + return SendMsg(SCI_INDICGETSTYLE, indicNum); +} + + +void wxStyledTextCtrl::IndicatorSetColour(int indicNum, const wxColour& colour) { + SendMsg(SCI_INDICSETSTYLE, indicNum, wxColourAsLong(colour)); +} + + + +//---------------------------------------------------------------------- +// Auto completion + + +void wxStyledTextCtrl::AutoCompShow(const wxString& listOfWords) { + SendMsg(SCI_AUTOCSHOW, 0, (long)listOfWords.c_str()); +} + + +void wxStyledTextCtrl::AutoCompCancel() { + SendMsg(SCI_AUTOCCANCEL); +} + + +bool wxStyledTextCtrl::AutoCompActive() { + return SendMsg(SCI_AUTOCACTIVE) != 0; +} + + +int wxStyledTextCtrl::AutoCompPosAtStart() { + return SendMsg(SCI_AUTOCPOSSTART); +} + + +void wxStyledTextCtrl::AutoCompComplete() { + SendMsg(SCI_AUTOCCOMPLETE); +} + + +void wxStyledTextCtrl::AutoCompStopChars(const wxString& stopChars) { + SendMsg(SCI_AUTOCSHOW, 0, (long)stopChars.c_str()); +} + + +//---------------------------------------------------------------------- +// Call tips + +void wxStyledTextCtrl::CallTipShow(int pos, const wxString& text) { + SendMsg(SCI_CALLTIPSHOW, pos, (long)text.c_str()); +} + + +void wxStyledTextCtrl::CallTipCancel() { + SendMsg(SCI_CALLTIPCANCEL); +} + + +bool wxStyledTextCtrl::CallTipActive() { + return SendMsg(SCI_CALLTIPACTIVE) != 0; +} + + +int wxStyledTextCtrl::CallTipPosAtStart() { + return SendMsg(SCI_CALLTIPPOSSTART); +} + + +void wxStyledTextCtrl::CallTipSetHighlight(int start, int end) { + SendMsg(SCI_CALLTIPSETHLT, start, end); +} + + +void wxStyledTextCtrl::CallTipSetBackground(const wxColour& colour) { + SendMsg(SCI_CALLTIPSETBACK, wxColourAsLong(colour)); +} + + +//---------------------------------------------------------------------- +// Key bindings + +void wxStyledTextCtrl::CmdKeyAssign(int key, int modifiers, int cmd) { + SendMsg(SCI_ASSIGNCMDKEY, MAKELONG(key, modifiers), cmd); +} + + +void wxStyledTextCtrl::CmdKeyClear(int key, int modifiers) { + SendMsg(SCI_CLEARCMDKEY, MAKELONG(key, modifiers)); +} + + +void wxStyledTextCtrl::CmdKeyClearAll() { + SendMsg(SCI_CLEARALLCMDKEYS); +} + + +void wxStyledTextCtrl::CmdKeyExecute(int cmd) { + SendMsg(cmd); +} + + + +//---------------------------------------------------------------------- +// Print formatting + +int +wxStyledTextCtrl::FormatRange(bool doDraw, + int startPos, + int endPos, + wxDC* draw, + wxDC* target, // Why does it use two? Can they be the same? + wxRect renderRect, + wxRect pageRect) { + FORMATRANGE fr; + + fr.hdc = draw; + fr.hdcTarget = target; + fr.rc.top = renderRect.GetTop(); + fr.rc.left = renderRect.GetLeft(); + fr.rc.right = renderRect.GetRight(); + fr.rc.bottom = renderRect.GetBottom(); + fr.rcPage.top = pageRect.GetTop(); + fr.rcPage.left = pageRect.GetLeft(); + fr.rcPage.right = pageRect.GetRight(); + fr.rcPage.bottom = pageRect.GetBottom(); + fr.chrg.cpMin = startPos; + fr.chrg.cpMax = endPos; + + return SendMsg(EM_FORMATRANGE, doDraw, (long)&fr); +} + + +//---------------------------------------------------------------------- +// Document Sharing + +void* wxStyledTextCtrl::GetDocument() { + return (void*)SendMsg(SCI_GETDOCPOINTER); +} + + +void wxStyledTextCtrl::SetDocument(void* document) { + SendMsg(SCI_SETDOCPOINTER, 0, (long)document); +} + + +//---------------------------------------------------------------------- +// Long Lines + +int wxStyledTextCtrl::GetEdgeColumn() { + return SendMsg(SCI_GETEDGECOLUMN); +} + +void wxStyledTextCtrl::SetEdgeColumn(int column) { + SendMsg(SCI_SETEDGECOLUMN, column); +} + +wxSTC_EDGE wxStyledTextCtrl::GetEdgeMode() { + return (wxSTC_EDGE) SendMsg(SCI_GETEDGEMODE); +} + +void wxStyledTextCtrl::SetEdgeMode(wxSTC_EDGE mode){ + SendMsg(SCI_SETEDGEMODE, mode); +} + +wxColour wxStyledTextCtrl::GetEdgeColour() { + long c = SendMsg(SCI_GETEDGECOLOUR); + return wxColourFromLong(c); +} + +void wxStyledTextCtrl::SetEdgeColour(const wxColour& colour) { + SendMsg(SCI_SETEDGECOLOUR, wxColourAsLong(colour)); +} + + +//---------------------------------------------------------------------- +// Lexer + +void wxStyledTextCtrl::SetLexer(wxSTC_LEX lexer) { + SendMsg(SCI_SETLEXER, lexer); +} + + +wxSTC_LEX wxStyledTextCtrl::GetLexer() { + return (wxSTC_LEX)SendMsg(SCI_GETLEXER); +} + + +void wxStyledTextCtrl::Colourise(int start, int end) { + SendMsg(SCI_COLOURISE, start, end); +} + + +void wxStyledTextCtrl::SetProperty(const wxString& key, const wxString& value) { + SendMsg(SCI_SETPROPERTY, (long)key.c_str(), (long)value.c_str()); +} + + +void wxStyledTextCtrl::SetKeywords(int keywordSet, const wxString& keywordList) { + SendMsg(SCI_SETKEYWORDS, keywordSet, (long)keywordList.c_str()); +} + + + +//---------------------------------------------------------------------- +// Event handlers + +void wxStyledTextCtrl::OnPaint(wxPaintEvent& evt) { + wxPaintDC dc(this); + wxRegion region = GetUpdateRegion(); + + m_swx->DoPaint(&dc, region.GetBox()); +} + +void wxStyledTextCtrl::OnScrollWin(wxScrollWinEvent& evt) { + if (evt.GetOrientation() == wxHORIZONTAL) + m_swx->DoHScroll(evt.GetEventType(), evt.GetPosition()); + else + m_swx->DoVScroll(evt.GetEventType(), evt.GetPosition()); +} + +void wxStyledTextCtrl::OnSize(wxSizeEvent& evt) { + wxSize sz = GetClientSize(); + m_swx->DoSize(sz.x, sz.y); +} + +void wxStyledTextCtrl::OnMouseLeftDown(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoButtonDown(Point(pt.x, pt.y), m_stopWatch.Time(), + evt.ShiftDown(), evt.ControlDown(), evt.AltDown()); +} + +void wxStyledTextCtrl::OnMouseMove(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoButtonMove(Point(pt.x, pt.y)); +} + +void wxStyledTextCtrl::OnMouseLeftUp(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoButtonUp(Point(pt.x, pt.y), m_stopWatch.Time(), + evt.ControlDown()); +} + + +void wxStyledTextCtrl::OnMouseRightUp(wxMouseEvent& evt) { + wxPoint pt = evt.GetPosition(); + m_swx->DoContextMenu(Point(pt.x, pt.y)); +} + +void wxStyledTextCtrl::OnChar(wxKeyEvent& evt) { + int processed = 0; + long key = evt.KeyCode(); + if ((key > WXK_ESCAPE) && + (key != WXK_DELETE) && (key < 255) && + !evt.ControlDown() && !evt.AltDown()) { + + m_swx->DoAddChar(key); + processed = true; + } + else { + key = toupper(key); + processed = m_swx->DoKeyDown(key, evt.ShiftDown(), + evt.ControlDown(), evt.AltDown()); + } + if (! processed) + evt.Skip(); +} + +void wxStyledTextCtrl::OnLoseFocus(wxFocusEvent& evt) { + m_swx->DoLoseFocus(); +} + +void wxStyledTextCtrl::OnGainFocus(wxFocusEvent& evt) { + m_swx->DoGainFocus(); +} + +void wxStyledTextCtrl::OnSysColourChanged(wxSysColourChangedEvent& evt) { + m_swx->DoSysColourChange(); +} + +void wxStyledTextCtrl::OnEraseBackground(wxEraseEvent& evt) { + // do nothing to help avoid flashing +} + + + +void wxStyledTextCtrl::OnMenu(wxCommandEvent& evt) { + m_swx->DoCommand(evt.GetId()); +} + + +//---------------------------------------------------------------------- +// Turn notifications from Scintilla into events + +void wxStyledTextCtrl::NotifyChange() { + wxStyledTextEvent evt(wxEVT_STC_CHANGE, GetId()); + GetEventHandler()->ProcessEvent(evt); +} + +void wxStyledTextCtrl::NotifyParent(SCNotification* _scn) { + SCNotification& scn = *_scn; + int eventType = 0; + switch (scn.nmhdr.code) { + case SCN_STYLENEEDED: + eventType = wxEVT_STC_STYLENEEDED; + break; + case SCN_CHARADDED: + eventType = wxEVT_STC_CHARADDED; + break; + case SCN_UPDATEUI: + eventType = wxEVT_STC_UPDATEUI; + break; + case SCN_SAVEPOINTREACHED: + eventType = wxEVT_STC_SAVEPOINTREACHED; + break; + case SCN_SAVEPOINTLEFT: + eventType = wxEVT_STC_SAVEPOINTLEFT; + break; + case SCN_MODIFYATTEMPTRO: + eventType = wxEVT_STC_ROMODIFYATTEMPT; + break; + case SCN_DOUBLECLICK: + eventType = wxEVT_STC_DOUBLECLICK; + break; + case SCN_MODIFIED: + eventType = wxEVT_STC_MODIFIED; + break; + case SCN_KEY: + eventType = wxEVT_STC_KEY; + break; + case SCN_MACRORECORD: + eventType = wxEVT_STC_MACRORECORD; + break; + case SCN_MARGINCLICK: + eventType = wxEVT_STC_MARGINCLICK; + break; + case SCN_NEEDSHOWN: + eventType = wxEVT_STC_NEEDSHOWN; + break; + } + if (eventType) { + wxStyledTextEvent evt(eventType, GetId()); + evt.SetPosition(scn.position); + evt.SetKey(scn.ch); + evt.SetModifiers(scn.modifiers); + if (eventType == wxEVT_STC_MODIFIED) { + evt.SetModificationType(scn.modificationType); + evt.SetText(scn.text); + evt.SetLength(scn.length); + evt.SetLinesAdded(scn.linesAdded); + evt.SetLine(scn.line); + evt.SetFoldLevelNow(scn.foldLevelNow); + evt.SetFoldLevelPrev(scn.foldLevelPrev); + } + if (eventType == wxEVT_STC_MARGINCLICK) + evt.SetMargin(scn.margin); + if (eventType == wxEVT_STC_MACRORECORD) { + evt.SetMessage(scn.message); + evt.SetWParam(scn.wParam); + evt.SetLParam(scn.lParam); + } + + GetEventHandler()->ProcessEvent(evt); + } +} + + + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +wxStyledTextEvent::wxStyledTextEvent(wxEventType commandType, int id) + : wxCommandEvent(commandType, id) +{ + m_position = 0; + m_key = 0; + m_modifiers = 0; + m_modificationType = 0; + m_length = 0; + m_linesAdded = 0; + m_line = 0; + m_foldLevelNow = 0; + m_foldLevelPrev = 0; + m_margin = 0; + m_message = 0; + m_wParam = 0; + m_lParam = 0; + + +} + +bool wxStyledTextEvent::GetShift() const { return (m_modifiers & SCI_SHIFT) != 0; } +bool wxStyledTextEvent::GetControl() const { return (m_modifiers & SCI_CTRL) != 0; } +bool wxStyledTextEvent::GetAlt() const { return (m_modifiers & SCI_ALT) != 0; } + +void wxStyledTextEvent::CopyObject(wxObject& obj) const { + wxCommandEvent::CopyObject(obj); + + wxStyledTextEvent* o = (wxStyledTextEvent*)&obj; + o->m_position = m_position; + o->m_key = m_key; + o->m_modifiers = m_modifiers; + o->m_modificationType = m_modificationType; + o->m_text = m_text; + o->m_length = m_length; + o->m_linesAdded = m_linesAdded; + o->m_line = m_line; + o->m_foldLevelNow = m_foldLevelNow; + o->m_foldLevelPrev = m_foldLevelPrev; + + o->m_margin = m_margin; + + o->m_message = m_message; + o->m_wParam = m_wParam; + o->m_lParam = m_lParam; + + + +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + -- 2.45.2