/* * IupScintilla component * * Description : A source code editing component, * derived from Scintilla (http://www.scintilla.org/) */ #include #include #include #include #include #include #include "iup.h" #include "iup_scintilla.h" #include "iupcbs.h" #include "iup_key.h" #include "iup_class.h" #include "iup_object.h" #include "iup_attrib.h" #include "iup_str.h" #include "iup_drv.h" #include "iup_drvfont.h" #include "iup_register.h" #include "iup_layout.h" #include "iup_assert.h" #include "iupsci.h" /***** AUXILIARY FUNCTIONS *****/ long iupScintillaEncodeColor(unsigned char r, unsigned char g, unsigned char b) { return (((unsigned long)r) << 0) | (((unsigned long)g) << 8) | (((unsigned long)b) << 16); } void iupScintillaDecodeColor(long color, unsigned char *r, unsigned char *g, unsigned char *b) { *r = (unsigned char)(((color) >> 0) & 0xFF); *g = (unsigned char)(((color) >> 8) & 0xFF); *b = (unsigned char)(((color) >> 16) & 0xFF); } void iupScintillaConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) { *pos = (int)IupScintillaSendMessage(ih, SCI_POSITIONFROMLINE, lin, 0); if(*pos != -1) { /* length of the line not including any end of line characters */ int line_length = (int)IupScintillaSendMessage(ih, SCI_GETLINEENDPOSITION, lin, 0) - (int)IupScintillaSendMessage(ih, SCI_POSITIONFROMLINE, lin, 0); if (col <= line_length) *pos += col; else *pos += line_length; } else { /* "lin" is greater than the lines in the document */ lin = (int)IupScintillaSendMessage(ih, SCI_GETLINECOUNT, 0, 0); *pos = (int)IupScintillaSendMessage(ih, SCI_POSITIONFROMLINE, lin, 0); } } void iupScintillaConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) { *lin = (int)IupScintillaSendMessage(ih, SCI_LINEFROMPOSITION, pos, 0); *col = (int)IupScintillaSendMessage(ih, SCI_GETCOLUMN, pos, 0); } static int iScintillaConvertXYToPos(Ihandle* ih, int x, int y) { return (int)IupScintillaSendMessage(ih, SCI_POSITIONFROMPOINTCLOSE, x, y); } /***** AUXILIARY ATTRIBUTES *****/ static int iScintillaSetUsePopupAttrib(Ihandle* ih, const char* value) { IupScintillaSendMessage(ih, SCI_USEPOPUP, iupStrBoolean(value), 0); return 1; /* there is no get */ } /***** NOTIFICATIONS *****/ static void iScintillaKeySetStatus(int state, char* status, int doubleclick) { if (state & SCMOD_SHIFT) iupKEY_SETSHIFT(status); if (state & SCMOD_CTRL) iupKEY_SETCONTROL(status); iupKEY_SETBUTTON1(status); if (state & SCMOD_ALT) iupKEY_SETALT(status); if (state & SCMOD_META) /* Apple/Win */ iupKEY_SETSYS(status); if (doubleclick) iupKEY_SETDOUBLE(status); } void iupScintillaNotify(Ihandle *ih, SCNotification* pMsg) { int lin = (int)IupScintillaSendMessage(ih, SCI_LINEFROMPOSITION, pMsg->position, 0); int col = (int)IupScintillaSendMessage(ih, SCI_GETCOLUMN, pMsg->position, 0); switch(pMsg->nmhdr.code) { case SCN_DWELLSTART: case SCN_DWELLEND: { IFniiii cb = (IFniiii)IupGetCallback(ih, "DWELL_CB"); if (cb) cb(ih, pMsg->nmhdr.code == SCN_DWELLSTART ? 1 : 0, pMsg->position, pMsg->x, pMsg->y); break; } case SCN_SAVEPOINTREACHED: case SCN_SAVEPOINTLEFT: { IFni cb = (IFni)IupGetCallback(ih, "SAVEPOINT_CB"); if (cb) cb(ih, pMsg->nmhdr.code==SCN_SAVEPOINTREACHED? 1: 0); break; } case SCN_MARGINCLICK: { IFniis cb = (IFniis)IupGetCallback(ih, "MARGINCLICK_CB"); if (cb) { char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; iScintillaKeySetStatus(pMsg->modifiers, status, 0); cb(ih, pMsg->margin, lin, status); } break; } case SCN_HOTSPOTDOUBLECLICK: case SCN_HOTSPOTCLICK: { IFniiis cb = (IFniiis)IupGetCallback(ih, "HOTSPOTCLICK_CB"); if (cb) { char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; iScintillaKeySetStatus(pMsg->modifiers, status, pMsg->nmhdr.code==SCN_HOTSPOTDOUBLECLICK? 1: 0); cb(ih, pMsg->position, lin, col, status); } break; } case SCN_ZOOM: { IFni cb = (IFni)IupGetCallback(ih, "ZOOM_CB"); if (cb) { int points = (int)IupScintillaSendMessage(ih, SCI_GETZOOM, 0, 0); cb(ih, points); } break; } case SCN_MODIFIED: if (ih->data->ignore_change) { iupdrvScintillaRefreshCaret(ih); break; } if (pMsg->modificationType&SC_MOD_INSERTCHECK) { IFniis cb = (IFniis)IupGetCallback(ih, "INSERTCHECK_CB"); if (cb) cb(ih, pMsg->position, pMsg->length, (char*)pMsg->text); } if (pMsg->modificationType&SC_PERFORMED_USER || pMsg->modificationType&SC_PERFORMED_UNDO || pMsg->modificationType&SC_PERFORMED_REDO) { if (pMsg->modificationType&SC_MOD_BEFOREINSERT || pMsg->modificationType&SC_MOD_BEFOREDELETE) { IFniiis cb = (IFniiis)IupGetCallback(ih, "ACTION"); if (cb) { int insert = 1; if (pMsg->modificationType&SC_MOD_BEFOREDELETE) insert = 0; cb(ih, insert, pMsg->position, pMsg->length, (char*)pMsg->text); } iupdrvScintillaRefreshCaret(ih); } if (pMsg->modificationType&SC_MOD_INSERTTEXT || pMsg->modificationType&SC_MOD_DELETETEXT) { IFn value_cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); if (value_cb) value_cb(ih); iupdrvScintillaRefreshCaret(ih); if (pMsg->linesAdded != 0) { IFnii cb = (IFnii)IupGetCallback(ih, "LINESCHANGED_CB"); if (cb) cb(ih, lin, pMsg->linesAdded); } } } break; case SCN_AUTOCSELECTION: { IFnis cb = (IFnis)IupGetCallback(ih, "AUTOCSELECTION_CB"); if (cb) cb(ih, pMsg->position, (char*)pMsg->text); break; } case SCN_AUTOCCANCELLED: { IFn cb = (IFn)IupGetCallback(ih, "AUTOCCANCELLED_CB"); if (cb) cb(ih); break; } case SCN_AUTOCCHARDELETED: { IFn cb = (IFn)IupGetCallback(ih, "AUTOCCHARDELETED_CB"); if (cb) cb(ih); break; } case SCN_UPDATEUI: { if (pMsg->updated & SC_UPDATE_CONTENT) { IFn cb = (IFn)IupGetCallback(ih, "UPDATECONTENT_CB"); if (cb) cb(ih); } if (pMsg->updated & SC_UPDATE_SELECTION) { IFn cb = (IFn)IupGetCallback(ih, "UPDATESELECTION_CB"); if (cb) cb(ih); } if (pMsg->updated & SC_UPDATE_V_SCROLL) { IFn cb = (IFn)IupGetCallback(ih, "UPDATEVSCROLL_CB"); if (cb) cb(ih); } if (pMsg->updated & SC_UPDATE_H_SCROLL) { IFn cb = (IFn)IupGetCallback(ih, "UPDATEHSCROLL_CB"); if (cb) cb(ih); } break; } } } void iupScintillaCallCaretCb(Ihandle* ih) { int pos; IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); if (!cb) return; pos = (int)IupScintillaSendMessage(ih, SCI_GETCURRENTPOS, 0, 0); if (pos != ih->data->last_caret_pos) { int col, lin; iupScintillaConvertPosToLinCol(ih, pos, &lin, &col); ih->data->last_caret_pos = pos; cb(ih, lin, col, pos); } } /*****************************************************************************/ static int iScintillaMapMethod(Ihandle* ih) { if (idrvScintillaMap(ih) == IUP_ERROR) return IUP_ERROR; /* configure for DROP of files */ if (IupGetCallback(ih, "DROPFILES_CB")) iupAttribSet(ih, "DROPFILESTARGET", "YES"); /* add scrollbar */ if (ih->data->sb & IUP_SB_HORIZ) IupScintillaSendMessage(ih, SCI_SETHSCROLLBAR, 1, 0); else IupScintillaSendMessage(ih, SCI_SETHSCROLLBAR, 0, 0); if (ih->data->sb & IUP_SB_VERT) IupScintillaSendMessage(ih, SCI_SETVSCROLLBAR, 1, 0); else IupScintillaSendMessage(ih, SCI_SETVSCROLLBAR, 0, 0); IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)iScintillaConvertXYToPos); IupSetCallback(ih, "_IUP_POS2LINCOL_CB", (Icallback)iupScintillaConvertPosToLinCol); IupSetCallback(ih, "_IUP_LINCOL2POS_CB", (Icallback)iupScintillaConvertLinColToPos); /* change default behavior */ IupScintillaSendMessage(ih, SCI_SETPASTECONVERTENDINGS, 1, 0); IupScintillaSendMessage(ih, SCI_SETEOLMODE, SC_EOL_LF, 0); IupScintillaSendMessage(ih, SCI_SETWHITESPACESIZE, 3, 0); IupScintillaSendMessage(ih, SCI_SETMARGINWIDTHN, 1, 0); if(IupGetInt(NULL, "UTF8MODE")) IupScintillaSendMessage(ih, SCI_SETCODEPAGE, SC_CP_UTF8, 0); else IupScintillaSendMessage(ih, SCI_SETCODEPAGE, 0, 0); return IUP_NOERROR; } static void iScintillaComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *children_expand) { int natural_w = 0, natural_h = 0, visiblecolumns = iupAttribGetInt(ih, "VISIBLECOLUMNS"), visiblelines = iupAttribGetInt(ih, "VISIBLELINES"); (void)children_expand; /* unset if not a container */ iupdrvFontGetCharSize(ih, NULL, &natural_h); /* one line height */ natural_w = iupdrvFontGetStringWidth(ih, "WWWWWWWWWW"); natural_w = (visiblecolumns*natural_w)/10; natural_h = visiblelines*natural_h; /* compute the borders space */ if (iupAttribGetBoolean(ih, "BORDER")) { int border_size = iupdrvScintillaGetBorder(); natural_w += border_size; natural_h += border_size; } /* compute scrollbar */ if (ih->data->sb != IUP_SB_NONE) { int sb_size = iupdrvGetScrollbarSize(); if (ih->data->sb & IUP_SB_HORIZ) natural_h += sb_size; /* sb horizontal affects vertical size */ if (ih->data->sb & IUP_SB_VERT) natural_w += sb_size; /* sb vertical affects horizontal size */ } *w = natural_w; *h = natural_h; } static int iScintillaCreateMethod(Ihandle* ih, void **params) { (void)params; ih->data = iupALLOCCTRLDATA(); ih->data->sb = IUP_SB_HORIZ | IUP_SB_VERT; ih->data->append_newline = 1; iupAttribSet(ih, "_IUP_MULTILINE_TEXT", "1"); /* unused for now */ ih->data->useBraceHLIndicator = 1; ih->data->useBraceBLIndicator = 1; return IUP_NOERROR; } static Iclass* iupScintillaNewClass(void) { Iclass* ic = iupClassNew(NULL); ic->name = (char*)"scintilla"; ic->format = NULL; /* no parameters */ ic->nativetype = IUP_TYPECONTROL; ic->childtype = IUP_CHILDNONE; ic->is_interactive = 1; ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */ /* Class functions */ ic->New = iupScintillaNewClass; ic->Release = iupdrvScintillaReleaseMethod; ic->Create = iScintillaCreateMethod; ic->Map = iScintillaMapMethod; ic->UnMap = iupdrvBaseUnMapMethod; ic->ComputeNaturalSize = iScintillaComputeNaturalSizeMethod; ic->LayoutUpdate = iupdrvBaseLayoutUpdateMethod; /* Callbacks */ iupClassRegisterCallback(ic, "DWELL_CB", "iiii"); iupClassRegisterCallback(ic, "SAVEPOINT_CB", "i"); iupClassRegisterCallback(ic, "MARGINCLICK_CB", "iis"); iupClassRegisterCallback(ic, "HOTSPOTCLICK_CB", "iiis"); iupClassRegisterCallback(ic, "BUTTON_CB", "iiiis"); iupClassRegisterCallback(ic, "MOTION_CB", "iis"); iupClassRegisterCallback(ic, "CARET_CB", "iii"); iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); iupClassRegisterCallback(ic, "ACTION", "iiis"); iupClassRegisterCallback(ic, "INSERTCHECK_CB", "iis"); iupClassRegisterCallback(ic, "ZOOM_CB", "i"); iupClassRegisterCallback(ic, "AUTOCSELECTION_CB", "is"); iupClassRegisterCallback(ic, "AUTOCCANCELLED_CB", ""); iupClassRegisterCallback(ic, "AUTOCCHARDELETED_CB", ""); iupClassRegisterCallback(ic, "UPDATECONTENT_CB", ""); iupClassRegisterCallback(ic, "UPDATESELECTION_CB", ""); iupClassRegisterCallback(ic, "UPDATEVSCROLL_CB", ""); iupClassRegisterCallback(ic, "UPDATEHSCROLL_CB", ""); iupClassRegisterCallback(ic, "LINESCHANGED_CB", "ii"); /* Common Callbacks */ iupBaseRegisterCommonCallbacks(ic); /* Common */ iupBaseRegisterCommonAttrib(ic); /* Visual */ iupBaseRegisterVisualAttrib(ic); /* Drag&Drop */ iupdrvRegisterDragDropAttrib(ic); iupScintillaRegisterText(ic); /* Text retrieval and modification */ iupScintillaRegisterSelection(ic); /* Selection and information */ iupScintillaRegisterClipboard(ic); /* Clipboard: Cut, Copy, Paste, Undo and Redo */ iupScintillaRegisterOvertype(ic); /* Overtype */ iupScintillaRegisterTab(ic); /* Tabs and Indentation Guides */ iupScintillaRegisterWordWrap(ic); /* Line wrapping */ iupScintillaRegisterStyle(ic); /* Style Definition Attributes */ iupScintillaRegisterLexer(ic); /* Lexer Attributes */ iupScintillaRegisterFolding(ic); /* Folding Attributes */ iupScintillaRegisterMargin(ic); /* Margin Attributes */ iupScintillaRegisterMarker(ic); /* Marker Attributes */ iupScintillaRegisterWhiteSpace(ic); /* White space Attributes */ iupScintillaRegisterBraceLight(ic); /* Brace highlighting Attributes */ iupScintillaRegisterCursor(ic); /* Cursor and Zooming Attributes */ iupScintillaRegisterAnnotation(ic); /* Annotation Attributes */ iupScintillaRegisterScrolling(ic); /* Scrolling and automatic scrolling */ iupScintillaRegisterAutocompletion(ic); /* Autocompletion */ iupScintillaRegisterSearching(ic); /* Search & Replace */ iupScintillaRegisterPrint(ic); /* Printing */ iupScintillaRegisterIndicators(ic); /* Indicators */ /* General */ iupClassRegisterAttribute(ic, "VISIBLECOLUMNS", NULL, NULL, IUPAF_SAMEASSYSTEM, "30", IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "VISIBLELINES", NULL, NULL, IUPAF_SAMEASSYSTEM, "10", IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "BORDER", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "MULTILINE", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_READONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "USEPOPUP", NULL, iScintillaSetUsePopupAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_WRITEONLY|IUPAF_NO_INHERIT); IupSetGlobal("SCINTILLA_VERSION", SCINTILLA_VERSION); return ic; } Iclass* iupScintillaDlgNewClass(void); void IupScintillaOpen(void) { if (!IupIsOpened()) return; if (!IupGetGlobal("_IUP_SCINTILLA_OPEN")) { iupRegisterClass(iupScintillaNewClass()); iupRegisterClass(iupScintillaDlgNewClass()); IupSetGlobal("_IUP_SCINTILLA_OPEN", "1"); iupdrvScintillaOpen(); } } Ihandle *IupScintilla(void) { return IupCreate("scintilla"); }