Scintilla开源库使用指南(二)

图片 1

借使您不爱好这几个圆圈,能够用SCI_MA路虎极光KE奥德赛DEFINE命令改变标记的样式,可选的有:

SC_MARK_CIRCLE, SC_MARK_ROUNDRECT, SC_MARK_ARROW, SC_MARK_SMALLRECT,
SC_MARK_SHORTARROW, SC_MARK_EMPTY, SC_MARK_ARROWDOWN, SC_MARK_MINUS,
SC_MARK_PLUS, SC_MARK_VLINE, SC_MARK_LCORNER, SC_MARK_TCORNER, SC_MARK_BOXPLUS,
SC_MARK_BOXPLUSCONNECTED, SC_MARK_BOXMINUS, SC_MARK_BOXMINUSCONNECTED,
SC_MARK_LCORNERCURVE, SC_MARK_TCORNERCURVE, SC_MARK_CIRCLEPLUS,
SC_MARK_CIRCLEPLUSCONNECTED, SC_MARK_CIRCLEMINUS, SC_MARK_CIRCLEMINUSCONNECTED,
SC_MARK_BACKGROUND, SC_MARK_DOTDOTDOT, SC_MARK_ARROWS, SC_MARK_PIXMAP,
SC_MARK_FULLRECT, SC_MARK_LEFTRECT, SC_MARK_CHARACTER

默认是SC_MARK_CI哈弗CLE,小圆圈。你可以试试其余的。(注意SC_MARK_CHARACTEGL450相比较特别,它和3个ASCII码加起来决定标记显示为贰个相应的ASCII字符)

有了这么些基础,咱们可以入手为Scintilla出席代码折叠功效了…

来得效果是:

页边(Margins)和标记(Markers)

代码折叠是现代IDE和代码编辑器的画龙点睛成效,假如前日推出3个不协理折叠的编辑器,那是要被BS地~~。为了不被BS,很有要求先“商量”一下Scintilla的页边(Margins)和符号(马克尔s)功用。


  • 边(Margins)
    :页边是位于文本展现区左侧的一竖条区域,它可以用来显示行号、书签、断点标记等东
    东。Scintilla最多可以有5个页边(从左
    到右的号子为0~4),各个页边能够运用SCI_SETMA奥迪Q5GINTYPEN命令明确是用来体现行号依然符号。大家可以用
    SCI_SETMAPAJEROGINWIDTHN命令控制2个页边的肥瘦,若是设置为0,则意味着不显得该页边。默许是只显示涨幅为16的1号页边。

  • 记(Markers)
    :标记,不用说也精通是用来标记文本地方(确切地说,是文本行)的。大家可以运用
    32种标志(编号0~31),我们可以任意支配那32种标志的意思,如标记0用来表示断点、标记1~10表示书签、标记20表示语法错误行等等。然则,假设编辑器要扶助代码折叠成效,我们得把标记
    25~31留出来,把那八个标志作为代码折叠专用标志(后边还会讲到)。

报告页边显示怎么标记

当页边不是设定为凸显行号时(由SCI_SETMA安德拉GINTYPEN命令设置),那么它就会显得标记。刚才说过Scintilla有32种标志,一般的话不会让1个页边来体现全部的标志,而是只突显部分标记。

在2个页边里可以体现哪三种标记由SCI_SETMA凯雷德GINMASKN命令设置,它的参数是1个30人掩码(mask)值,掩码值的第n位为1时意味着该页边可显示n号标记。

装有页边相关的指令以SCI_SETMARGIN或SCI_GETMA奥德赛GIN作为前缀,如:

  • SCI_SETMASportageGINTYPEN(int margin, int type) 
    设置页边突显行号照旧符号,type可以是SC_MARGIN_SYMBOL或SC_MARGIN_NUMBER
  • SCI_SETMA悍马H2GINWIDTHN(int margin, int pixelWidth)  设置页边宽度
  • SCI_SETMACR-VGINMASKN(int margin, int mask)  设置页边掩码
  • SCI_SETMARubiconGINSENSITIVEN(int margin, bool sensitive) 
    设置页边是不是接受鼠标点击事件

拥有标记相关的授命以SCI_MAEvoqueKEMurano作为前缀,如:

  • SCI_MACRUISERKERADD(int line, int markerNumber) 
    在钦赐行参与3个markerNumber号标记
  • SCI_MA奔驰G级KE奥迪Q5DEFINE(int markerNumber, int markerSymbols) 
    定义markerNumber号标记的体裁
  • SCI_MAHavalKECRUISERDELETE(int line, int markerNumber)
    在内定行上的删除markerNumber号标记
  • SCI_MA奔驰M级KE奔驰M级DELETEALL(int markerNumber)
    删除文本中享有markerNumber号标记
  • SCI_MA奥迪Q5KEPRADOSETFORE(int markerNumber, int colour)
    为markerNumber号标记内定前景观
  • SCI_MA翼虎KE途乐SETBACK(int markerNumber, int colour)
    为markerNumber号标记钦点背景观

?

// 标记和页边演示
void TForm1::example()
{
    // 先写10行文本上去
    for(int i=0; i<10; i++)
        SendEditor(SCI_APPENDTEXT, 12, (sptr_t)"hello world ");
    // 0号页边,宽度为9,显示0号标记(0..0001B)
    SendEditor(SCI_SETMARGINTYPEN,0,SC_MARGIN_SYMBOL);
    SendEditor(SCI_SETMARGINWIDTHN,0, 9);
    SendEditor(SCI_SETMARGINMASKN,0, 0x01);
    // 1号页边,宽度为9,显示1,2号标记(0..0110B)
    SendEditor(SCI_SETMARGINTYPEN,1, SC_MARGIN_SYMBOL);
    SendEditor(SCI_SETMARGINWIDTHN,1, 9);
    SendEditor(SCI_SETMARGINMASKN,1, 0x06);
    // 2号页边,宽度为20,显示行号
    SendEditor(SCI_SETMARGINTYPEN,2, SC_MARGIN_NUMBER);
    SendEditor(SCI_SETMARGINWIDTHN,2, 20);
   
    for(int i=0; i<10; i++)
    {
        // 前10行分别加入0~2号标记
        SendEditor(SCI_MARKERADD, i, i%3);
    }
   
    // 设置标记的前景色
    SendEditor(SCI_MARKERSETFORE,0,0x0000ff);//0-红色
    SendEditor(SCI_MARKERSETFORE,1,0x00ff00);//1-绿色
    SendEditor(SCI_MARKERSETFORE,2,0xff0000);//2-蓝色
}

怎么资助电动缩进

在VS里编写C++代码时,输入回车换行后会保持和上一行的缩进一致,输入”{‘字符后回车还会帮大家多缩进两遍,输入’}’后又能自动退回。大家的编辑器也要贯彻这些意义。

于今再细致询问一下Scintilla的关照信息(http://scintilla.sourceforge.net/ScintillaDoc.html#Notifications),除了后边用到的页边点击事件外,还有为数不少风云格外实惠。

落到实处自动缩进功效我们要关怀的风云通报是SCN_CHARADDEDSCN_UPDATEUI

  • 当用户输入一个字符时,SCN_CHARADDED事件触发,SCNotification的ch成员保存了输入的字符。
  • 当更新文档界面时,SCN_UPDATEUI事件触发。输入字符,改变字体风格,改变选区都会挑起界面更新

示范代码

改写TForm1::WndProc,处理那多个事件,我们的编辑器接济电动缩进啦

?

void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
    TForm::WndProc(Message);
   
    if(Message.Msg == WM_NOTIFY)
    {
        ...
        // 处理自动缩进
        static int LastProcessedChar = 0;
        //在CharAdded事件中记录最后输入的字符
        if(notify->nmhdr.code == SCN_CHARADDED)
        {
            LastProcessedChar = notify->ch;
        }
        // 在UpdateUI事件中处理缩进
        if(notify->nmhdr.code == SCN_UPDATEUI && LastProcessedChar!=0)
        {
            int pos = SendEditor(SCI_GETCURRENTPOS); //取得当前位置
            int line = SendEditor(SCI_LINEFROMPOSITION,pos); //取得当前行
            //如果最后输入的字符是右括号的话就自动让当前行缩进和它匹配的左括号所在行一致
            if( strchr("})>]",LastProcessedChar) &&
                isspace(SendEditor(SCI_GETCHARAT,pos-2)) && //要求右括号左边是空白字符
                LastProcessedChar!=0)
            {
                //找前一个单词起始位置,这里用它来确定右括号左边是否全是空白字符
                int startpos = SendEditor(SCI_WORDSTARTPOSITION,pos-1,false);
                int linepos = SendEditor(SCI_POSITIONFROMLINE,line); //当前行起始位置
                if(startpos == linepos) //这样相当于判断右括号左边是否全是空白字符
                {
                    int othpos = SendEditor(SCI_BRACEMATCH,pos-1); //得到对应的左括号所在的位置
                    int othline = SendEditor(SCI_LINEFROMPOSITION,othpos);  //左括号所在行
                    int nIndent = SendEditor(SCI_GETLINEINDENTATION,othline);//左括号所在行的缩进值
                    // 替换右括号前面的空白字符,使之与左括号缩进一致
                    char space[1024];
                    memset(space,' ',1024);
                    SendEditor(SCI_SETTARGETSTART, startpos);
                    SendEditor(SCI_SETTARGETEND, pos-1);
                    SendEditor(SCI_REPLACETARGET,nIndent,(sptr_t)space);
                }
            }
            // 如果输入的是回车,则保持与上一行缩进一致
            // 如果上一行最后有效字符为左括号,就多缩进四个空格
            if(LastProcessedChar == ' ')
            {
                if(line > 0)
                {
                    // 得到上一行缩进设置
                    int nIndent = SendEditor(SCI_GETLINEINDENTATION,line-1);
                    // 查找上一行最后一个有效字符(非空白字符)
                    int nPrevLinePos = SendEditor(SCI_POSITIONFROMLINE,line-1);
                    int c = ' ';
                    for(int p = pos-2;
                        p>=nPrevLinePos && isspace(c);
                        p--, c=SendEditor(SCI_GETCHARAT,p));
                    // 如果是左括号,就多缩进四格
                    if(c && strchr("{([<",c)) nIndent+=4;
                    // 缩进...
                    char space[1024];
                    memset(space,' ',1024);
                    space[nIndent] = 0;
                    SendEditor(SCI_REPLACESEL, 0, (sptr_t)space);
                }
            }
            LastProcessedChar = 0;
        }
    }
}

辅助粤语

Scintilla暗中认同用的是ANSI编码,所以编辑普通话之类的多字节编码时,会出错半个字符的题目。大家可以采纳SCI_SETCODEPAGE命令设置使用的编码。

为了扶助多语言,指出使用UTF8编码:

  1. // UTF-8编码
  2. SendEditor(SCI_SETCODEPAGE,SC_CP_UTF8);

行使自定义图形

Scintilla自带的记号样式和VS比起来还有差别,反正偶是怎么调都觉着多少土。Scintilla允许大家相濡相呴定义标记的体裁,方法是:

  1. 用SCI_MA奥迪Q7KE奥德赛DEFINE命令设置标记的体裁为SC_MARK_PIXMAP
  2. 用SCI_MAKugaKESportageDEFINEPIXMAP命令设置标记使用的图纸,这里的图纸必要是xpm格式。

何以得到xpm格式图形

xpm在linux系统下用得相比较多,它和BMP、jpg一样也是一种图片格式,有众多工具得以把图纸转换来xpm格式的,比如作者爱好的免费看图软件XnView就可以,想必ACDSee也行吧。

xpm相比较新鲜的地方是它可以当做头文件一向被C语言调用,吃惊吗?用文件编辑器打开它看看,呵呵,其实它就是两个数组定义。

如上边这几个数据(代码)就是后边立刻快要动用的minus.xpm和plus.xpm图片文件的始末(从eclipse里挖出来的):

?

/* XPM */
static const char *minus_xpm[] = {
/* width height num_colors chars_per_pixel */
"     9     9       16            1",
/* colors */
"` c #8c96ac",
". c #c4d0da",
"# c #daecf4",
"a c #ccdeec",
"b c #eceef4",
"c c #e0e5eb",
"d c #a7b7c7",
"e c #e4ecf0",
"f c #d0d8e2",
"g c #b7c5d4",
"h c #fafdfc",
"i c #b4becc",
"j c #d1e6f1",
"k c #e4f2fb",
"l c #ecf6fc",
"m c #d4dfe7",
/* pixels */
"hbc.i.cbh",
"bffeheffb",
"mfllkllfm",
"gjkkkkkji",
"da`````jd",
"ga#j##jai",
"f.k##k#.a",
"#..jkj..#",
"hemgdgc#h"
};

?

/* XPM */
static const char *plus_xpm[] = {
/* width height num_colors chars_per_pixel */
"     9     9       16            1",
/* colors */
"` c #242e44",
". c #8ea0b5",
"# c #b7d5e4",
"a c #dcf2fc",
"b c #a2b8c8",
"c c #ccd2dc",
"d c #b8c6d4",
"e c #f4f4f4",
"f c #accadc",
"g c #798fa4",
"h c #a4b0c0",
"i c #cde5f0",
"j c #bcdeec",
"k c #ecf1f6",
"l c #acbccc",
"m c #fcfefc",
/* pixels */
"mech.hcem",
"eldikille",
"dlaa`akld",
".#ii`ii#.",
"g#`````fg",
".fjj`jjf.",
"lbji`ijbd",
"khb#idlhk",
"mkd.ghdkm"
};

当今,我们的结晶是这么的(与VS有一拼了吧^_^):

图片 2

演示,使用自定义图形:

?

#include "minus.xpm"
#include "plus.xpm"
void TForm1::setFold()
{
    ...
    // 折叠标签样式
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_PIXMAP);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_PIXMAP);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND,  SC_MARK_PIXMAP);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_PIXMAP);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);
   
    //
    SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDER, (sptr_t)plus_xpm);
    SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEROPEN, (sptr_t)minus_xpm);
    SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEREND, (sptr_t)plus_xpm);
    SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEROPENMID, (sptr_t)minus_xpm);
    ...
}

上边是代码中用到的Scintilla命令的简要介绍

  • SCN_CHARADDED事件记录最终输入的字符,在SCN_UPDATEUI事件中处理缩进。
  • 当输入回车时(LastProcessedChar == ‘
    ‘),大家只须要确保新行和前一行的缩进相同就可以了。
  • SCI_GETLINEINDENTATION命令可以拿走指定行的缩进数(即行首的空格数目)。
  • SCI_REPLACESEL命令用钦定字符串替换选取区域
  • SCI_GETCU奥迪Q5RENTPOS命令取得当前义务
  • SCI_GETCHARAT命令取得钦点地点的字符
  • SCI_LINEFROMPOSITION命令取得内定地方所在的行号
  • SCI_POSITIONFROMLINE命令取得钦命行号的苗子地点
  • SCI_WO哈弗DSTAHighlanderTPOSITION命令取得钦命地点所在单词的序幕地方,如xxx|xx,(|代表钦定地点),那么它会回来|xxxxx的地点。同样还有SCI_WORDENDPOSITION命令。
  • SCI_BRACEMATCH取得括号的另1/2任务,如钦赐地点的字符是’}’时,它回到匹配的'{‘所在的地点。
  • SCI_SETTARGETSTART和SCI_SETTA哈弗GETEND设置TA本田UR-VGET的苗头和始止地方,SCI_REPLACETA景逸SUVGET命令用内定字符串替换TA汉兰达GET钦点范围内的字符。

VS的代码完结和函数指示作用是很值得夸奖的,它们得以极大地升高大家的编程功能(造成本人现在写代码时一再只记住前七个假名,假诺在对象前面点了小数点后不出新提醒就会胸中无数的说-_-),尽管有时也会失灵。

做为IDE这么些职能是相对无法少D。尽管你只打算做个编辑器,假诺有其一效果那也是一大优点啊~~(近来不可胜数代码编辑器都没那个作用的说)。

关于函数提醒的几个指令以SCI_CALLTIP作为前缀,那里只介绍我们就要使用的多少个指令(越来越多命令见:http://scintilla.sourceforge.net/ScintillaDoc.html#CallTips

  • SCI_CALLTIPSHOW(int posStart, const char *definition)
    显示提醒。posStart表示突显地点,definition是显示的内容
  • SCI_CALLTIPCANCEL 裁撤提醒
  • SCI_CALLTIPACTIVE 假诺当前编辑器中有提醒消息,再次来到1,否则重返0
  • SCI_CALLTIPSETHLT(int highlightStart, int highlightEnd)
    设置提示中的高亮地方,在VS里大家输入函数实参时函数提醒会高亮当前输入的参数名。

在咱们先后中投入指示的最佳时机是SCN_CHARADDED(见上一节)事件。当用户输入左圆括号'(‘时,取得括号左侧的函数名,然后突显出该函数的共同体定义。

上边的代码已毕了CreateWindow和MoveWindow多个API的函数提醒

?

//我们要高亮的两个函数
const size_t FUNCSIZE=2;
char* g_szFuncList[FUNCSIZE]={ //函数名
    "CreateWindow(",
    "MoveWindow("
};
char* g_szFuncDesc[FUNCSIZE]={ //函数信息
    "HWND CreateWindow("
    "LPCTSTR lpClassName,"
    " LPCTSTR lpWindowName,"
    " DWORD dwStyle, "
    " int x,"
    " int y,"
    " int nWidth,"
    " int nHeight, "
    " HWND hWndParent,"
    " HMENU hMenu,"
    " HANDLE hInstance,"
    " PVOID lpParam"
    ")",
    "BOOL MoveWindow("
    "HWND hWnd,"
    " int X,"
    " int Y,"
    " int nWidth,"
    " int nHeight,"
    " BOOL bRepaint"
    ")"
};
void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
    TForm::WndProc(Message);
    if(Message.Msg == WM_NOTIFY)
    {
        SCNotification* notify = (SCNotification*)Message.LParam;
        ...
        if(notify->nmhdr.code == SCN_CHARADDED)
        {
            ...
            // 函数提示功能
            static const char* pCallTipNextWord = NULL;//下一个高亮位置
            static const char* pCallTipCurDesc = NULL;//当前提示的函数信息
            if(notify->ch == '(') //如果输入了左括号,显示函数提示
            {
                char word[1000]; //保存当前光标下的单词(函数名)
                TextRange tr;    //用于SCI_GETTEXTRANGE命令
                int pos = SendEditor(SCI_GETCURRENTPOS); //取得当前位置(括号的位置)
                int startpos = SendEditor(SCI_WORDSTARTPOSITION,pos-1);//当前单词起始位置
                int endpos = SendEditor(SCI_WORDENDPOSITION,pos-1);//当前单词终止位置
                tr.chrg.cpMin = startpos;  //设定单词区间,取出单词
                tr.chrg.cpMax = endpos;
                tr.lpstrText = word;
                SendEditor(SCI_GETTEXTRANGE,0, sptr_t(&tr));
                  
                for(size_t i=0; i<FUNCSIZE; i++) //找找有没有我们认识的函数?
                {
                    if(memcmp(g_szFuncList[i],word,sizeof(g_szFuncList[i])) == 0)
                    {     //找到啦,那么显示提示吧
                        pCallTipCurDesc = g_szFuncDesc[i]; //当前提示的函数信息
                        SendEditor(SCI_CALLTIPSHOW,pos,sptr_t(pCallTipCurDesc));//显示这个提示
                        const char *pStart = strchr(pCallTipCurDesc,'(')+1; //高亮第一个参数
                        const char *pEnd = strchr(pStart,',');//参数列表以逗号分隔
                        if(pEnd == NULL) pEnd = strchr(pStart,')');//若是最后一个参数,后面是右括号
                        SendEditor(SCI_CALLTIPSETHLT,
                            pStart-pCallTipCurDesc, pEnd-pCallTipCurDesc);
                        pCallTipNextWord = pEnd+1;//指向下一参数位置
                        break;
                    }
                }
            }
            else if(notify->ch == ')') //如果输入右括号,就关闭函数提示
            {
                SendEditor(SCI_CALLTIPCANCEL);
                pCallTipCurDesc = NULL;
                pCallTipNextWord = NULL;                
            }
            else if(notify->ch == ',' && SendEditor(SCI_CALLTIPACTIVE) && pCallTipCurDesc)
            {
                //输入的是逗号,高亮下一个参数
                const char *pStart = pCallTipNextWord;
                const char *pEnd = strchr(pStart,',');
                if(pEnd == NULL) pEnd = strchr(pStart,')');
                if(pEnd == NULL) //没有下一个参数啦,关闭提示
                    SendEditor(SCI_CALLTIPCANCEL);
                else
                {
                    SendEditor(SCI_CALLTIPSETHLT,pStart-pCallTipCurDesc, pEnd-pCallTipCurDesc);
                    pCallTipNextWord = pEnd+1;
                }
            }
        }//if(notify->nmhdr.code == SCN_CHARADDED)
        ...
    }//if(Message.Msg == WM_NOTIFY)
}

