Date: 02-16-2022
Return to Index
 
 
  
created by gbSnippets
'This is presented only as a reference. It is pulled directly from
'the Scintilla distribution.
 
'Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
 
// Scintilla Source Code edit Control
/** @file ScintillaBase.cxx
 ** An enhanced subclass of Editor with calltips, autocomplete AND context Menu.
 **/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
 
#Include <stdlib.h>
#Include <String.h>
#Include <stdio.h>
#Include <ctype.h>
 
#Include <String>
#Include <vector>
 
#Include "Platform.h"
 
#Include "Scintilla.h"
#Include "PropSet.h"
#Include "PropSetSimple.h"
#ifdef SCI_LEXER
#Include "SciLexer.h"
#Include "Accessor.h"
#Include "DocumentAccessor.h"
#Include "KeyWords.h"
#EndIf
#Include "SplitVector.h"
#Include "Partitioning.h"
#Include "RunStyles.h"
#Include "ContractionState.h"
#Include "CellBuffer.h"
#Include "CallTip.h"
#Include "KeyMap.h"
#Include "Indicator.h"
#Include "XPM.h"
#Include "LineMarker.h"
#Include "Style.h"
#Include "ViewStyle.h"
#Include "AutoComplete.h"
#Include "CharClassify.h"
#Include "Decoration.h"
#Include "Document.h"
#Include "Selection.h"
#Include "PositionCache.h"
#Include "Editor.h"
#Include "ScintillaBase.h"
 
#ifdef SCI_NAMESPACE
using namespace Scintilla;
#EndIf
 
ScintillaBase::ScintillaBase() {
	displayPopupMenu = true;
	listType = 0;
	maxListWidth = 0;
#ifdef SCI_LEXER
	lexLanguage = SCLEX_CONTAINER;
	performingStyle = false;
	lexCurrent = 0;
	For (Int wl = 0; wl < numWordLists; wl++)
		keyWordLists[wl] = New WordList;
	keyWordLists[numWordLists] = 0;
#EndIf
}
 
ScintillaBase::~ScintillaBase() {
#ifdef SCI_LEXER
	For (Int wl = 0; wl < numWordLists; wl++)
		Delete keyWordLists[wl];
#EndIf
}
 
void ScintillaBase::Finalise() {
	Editor::Finalise();
	Popup.Destroy();
}
 
void ScintillaBase::RefreshColourPalette(Palette &pal, bool want) {
	Editor::RefreshColourPalette(pal, want);
	ct.RefreshColourPalette(pal, want);
}
 
void ScintillaBase::AddCharUTF(char *s, unsigned Int Len, bool treatAsDBCS) {
	bool isFillUp = ac.Active() && ac.IsFillUpChar(*s);
	If (!isFillUp) {
		Editor::AddCharUTF(s, Len, treatAsDBCS);
	}
	If (ac.Active()) {
		AutoCompleteCharacterAdded(s[0]);
		// For fill ups Add the character after the autocompletion has
		// triggered so containers see the key so can Display a calltip.
		If (isFillUp) {
			Editor::AddCharUTF(s, Len, treatAsDBCS);
		}
	}
}
 
void ScintillaBase::Command(Int cmdId) {
 
	Switch (cmdId) {
 
	Case idAutoComplete:  	// Nothing to Do
 
		break;
 
	Case idCallTip:  	// Nothing to Do
 
		break;
 
	Case idcmdUndo:
		WndProc(SCI_UNDO, 0, 0);
		break;
 
	Case idcmdRedo:
		WndProc(SCI_REDO, 0, 0);
		break;
 
	Case idcmdCut:
		WndProc(SCI_CUT, 0, 0);
		break;
 
	Case idcmdCopy:
		WndProc(SCI_COPY, 0, 0);
		break;
 
	Case idcmdPaste:
		WndProc(SCI_PASTE, 0, 0);
		break;
 
	Case idcmdDelete:
		WndProc(SCI_CLEAR, 0, 0);
		break;
 
	Case idcmdSelectAll:
		WndProc(SCI_SELECTALL, 0, 0);
		break;
	}
}
 
Int ScintillaBase::KeyCommand(unsigned Int iMessage) {
	// Most key commands Cancel autocompletion Mode
	If (ac.Active()) {
		Switch (iMessage) {
			// Except For these
		Case SCI_LINEDOWN:
			AutoCompleteMove(1);
			Return 0;
		Case SCI_LINEUP:
			AutoCompleteMove( -1);
			Return 0;
		Case SCI_PAGEDOWN:
			AutoCompleteMove(5);
			Return 0;
		Case SCI_PAGEUP:
			AutoCompleteMove( -5);
			Return 0;
		Case SCI_VCHOME:
			AutoCompleteMove( -5000);
			Return 0;
		Case SCI_LINEEND:
			AutoCompleteMove(5000);
			Return 0;
		Case SCI_DELETEBACK:
			DelCharBack(true);
			AutoCompleteCharacterDeleted();
			EnsureCaretVisible();
			Return 0;
		Case SCI_DELETEBACKNOTLINE:
			DelCharBack(false);
			AutoCompleteCharacterDeleted();
			EnsureCaretVisible();
			Return 0;
		Case SCI_TAB:
			AutoCompleteCompleted();
			Return 0;
		Case SCI_NEWLINE:
			AutoCompleteCompleted();
			Return 0;
 
		Default:
			AutoCompleteCancel();
		}
	}
 
	If (ct.inCallTipMode) {
		If (
		    (iMessage != SCI_CHARLEFT) &&
		    (iMessage != SCI_CHARLEFTEXTEND) &&
		    (iMessage != SCI_CHARRIGHT) &&
		    (iMessage != SCI_CHARRIGHTEXTEND) &&
		    (iMessage != SCI_EDITTOGGLEOVERTYPE) &&
		    (iMessage != SCI_DELETEBACK) &&
		    (iMessage != SCI_DELETEBACKNOTLINE)
		) {
			ct.CallTipCancel();
		}
		If ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) {
			If (sel.MainCaret() <= ct.posStartCallTip) {
				ct.CallTipCancel();
			}
		}
	}
	Return Editor::KeyCommand(iMessage);
}
 
void ScintillaBase::AutoCompleteDoubleClick(void *p) {
	ScintillaBase *sci = reinterpret_cast<ScintillaBase *>(p);
	sci->AutoCompleteCompleted();
}
 
void ScintillaBase::AutoCompleteStart(Int lenEntered, const char *list) {
	//Platform::DebugPrintf("AutoComplete %s\n", list);
	ct.CallTipCancel();
 
	If (ac.chooseSingle && (listType == 0)) {
		If (list && !strchr(list, ac.GetSeparator())) {
			const char *typeSep = strchr(list, ac.GetTypesep());
			size_t lenInsert = (typeSep) ? (typeSep-list) : strlen(list);
			If (ac.ignoreCase) {
				SetEmptySelection(sel.MainCaret() - lenEntered);
				pdoc->DeleteChars(sel.MainCaret(), lenEntered);
				SetEmptySelection(sel.MainCaret());
				pdoc->InsertString(sel.MainCaret(), list, lenInsert);
				SetEmptySelection(sel.MainCaret() + lenInsert);
			} Else {
				SetEmptySelection(sel.MainCaret());
				pdoc->InsertString(sel.MainCaret(), list + lenEntered, lenInsert - lenEntered);
				SetEmptySelection(sel.MainCaret() + lenInsert - lenEntered);
			}
			Return;
		}
	}
	ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(),
				lenEntered, vs.lineHeight, IsUnicodeMode());
 
	PRectangle rcClient = GetClientRectangle();
	Point pt = LocationFromPosition(sel.MainCaret() - lenEntered);
	PRectangle rcPopupBounds = wMain.GetMonitorRect(pt);
	If (rcPopupBounds.Height() == 0)
		rcPopupBounds = rcClient;
 
	Int heightLB = 100;
	Int widthLB = 100;
	If (pt.x >= rcClient.right - widthLB) {
		HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB);
		Redraw();
		pt = PointMainCaret();
	}
	PRectangle rcac;
	rcac.left = pt.x - ac.lb->CaretFromEdge();
	If (pt.y >= rcPopupBounds.bottom - heightLB &&  // Wont Fit below.
	        pt.y >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2) { // AND there is more room above.
		rcac.top = pt.y - heightLB;
		If (rcac.top < rcPopupBounds.top) {
			heightLB -= (rcPopupBounds.top - rcac.top);
			rcac.top = rcPopupBounds.top;
		}
	} Else {
		rcac.top = pt.y + vs.lineHeight;
	}
	rcac.right = rcac.left + widthLB;
	rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcPopupBounds.bottom);
	ac.lb->SetPositionRelative(rcac, wMain);
	ac.lb->SetFont(vs.styles[STYLE_DEFAULT].Font);
	unsigned Int aveCharWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
	ac.lb->SetAverageCharWidth(aveCharWidth);
	ac.lb->SetDoubleClickAction(AutoCompleteDoubleClick, this);
 
	ac.SetList(list);
 
	// Fiddle the position of the list so it is right Next to the target AND wide enough For all its strings
	PRectangle rcList = ac.lb->GetDesiredRect();
	Int heightAlloced = rcList.bottom - rcList.top;
	widthLB = Platform::Maximum(widthLB, rcList.right - rcList.left);
	If (maxListWidth != 0)
		widthLB = Platform::Minimum(widthLB, aveCharWidth*maxListWidth);
	// Make an allowance For large strings in list
	rcList.left = pt.x - ac.lb->CaretFromEdge();
	rcList.right = rcList.left + widthLB;
	If (((pt.y + vs.lineHeight) >= (rcPopupBounds.bottom - heightAlloced)) &&  // Wont Fit below.
	        ((pt.y + vs.lineHeight / 2) >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2)) { // AND there is more room above.
		rcList.top = pt.y - heightAlloced;
	} Else {
		rcList.top = pt.y + vs.lineHeight;
	}
	rcList.bottom = rcList.top + heightAlloced;
	ac.lb->SetPositionRelative(rcList, wMain);
	ac.Show(true);
	If (lenEntered != 0) {
		AutoCompleteMoveToCurrentWord();
	}
}
 
void ScintillaBase::AutoCompleteCancel() {
	If (ac.Active()) {
		SCNotification scn = {0};
		scn.Nmhdr.Code = SCN_AUTOCCANCELLED;
		scn.wParam = 0;
		scn.listType = 0;
		NotifyParent(scn);
	}
	ac.Cancel();
}
 
void ScintillaBase::AutoCompleteMove(Int delta) {
	ac.Move(delta);
}
 
void ScintillaBase::AutoCompleteMoveToCurrentWord() {
	char wordCurrent[1000];
	Int i;
	Int startWord = ac.posStart - ac.startLen;
	For (i = startWord; i < sel.MainCaret() && i - startWord < 1000; i++)
		wordCurrent[i - startWord] = pdoc->CharAt(i);
	wordCurrent[Platform::Minimum(i - startWord, 999)] = '\0';
	ac.Select(wordCurrent);
}
 
void ScintillaBase::AutoCompleteCharacterAdded(char ch) {
	If (ac.IsFillUpChar(ch)) {
		AutoCompleteCompleted();
	} Else If (ac.IsStopChar(ch)) {
		AutoCompleteCancel();
	} Else {
		AutoCompleteMoveToCurrentWord();
	}
}
 
void ScintillaBase::AutoCompleteCharacterDeleted() {
	If (sel.MainCaret() < ac.posStart - ac.startLen) {
		AutoCompleteCancel();
	} Else If (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) {
		AutoCompleteCancel();
	} Else {
		AutoCompleteMoveToCurrentWord();
	}
	SCNotification scn = {0};
	scn.Nmhdr.Code = SCN_AUTOCCHARDELETED;
	scn.wParam = 0;
	scn.listType = 0;
	NotifyParent(scn);
}
 
void ScintillaBase::AutoCompleteCompleted() {
	Int Item = ac.lb->GetSelection();
	char selected[1000];
	selected[0] = '\0';
	If (Item != -1) {
		ac.lb->GetValue(Item, selected, SizeOf(selected));
	} Else {
		AutoCompleteCancel();
		Return;
	}
 
	ac.Show(false);
 
	SCNotification scn = {0};
	scn.Nmhdr.Code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION;
	scn.message = 0;
	scn.wParam = listType;
	scn.listType = listType;
	Position firstPos = ac.posStart - ac.startLen;
	scn.lParam = firstPos;
	scn.Text = selected;
	NotifyParent(scn);
 
	If (!ac.Active())
		Return;
	ac.Cancel();
 
	If (listType > 0)
		Return;
 
	Position endPos = sel.MainCaret();
	If (ac.dropRestOfWord)
		endPos = pdoc->ExtendWordSelect(endPos, 1, true);
	If (endPos < firstPos)
		Return;
	UndoGroup ug(pdoc);
	If (endPos != firstPos) {
		pdoc->DeleteChars(firstPos, endPos - firstPos);
	}
	SetEmptySelection(ac.posStart);
	If (Item != -1) {
		pdoc->InsertCString(firstPos, selected);
		SetEmptySelection(firstPos + static_cast<Int>(strlen(selected)));
	}
}
 
Int ScintillaBase::AutoCompleteGetCurrent() {
	If (!ac.Active())
		Return -1;
	Return ac.lb->GetSelection();
}
 
Int ScintillaBase::AutoCompleteGetCurrentText(char *buffer) {
	If (ac.Active()) {
		Int Item = ac.lb->GetSelection();
		char selected[1000];
		selected[0] = '\0';
		If (Item != -1) {
			ac.lb->GetValue(Item, selected, SizeOf(selected));
			If (buffer != NULL)
				strcpy(buffer, selected);
			Return strlen(selected);
		}
	}
	If (buffer != NULL)
		*buffer = '\0';
	Return 0;
}
 
void ScintillaBase::CallTipShow(Point pt, const char *defn) {
	ac.Cancel();
	pt.y += vs.lineHeight;
	// If container knows about STYLE_CALLTIP Then use it in place of the
	// STYLE_DEFAULT For the face Name, Size AND character Set. Also use it
	// For the foreground AND background colour.
	Int ctStyle = ct.UseStyleCallTip() ? STYLE_CALLTIP : STYLE_DEFAULT;
	If (ct.UseStyleCallTip()) {
		ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back);
	}
	PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
		defn,
		vs.styles[ctStyle].fontName,
		vs.styles[ctStyle].sizeZoomed,
		CodePage(),
		vs.styles[ctStyle].characterSet,
		wMain);
	// If the Call-tip Window would be out of the Client
	// space, adjust so it displays above the Text.
	PRectangle rcClient = GetClientRectangle();
	If (rc.bottom > rcClient.bottom) {
		Int offset = vs.lineHeight + rc.Height();
		rc.top -= offset;
		rc.bottom -= offset;
	}
	// Now Display the Window.
	CreateCallTipWindow(rc);
	ct.wCallTip.SetPositionRelative(rc, wMain);
	ct.wCallTip.Show();
}
 
void ScintillaBase::CallTipClick() {
	SCNotification scn = {0};
	scn.Nmhdr.Code = SCN_CALLTIPCLICK;
	scn.position = ct.clickPlace;
	NotifyParent(scn);
}
 
void ScintillaBase::ContextMenu(Point pt) {
	If (displayPopupMenu) {
		bool writable = !WndProc(SCI_GETREADONLY, 0, 0);
		Popup.CreatePopUp();
		AddToPopUp("Undo", idcmdUndo, writable && pdoc->CanUndo());
		AddToPopUp("Redo", idcmdRedo, writable && pdoc->CanRedo());
		AddToPopUp("");
		AddToPopUp("Cut", idcmdCut, writable && !sel.Empty());
		AddToPopUp("Copy", idcmdCopy, !sel.Empty());
		AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0));
		AddToPopUp("Delete", idcmdDelete, writable && !sel.Empty());
		AddToPopUp("");
		AddToPopUp("Select All", idcmdSelectAll);
		Popup.Show(pt, wMain);
	}
}
 
void ScintillaBase::CancelModes() {
	AutoCompleteCancel();
	ct.CallTipCancel();
	Editor::CancelModes();
}
 
void ScintillaBase::ButtonDown(Point pt, unsigned Int curTime, bool Shift, bool ctrl, bool alt) {
	CancelModes();
	Editor::ButtonDown(pt, curTime, Shift, ctrl, alt);
}
 
#ifdef SCI_LEXER
void ScintillaBase::SetLexer(uptr_t wParam) {
	lexLanguage = wParam;
	lexCurrent = LexerModule::Find(lexLanguage);
	If (!lexCurrent)
		lexCurrent = LexerModule::Find(SCLEX_NULL);
	Int Bits = lexCurrent ? lexCurrent->GetStyleBitsNeeded() : 5;
	vs.EnsureStyle((1 << Bits) - 1);
}
 
void ScintillaBase::SetLexerLanguage(const char *languageName) {
	lexLanguage = SCLEX_CONTAINER;
	lexCurrent = LexerModule::Find(languageName);
	If (!lexCurrent)
		lexCurrent = LexerModule::Find(SCLEX_NULL);
	If (lexCurrent)
		lexLanguage = lexCurrent->GetLanguage();
	Int Bits = lexCurrent ? lexCurrent->GetStyleBitsNeeded() : 5;
	vs.EnsureStyle((1 << Bits) - 1);
}
 
void ScintillaBase::Colourise(Int start, Int End) {
	If (!performingStyle) {
		// Protect against reentrance, which may occur, For example, when
		// fold Points are discovered While performing styling AND the folding
		// Code looks For Child Lines which may trigger styling.
		performingStyle = true;
 
		Int lengthDoc = pdoc->Length();
		If (End == -1)
			End = lengthDoc;
		Int Len = End - start;
 
		PLATFORM_ASSERT(Len >= 0);
		PLATFORM_ASSERT(start + Len <= lengthDoc);
 
		//WindowAccessor styler(wMain.GetID(), props);
		DocumentAccessor styler(pdoc, props, wMain.GetID());
 
		Int styleStart = 0;
		If (start > 0)
			styleStart = styler.StyleAt(start - 1) & pdoc->stylingBitsMask;
		styler.SetCodePage(pdoc->dbcsCodePage);
 
		If (lexCurrent && (Len > 0)) {	// Should always succeed as null lexer should always be available
			lexCurrent->Lex(start, Len, styleStart, keyWordLists, styler);
			styler.Flush();
			If (styler.GetPropertyInt("fold")) {
				lexCurrent->Fold(start, Len, styleStart, keyWordLists, styler);
				styler.Flush();
			}
		}
 
		performingStyle = false;
	}
}
#EndIf
 
void ScintillaBase::NotifyStyleToNeeded(Int endStyleNeeded) {
#ifdef SCI_LEXER
	If (lexLanguage != SCLEX_CONTAINER) {
		Int endStyled = WndProc(SCI_GETENDSTYLED, 0, 0);
		Int lineEndStyled = WndProc(SCI_LINEFROMPOSITION, endStyled, 0);
		endStyled = WndProc(SCI_POSITIONFROMLINE, lineEndStyled, 0);
		Colourise(endStyled, endStyleNeeded);
		Return;
	}
#EndIf
	Editor::NotifyStyleToNeeded(endStyleNeeded);
}
 
