iup-stack/iup/srcscintilla/iup_scintilla.c

507 lines
14 KiB
C
Executable File

/*
* IupScintilla component
*
* Description : A source code editing component,
* derived from Scintilla (http://www.scintilla.org/)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <Scintilla.h>
#include <SciLexer.h>
#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");
}