图片 3

自然,这些提醒效果卓殊山寨啦。比如函数名和括号之间有空格提醒就不出来了,函数嵌套调用时只会唤醒最终贰个函数的参数。关于即使改良,大家各显神通吧。

其余,还有二个提外话,在实际的应用中,大家的函数新闻不容许象那里一样是写死的,而是基于用户的输入动态变化的函数名及音信列表。那就事关到3个C++代码解析的题材(幸好,只要解析函数讲明就行了),对于这或多或少,牛X的校友可以协调写解析代码;次牛X的可以考虑用WAVE,Spirit,Regex等库接济解析;象偶那种不牛的同窗,则能够设想动用CTAGS工具在后台线程中生成tag文件,大家从tag文件里取就足以了(当然,作用嘛~~可以参照C++Builder的函数指示效能-_-)。

代码完结和函数指示的用法类似,前缀是SCI_AUTOC,具体命令见:http://scintilla.sourceforge.net/ScintillaDoc.html\#Autocompletion

?

void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
    TForm::WndProc(Message);
    if(Message.Msg == WM_NOTIFY)
    {
        ...
        if(notify->nmhdr.code == SCN_CHARADDED)
        {
            ...
            if(notify->ch == '.')
            {
                char word[1000]; //保存当前光标下的单词
                TextRange tr;    //用于SCI_GETTEXTRANGE命令
                int pos = SendEditor(SCI_GETCURRENTPOS); //取得当前位置
                int startpos = SendEditor(SCI_WORDSTARTPOSITION,pos-1);//当前单词起始位置
                int endpos = SendEditor(SCI_WORDENDPOSITION,pos-1);//当前单词终止位置
                tr.chrg.cpMin = startpos;  //设定单词区间,取出单词
                tr.chrg.cpMax = endpos;
                tr.lpstrText = word;
                SendEditor(SCI_GETTEXTRANGE,0, sptr_t(&tr));
                if(strcmp(word,"file.") == 0) //输入file.后提示file对象的几个方法
                {
                    SendEditor(SCI_AUTOCSHOW,0,
                        sptr_t(
                            "close "
                            "eof "
                            "good "
                            "open "
                            "rdbuf "
                            "size"
                        ));
                }
            }
            ...

图片 4

SCI_AUTOCSHOW命令的率先个参数表示曾经输入了略微个字符。这对于代码自动完结是很有扶持的,比如我们可以用它扶助用户输入长串的单词,如:

?

if(strcmp(word,"Create") == 0)
{
    SendEditor(SCI_AUTOCSHOW,6,//已经输入了6位字符
        sptr_t(
            "CreateBitmap "
            "CreateDC "
            "CreateHandle "
            "CreateWindow "
            "CreateWindowEx"
        ));
}

http://www.cnblogs.com/superanyi/archive/2011/04/07/2008636.html

为Scintilla参与代码折叠效能

前方曾说过当编辑器有代码折叠作用时,25号到31号那8个标志是作为代码折叠专用标志的。在scintilla.h中,我们可以找到它们的概念:

#define SC_MARKNUM_FOLDEREND 25  //折叠状态(多级中间)
#define SC_MARKNUM_FOLDEROPENMID 26  //展开状态(多级中间)
#define SC_MARKNUM_FOLDERMIDTAIL 27  //被折叠代码块尾部(多级中间)
#define SC_MARKNUM_FOLDERTAIL 28  //被折叠代码块尾部
#define SC_MARKNUM_FOLDERSUB 29   //被折叠的代码块
#define SC_MARKNUM_FOLDER 30     //折叠状态
#define SC_MARKNUM_FOLDEROPEN 31 //展开状态
显示这些标记的掩码是0xFE000000,同样头文件里已经定义好了

#define SC_MASK_FOLDERS 0xFE000000

要加入代码折叠功能,还有一个最最关键的事情,就是要得到语法解析器(Lexer)的支持,上面的这些标记都是由语法解析器自动添加删除的。一般来说,只要用下面这条命令就可以了让语法解析器支持代码折叠了:

SendEditor(SCI_SETPROPERTY,(sptr_t)"fold",(sptr_t)"1");

?

#define MARGIN_FOLD_INDEX 2
void TForm1::setFold()
{
    SendEditor(SCI_SETPROPERTY,(sptr_t)"fold",(sptr_t)"1");
   
    SendEditor(SCI_SETMARGINTYPEN, MARGIN_FOLD_INDEX, SC_MARGIN_SYMBOL);//页边类型
    SendEditor(SCI_SETMARGINMASKN, MARGIN_FOLD_INDEX, SC_MASK_FOLDERS); //页边掩码
    SendEditor(SCI_SETMARGINWIDTHN, MARGIN_FOLD_INDEX, 11); //页边宽度
    SendEditor(SCI_SETMARGINSENSITIVEN, MARGIN_FOLD_INDEX, TRUE); //响应鼠标消息
   
    // 折叠标签样式
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_CIRCLEPLUS); 
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_CIRCLEMINUS); 
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND,  SC_MARK_CIRCLEPLUSCONNECTED);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_CIRCLEMINUSCONNECTED);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE);
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); 
    SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE);
   
    // 折叠标签颜色
    SendEditor(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERSUB, 0xa0a0a0);
    SendEditor(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERMIDTAIL, 0xa0a0a0);
    SendEditor(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERTAIL, 0xa0a0a0);
   
    SendEditor(SCI_SETFOLDFLAGS, 16|4, 0); //如果折叠就在折叠行的上下各画一条横线
}
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    ...
    setFold();
}
void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
    TForm::WndProc(Message);
   
    if(Message.Msg == WM_NOTIFY){
        SCNotification* notify = (SCNotification*)Message.LParam;
        if(notify->nmhdr.code == SCN_MARGINCLICK &&
            notify->nmhdr.idFrom == SCINT_ID){
            // 确定是页边点击事件
            const int line_number = SendEditor(SCI_LINEFROMPOSITION,notify->position);
            SendEditor(SCI_TOGGLEFOLD, line_number);
        }
    }
}

图片 5

那边TForm1::WndProc方法是Scintilla父窗体即我们的TForm1的窗口处理函数。

代码折叠以往咱们要通过点击页边上的+和-标记来打开和折叠代码,所以要求页边接收鼠标点击事件:

那边TForm1::WndProc方法是Scintilla父窗体即大家的TForm1的窗口处理函数。

代码折叠以往我们要经过点击页边上的+和-标记来开辟和折叠代码,所以须要页边接收鼠标点击事件:

SendEditor(SCI_SETMARGINSENSITIVEN, MARGIN_FOLD_INDEX, TRUE); //响应鼠标消息

那般,当有鼠标点击该页边后,Scintilla就会向它的父窗体发送代码为SCN_MARGINCLICK的WM_NOTIFY消息,其中的LParam为SCNotification*项目。关于SCNotification的详细新闻请参考这里。SCNotification的position成员提出了点击地方对应的行号,最终大家用SCI_TOGGLEFOLD命令折叠或举行代码。

Scintilla开源库使用指南(二)

上一篇小说介绍了Scintilla的中央拔取,那里继续攻读Scintilla越多的决定命令和贯彻细节,完善我们的编辑器;