sptr_t ScintillaBase::WndProc(unsigned Int iMessage, uptr_t wParam, sptr_t lParam) {
	Switch (iMessage) {
	Case SCI_AUTOCSHOW:
		listType = 0;
		AutoCompleteStart(wParam, reinterpret_cast<const char *>(lParam));
		break;
 
	Case SCI_AUTOCCANCEL:
		ac.Cancel();
		break;
 
	Case SCI_AUTOCACTIVE:
		Return ac.Active();
 
	Case SCI_AUTOCPOSSTART:
		Return ac.posStart;
 
	Case SCI_AUTOCCOMPLETE:
		AutoCompleteCompleted();
		break;
 
	Case SCI_AUTOCSETSEPARATOR:
		ac.SetSeparator(static_cast<char>(wParam));
		break;
 
	Case SCI_AUTOCGETSEPARATOR:
		Return ac.GetSeparator();
 
	Case SCI_AUTOCSTOPS:
		ac.SetStopChars(reinterpret_cast<char *>(lParam));
		break;
 
	Case SCI_AUTOCSELECT:
		ac.Select(reinterpret_cast<char *>(lParam));
		break;
 
	Case SCI_AUTOCGETCURRENT:
		Return AutoCompleteGetCurrent();
 
	Case SCI_AUTOCGETCURRENTTEXT:
		Return AutoCompleteGetCurrentText(reinterpret_cast<char *>(lParam));
 
	Case SCI_AUTOCSETCANCELATSTART:
		ac.cancelAtStartPos = wParam != 0;
		break;
 
	Case SCI_AUTOCGETCANCELATSTART:
		Return ac.cancelAtStartPos;
 
	Case SCI_AUTOCSETFILLUPS:
		ac.SetFillUpChars(reinterpret_cast<char *>(lParam));
		break;
 
	Case SCI_AUTOCSETCHOOSESINGLE:
		ac.chooseSingle = wParam != 0;
		break;
 
	Case SCI_AUTOCGETCHOOSESINGLE:
		Return ac.chooseSingle;
 
	Case SCI_AUTOCSETIGNORECASE:
		ac.ignoreCase = wParam != 0;
		break;
 
	Case SCI_AUTOCGETIGNORECASE:
		Return ac.ignoreCase;
 
	Case SCI_USERLISTSHOW:
		listType = wParam;
		AutoCompleteStart(0, reinterpret_cast<const char *>(lParam));
		break;
 
	Case SCI_AUTOCSETAUTOHIDE:
		ac.autoHide = wParam != 0;
		break;
 
	Case SCI_AUTOCGETAUTOHIDE:
		Return ac.autoHide;
 
	Case SCI_AUTOCSETDROPRESTOFWORD:
		ac.dropRestOfWord = wParam != 0;
		break;
 
	Case SCI_AUTOCGETDROPRESTOFWORD:
		Return ac.dropRestOfWord;
 
	Case SCI_AUTOCSETMAXHEIGHT:
		ac.lb->SetVisibleRows(wParam);
		break;
 
	Case SCI_AUTOCGETMAXHEIGHT:
		Return ac.lb->GetVisibleRows();
 
	Case SCI_AUTOCSETMAXWIDTH:
		maxListWidth = wParam;
		break;
 
	Case SCI_AUTOCGETMAXWIDTH:
		Return maxListWidth;
 
	Case SCI_REGISTERIMAGE:
		ac.lb->RegisterImage(wParam, reinterpret_cast<const char *>(lParam));
		break;
 
	Case SCI_CLEARREGISTEREDIMAGES:
		ac.lb->ClearRegisteredImages();
		break;
 
	Case SCI_AUTOCSETTYPESEPARATOR:
		ac.SetTypesep(static_cast<char>(wParam));
		break;
 
	Case SCI_AUTOCGETTYPESEPARATOR:
		Return ac.GetTypesep();
 
	Case SCI_CALLTIPSHOW:
		CallTipShow(LocationFromPosition(wParam),
			reinterpret_cast<const char *>(lParam));
		break;
 
	Case SCI_CALLTIPCANCEL:
		ct.CallTipCancel();
		break;
 
	Case SCI_CALLTIPACTIVE:
		Return ct.inCallTipMode;
 
	Case SCI_CALLTIPPOSSTART:
		Return ct.posStartCallTip;
 
	Case SCI_CALLTIPSETHLT:
		ct.SetHighlight(wParam, lParam);
		break;
 
	Case SCI_CALLTIPSETBACK:
		ct.colourBG = ColourDesired(wParam);
		vs.styles[STYLE_CALLTIP].back = ct.colourBG;
		InvalidateStyleRedraw();
		break;
 
	Case SCI_CALLTIPSETFORE:
		ct.colourUnSel = ColourDesired(wParam);
		vs.styles[STYLE_CALLTIP].fore = ct.colourUnSel;
		InvalidateStyleRedraw();
		break;
 
	Case SCI_CALLTIPSETFOREHLT:
		ct.colourSel = ColourDesired(wParam);
		InvalidateStyleRedraw();
		break;
 
	Case SCI_CALLTIPUSESTYLE:
		ct.SetTabSize((Int)wParam);
		InvalidateStyleRedraw();
		break;
 
	Case SCI_USEPOPUP:
		displayPopupMenu = wParam != 0;
		break;
 
#ifdef SCI_LEXER
	Case SCI_SETLEXER:
		SetLexer(wParam);
		lexLanguage = wParam;
		break;
 
	Case SCI_GETLEXER:
		Return lexLanguage;
 
	Case SCI_COLOURISE:
		If (lexLanguage == SCLEX_CONTAINER) {
			pdoc->ModifiedAt(wParam);
			NotifyStyleToNeeded((lParam == -1) ? pdoc->Length() : lParam);
		} Else {
			Colourise(wParam, lParam);
		}
		Redraw();
		break;
 
	Case SCI_SETPROPERTY:
		props.Set(reinterpret_cast<const char *>(wParam),
		          reinterpret_cast<const char *>(lParam));
		break;
 
	Case SCI_GETPROPERTY:
			Return StringResult(lParam, props.Get(reinterpret_cast<const char *>(wParam)));
 
	Case SCI_GETPROPERTYEXPANDED: {
			char *Val = props.Expanded(reinterpret_cast<const char *>(wParam));
			const Int n = strlen(Val);
			If (lParam != 0) {
				char *ptr = reinterpret_cast<char *>(lParam);
				strcpy(ptr, Val);
			}
			Delete []Val;
			Return n;	// Not including NUL
		}
 
	Case SCI_GETPROPERTYINT:
		Return props.GetInt(reinterpret_cast<const char *>(wParam), lParam);
 
	Case SCI_SETKEYWORDS:
		If (wParam < numWordLists) {
			keyWordLists[wParam]->Clear();
			keyWordLists[wParam]->Set(reinterpret_cast<const char *>(lParam));
		}
		break;
 
	Case SCI_SETLEXERLANGUAGE:
		SetLexerLanguage(reinterpret_cast<const char *>(lParam));
		break;
 
	Case SCI_GETLEXERLANGUAGE:
		Return StringResult(lParam, lexCurrent ? lexCurrent->languageName : "");
 
	Case SCI_GETSTYLEBITSNEEDED:
		Return lexCurrent ? lexCurrent->GetStyleBitsNeeded() : 5;
 
#EndIf
 
	Default:
		Return Editor::WndProc(iMessage, wParam, lParam);
	}
	Return 0l;
}
 
'gbs_00674
'Date: 03-10-2012
http://www.garybeene.com/sw/gbsnippets.htm