📄 scintillawin.cxx
字号:
void ScintillaWin::AddToPopUp(const char *label, int cmd, bool enabled) {
#ifdef TOTAL_CONTROL
HMENU hmenuPopup = reinterpret_cast<HMENU>(popup.GetID());
if (!label[0])
::AppendMenu(hmenuPopup, MF_SEPARATOR, 0, "");
else if (enabled)
::AppendMenu(hmenuPopup, MF_STRING, cmd, label);
else
::AppendMenu(hmenuPopup, MF_STRING | MF_DISABLED | MF_GRAYED, cmd, label);
#endif
}
void ScintillaWin::ClaimSelection() {
// Windows does not have a primary selection
}
#ifdef SCI_LEXER
/*
Initial Windows-Only implementation of the external lexer
system in ScintillaWin class. Intention is to create a LexerModule
subclass (?) to have lex and fold methods which will call out to their
relevant DLLs...
*/
void ScintillaWin::SetLexer(uptr_t wParam) {
lexLanguage = wParam;
lexCurrent = LexerModule::Find(lexLanguage);
if (!lexCurrent)
lexCurrent = LexerModule::Find(SCLEX_NULL);
}
void ScintillaWin::SetLexerLanguage(const char *languageName) {
lexLanguage = SCLEX_CONTAINER;
lexCurrent = LexerModule::Find(languageName);
if (!lexCurrent)
lexCurrent = LexerModule::Find(SCLEX_NULL);
if (lexCurrent)
lexLanguage = lexCurrent->GetLanguage();
}
#endif
/// Implement IUnknown
STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe);
STDMETHODIMP FormatEnumerator_QueryInterface(FormatEnumerator *fe, REFIID riid, PVOID *ppv) {
//Platform::DebugPrintf("EFE QI");
*ppv = NULL;
if (riid == IID_IUnknown)
*ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
if (riid == IID_IEnumFORMATETC)
*ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
if (!*ppv)
return E_NOINTERFACE;
FormatEnumerator_AddRef(fe);
return S_OK;
}
STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe) {
return ++fe->ref;
}
STDMETHODIMP_(ULONG)FormatEnumerator_Release(FormatEnumerator *fe) {
fe->ref--;
if (fe->ref > 0)
return fe->ref;
delete fe;
return 0;
}
/// Implement IEnumFORMATETC
STDMETHODIMP FormatEnumerator_Next(FormatEnumerator *fe, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) {
//Platform::DebugPrintf("EFE Next %d %d", fe->pos, celt);
if (rgelt == NULL) return E_POINTER;
// We only support one format, so this is simple.
unsigned int putPos = 0;
while ((fe->pos < fe->formatsLen) && (putPos < celt)) {
rgelt->cfFormat = fe->formats[fe->pos];
rgelt->ptd = 0;
rgelt->dwAspect = DVASPECT_CONTENT;
rgelt->lindex = -1;
rgelt->tymed = TYMED_HGLOBAL;
fe->pos++;
putPos++;
}
if (pceltFetched)
*pceltFetched = putPos;
return putPos ? S_OK : S_FALSE;
}
STDMETHODIMP FormatEnumerator_Skip(FormatEnumerator *fe, ULONG celt) {
fe->pos += celt;
return S_OK;
}
STDMETHODIMP FormatEnumerator_Reset(FormatEnumerator *fe) {
fe->pos = 0;
return S_OK;
}
STDMETHODIMP FormatEnumerator_Clone(FormatEnumerator *fe, IEnumFORMATETC **ppenum) {
FormatEnumerator *pfe = new FormatEnumerator(fe->pos, fe->formats, fe->formatsLen);
return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
reinterpret_cast<void **>(ppenum));
}
static void *vtFormatEnumerator[] = {
(void *)(FormatEnumerator_QueryInterface),
(void *)(FormatEnumerator_AddRef),
(void *)(FormatEnumerator_Release),
(void *)(FormatEnumerator_Next),
(void *)(FormatEnumerator_Skip),
(void *)(FormatEnumerator_Reset),
(void *)(FormatEnumerator_Clone)
};
FormatEnumerator::FormatEnumerator(int pos_, CLIPFORMAT formats_[], int formatsLen_) {
vtbl = vtFormatEnumerator;
ref = 0; // First QI adds first reference...
pos = pos_;
formatsLen = formatsLen_;
for (int i=0;i<formatsLen;i++)
formats[i] = formats_[i];
}
/// Implement IUnknown
STDMETHODIMP DropSource_QueryInterface(DropSource *ds, REFIID riid, PVOID *ppv) {
return ds->sci->QueryInterface(riid, ppv);
}
STDMETHODIMP_(ULONG)DropSource_AddRef(DropSource *ds) {
return ds->sci->AddRef();
}
STDMETHODIMP_(ULONG)DropSource_Release(DropSource *ds) {
return ds->sci->Release();
}
/// Implement IDropSource
STDMETHODIMP DropSource_QueryContinueDrag(DropSource *, BOOL fEsc, DWORD grfKeyState) {
if (fEsc)
return DRAGDROP_S_CANCEL;
if (!(grfKeyState & MK_LBUTTON))
return DRAGDROP_S_DROP;
return S_OK;
}
STDMETHODIMP DropSource_GiveFeedback(DropSource *, DWORD) {
return DRAGDROP_S_USEDEFAULTCURSORS;
}
static void *vtDropSource[] = {
(void *)(DropSource_QueryInterface),
(void *)(DropSource_AddRef),
(void *)(DropSource_Release),
(void *)(DropSource_QueryContinueDrag),
(void *)(DropSource_GiveFeedback)
};
DropSource::DropSource() {
vtbl = vtDropSource;
sci = 0;
}
/// Implement IUnkown
STDMETHODIMP DataObject_QueryInterface(DataObject *pd, REFIID riid, PVOID *ppv) {
//Platform::DebugPrintf("DO QI %x\n", pd);
return pd->sci->QueryInterface(riid, ppv);
}
STDMETHODIMP_(ULONG)DataObject_AddRef(DataObject *pd) {
return pd->sci->AddRef();
}
STDMETHODIMP_(ULONG)DataObject_Release(DataObject *pd) {
return pd->sci->Release();
}
/// Implement IDataObject
STDMETHODIMP DataObject_GetData(DataObject *pd, FORMATETC *pFEIn, STGMEDIUM *pSTM) {
return pd->sci->GetData(pFEIn, pSTM);
}
STDMETHODIMP DataObject_GetDataHere(DataObject *, FORMATETC *, STGMEDIUM *) {
//Platform::DebugPrintf("DOB GetDataHere\n");
return E_NOTIMPL;
}
STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) {
if (pd->sci->DragIsRectangularOK(pFE->cfFormat) &&
pFE->ptd == 0 &&
(pFE->dwAspect & DVASPECT_CONTENT) != 0 &&
pFE->lindex == -1 &&
(pFE->tymed & TYMED_HGLOBAL) != 0
) {
return S_OK;
}
bool formatOK = (pFE->cfFormat == CF_TEXT) ||
((pFE->cfFormat == CF_UNICODETEXT) && pd->sci->IsUnicodeMode());
if (!formatOK ||
pFE->ptd != 0 ||
(pFE->dwAspect & DVASPECT_CONTENT) == 0 ||
pFE->lindex != -1 ||
(pFE->tymed & TYMED_HGLOBAL) == 0
) {
//Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
//return DATA_E_FORMATETC;
return S_FALSE;
}
//Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
return S_OK;
}
STDMETHODIMP DataObject_GetCanonicalFormatEtc(DataObject *pd, FORMATETC *, FORMATETC *pFEOut) {
//Platform::DebugPrintf("DOB GetCanon\n");
if (pd->sci->IsUnicodeMode())
pFEOut->cfFormat = CF_UNICODETEXT;
else
pFEOut->cfFormat = CF_TEXT;
pFEOut->ptd = 0;
pFEOut->dwAspect = DVASPECT_CONTENT;
pFEOut->lindex = -1;
pFEOut->tymed = TYMED_HGLOBAL;
return S_OK;
}
STDMETHODIMP DataObject_SetData(DataObject *, FORMATETC *, STGMEDIUM *, BOOL) {
//Platform::DebugPrintf("DOB SetData\n");
return E_FAIL;
}
STDMETHODIMP DataObject_EnumFormatEtc(DataObject *pd, DWORD dwDirection, IEnumFORMATETC **ppEnum) {
//Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
if (dwDirection != DATADIR_GET) {
*ppEnum = 0;
return E_FAIL;
}
FormatEnumerator *pfe;
if (pd->sci->IsUnicodeMode()) {
CLIPFORMAT formats[] = {CF_UNICODETEXT, CF_TEXT};
pfe = new FormatEnumerator(0, formats, 2);
} else {
CLIPFORMAT formats[] = {CF_TEXT};
pfe = new FormatEnumerator(0, formats, 1);
}
return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
reinterpret_cast<void **>(ppEnum));
}
STDMETHODIMP DataObject_DAdvise(DataObject *, FORMATETC *, DWORD, IAdviseSink *, PDWORD) {
//Platform::DebugPrintf("DOB DAdvise\n");
return E_FAIL;
}
STDMETHODIMP DataObject_DUnadvise(DataObject *, DWORD) {
//Platform::DebugPrintf("DOB DUnadvise\n");
return E_FAIL;
}
STDMETHODIMP DataObject_EnumDAdvise(DataObject *, IEnumSTATDATA **) {
//Platform::DebugPrintf("DOB EnumDAdvise\n");
return E_FAIL;
}
static void *vtDataObject[] = {
(void *)(DataObject_QueryInterface),
(void *)(DataObject_AddRef),
(void *)(DataObject_Release),
(void *)(DataObject_GetData),
(void *)(DataObject_GetDataHere),
(void *)(DataObject_QueryGetData),
(void *)(DataObject_GetCanonicalFormatEtc),
(void *)(DataObject_SetData),
(void *)(DataObject_EnumFormatEtc),
(void *)(DataObject_DAdvise),
(void *)(DataObject_DUnadvise),
(void *)(DataObject_EnumDAdvise)
};
DataObject::DataObject() {
vtbl = vtDataObject;
sci = 0;
}
/// Implement IUnknown
STDMETHODIMP DropTarget_QueryInterface(DropTarget *dt, REFIID riid, PVOID *ppv) {
//Platform::DebugPrintf("DT QI %x\n", dt);
return dt->sci->QueryInterface(riid, ppv);
}
STDMETHODIMP_(ULONG)DropTarget_AddRef(DropTarget *dt) {
return dt->sci->AddRef();
}
STDMETHODIMP_(ULONG)DropTarget_Release(DropTarget *dt) {
return dt->sci->Release();
}
/// Implement IDropTarget by forwarding to Scintilla
STDMETHODIMP DropTarget_DragEnter(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
POINTL pt, PDWORD pdwEffect) {
return dt->sci->DragEnter(pIDataSource, grfKeyState, pt, pdwEffect);
}
STDMETHODIMP DropTarget_DragOver(DropTarget *dt, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
return dt->sci->DragOver(grfKeyState, pt, pdwEffect);
}
STDMETHODIMP DropTarget_DragLeave(DropTarget *dt) {
return dt->sci->DragLeave();
}
STDMETHODIMP DropTarget_Drop(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
POINTL pt, PDWORD pdwEffect) {
return dt->sci->Drop(pIDataSource, grfKeyState, pt, pdwEffect);
}
static void *vtDropTarget[] = {
(void *)(DropTarget_QueryInterface),
(void *)(DropTarget_AddRef),
(void *)(DropTarget_Release),
(void *)(DropTarget_DragEnter),
(void *)(DropTarget_DragOver),
(void *)(DropTarget_DragLeave),
(void *)(DropTarget_Drop)
};
DropTarget::DropTarget() {
vtbl = vtDropTarget;
sci = 0;
}
/**
* DBCS: support Input Method Editor (IME).
* Called when IME Window opened.
*/
void ScintillaWin::ImeStartComposition() {
#ifndef __DMC__
// Digital Mars compiler does not include Imm library
if (caret.active) {
// Move IME Window to current caret position
HIMC hIMC = ::ImmGetContext(MainHWND());
Point pos = LocationFromPosition(currentPos);
COMPOSITIONFORM CompForm;
CompForm.dwStyle = CFS_POINT;
CompForm.ptCurrentPos.x = pos.x;
CompForm.ptCurrentPos.y = pos.y;
::ImmSetCompositionWindow(hIMC, &CompForm);
// Set font of IME window to same as surrounded text.
if (stylesValid) {
// Since the style creation code has been made platform independent,
// The logfont for the IME is recreated here.
int styleHere = (pdoc->StyleAt(currentPos)) & 31;
LOGFONT lf = {0,0,0,0,0,0,0,0,0,0,0,0,0,TEXT("")};
int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel;
if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1
sizeZoomed = 2;
AutoSurface surface(this);
int deviceHeight = sizeZoomed;
if (surface) {
deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72;
}
// The negative is to allow for leading
lf.lfHeight = -(abs(deviceHeight));
lf.lfWeight = vs.styles[styleHere].bold ? FW_BOLD : FW_NORMAL;
lf.lfItalic = static_cast<BYTE>(vs.styles[styleHere].italic ? 1 : 0);
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfFaceName[0] = '\0';
if (vs.styles[styleHere].fontName)
strcpy(lf.lfFaceName, vs.styles[styleHere].fontName);
::ImmSetCompositionFont(hIMC, &lf);
}
::ImmReleaseContext(MainHWND(), hIMC);
// Caret is displayed in IME window. So, caret in Scintilla is useless.
DropCaret();
}
#endif
}
/** Called when IME Window closed. */
void ScintillaWin::ImeEndComposition() {
ShowCaretAtCurrentPosition();
}
void ScintillaWin::AddCharBytes(char b0, char b1) {
int inputCodePage = InputCodePage();
if (inputCodePage && IsUnicodeMode()) {
char utfval[4]="\0\0\0";
char ansiChars[3];
wchar_t wcs[2];
if (b0) { // Two bytes from IME
ansiChars[0] = b0;
ansiChars[1] = b1;
ansiChars[2] = '\0';
::MultiByteToWideChar(inputCodePage, 0, ansiChars, 2, wcs, 1);
} else {
ansiChars[0] = b1;
ansiChars[1] = '\0';
::MultiByteToWideChar(inputCodePage, 0, ansiChars, 1, wcs, 1);
}
unsigned int len = UTF8Length(wcs, 1);
UTF8FromUCS2(wcs, 1, utfval, len);
utfval[len] = '\0';
AddCharUTF(utfval, len ? len : 1);
} else if (b0) {
char dbcsChars[3];
dbcsChars[0] = b0;
dbcsChars[1] = b1;
dbcsChars[2] = '\0';
AddCharUTF(dbcsChars, 2, true);
} else {
AddChar(b1);
}
}
void ScintillaWin::GetIntelliMouseParameters() {
// This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
}
void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {
if (!::OpenClipboard(MainHWND()))
return ;
::EmptyClipboard();
GlobalMemory uniText;
// Default Scintilla behaviour in Unicode mode
if (IsUnicodeMode()) {
int uchars = UCS2Length(selectedText.s, selectedText.len);
uniText.Allocate(2 * uchars);
if (uniText) {
UCS2FromUTF8(selectedText.s, selectedText.len, static_cast<wchar_t *>(uniText.ptr), uchars);
}
} else {
// Not Unicode mode
// Convert to Unicode using the current Scintilla code page
UINT cpSrc = CodePageFromCharSet(
selectedText.characterSet, selectedText.codePage);
uniText.Allocate(2 * selectedText.len);
if (uniText) {
::MultiByteToWideChar(cpSrc, 0, selectedText.s, selectedText.len,
static_cast<wchar_t *>(uniText.ptr), selectedText.len);
}
}
if (uniText) {
if (!IsNT()) {
// Copy ANSI text to clipboard on Windows 9x
// Convert from Unicode text, so other ANSI programs can
// paste the text
// Windows NT, 2k, XP automatically generates CF_TEXT
GlobalMemory ansiText;
ansiText.Allocate(selectedText.len);
if (ansiText) {
::WideCharToMultiByte(CP_ACP, 0, static_cast<wchar_t *>(uniText.ptr), -1,
static_cast<char *>(ansiText.ptr), selectedText.len, NULL, NULL);
ansiText.SetClip(CF_TEXT);
}
}
uniText.SetClip(CF_UNICODETEXT);
} else {
// There was a failure - try to copy at least ANSI text
GlobalMemory ansiText;
ansiText.Allocate(selectedText.len);
if (ansiText) {
memcpy(static_cast<char *>(ansiText.ptr), selectedText.s, selectedText.len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -