📄 textedit.c
字号:
}
if (pLine[ln_chars-1] == txtdoc->lnsep) {
// add caret before line seperator
ln_chars --;
if (ln_chars > 0 && is_rn_sep((pLine + ln_chars - 1)) )
ln_chars --;
}
if (x - indent <= 0) {
out_chars = 0;
txtsize.cx = 0;
}
else
out_chars = GetTabbedTextExtentPoint (hdc, pLine, ln_chars,
x - indent, NULL, NULL, NULL, &txtsize);
ReleaseDC (hdc);
#if 0
printf ("pLine : %s\n", pLine);
printf ("lnchars : %d\n", ln_chars);
printf ("out chars : %d\n", out_chars);
printf ("caret x = %d\n", x);
printf ("txtsize.cx = %d\n", txtsize.cx);
printf ("h = %d\n", h);
#endif
if (!bSel) {
txtdoc->insert.pos_lnOff = pLine - string + out_chars;
mySetCaretPos (hWnd, txtsize.cx + indent, h + ptedata->nLineAboveH);
}
#ifdef _SELECT_SUPPORT
else {
txtdoc->selection.pos_lnOff = pLine - string + out_chars;
mySetSelPos (txtsize.cx + indent, h + ptedata->nLineAboveH);
}
#endif
//scrolled_make_pos_visible (hWnd, ptescr, txtsize.cx + indent, h + ptedata->nLineHeight);
return 0;
}
/* calculates line number of a text node, for wrap mode */
static int get_line_nr (HWND hWnd, PTEDATA ptedata, TextNode *node, int indent)
{
RECT rc;
PLOGFONT logfont = GetWindowFont(hWnd);
HDC hdc;
if (!node) {
fprintf (stderr, "Warning: pass NULL text node to get_line_nr\n");
return 0;
}
if (!BE_WRAP(hWnd))
return 1;
hdc = GetClientDC (hWnd);
SelectFont (hdc, logfont);
rc.left = 0;
rc.top = 0;
rc.right = scrolled_get_contwidth(ptescr);
rc.bottom = logfont->size;
if (ptedata->lnChar) {
char *content, chln = 0;
int outlen;
content = node->content.string;
outlen = node->content.txtlen;
if (outlen > 0 && content[outlen-1] == ptedata->txtdoc.lnsep) {
outlen --;
if (ptedata->txtdoc.lnsep == '\n' && content[outlen-1] == '\r')
outlen --;
outlen ++;
chln = content[outlen-1];
content[outlen-1] = ptedata->lnChar;
}
DrawTextEx (hdc, content, outlen, &rc, indent,
TE_FORMAT | DT_WORDBREAK | DT_CALCRECT);
if (chln)
content[outlen-1] = chln;
}
else {
DrawTextEx (hdc, node->content.string, node->content.txtlen, &rc, indent,
TE_FORMAT | DT_WORDBREAK | DT_CALCRECT);
}
ReleaseDC (hdc);
return (RECTH(rc)/logfont->size);
}
//TODO
static int recalc_max_len (HWND hWnd ,PTEDATA ptedata)
{
list_t *me;
TextDoc *txtdoc = &ptedata->txtdoc;
SIZE txtsize;
TextNode *node;
HDC hdc;
ptedata->maxLen = 0;
ptedata->maxNode = NULL;
ptedata->secLen = 0;
ptedata->secNode = NULL;
hdc = GetClientDC (hWnd);
//SelectFont (hdc, GetWindowFont(hWnd));
list_for_each (me, &txtdoc->queue) {
node = list_entry (me, TextNode, list);
GetTabbedTextExtent(hdc, node->content.string,
node->content.txtlen, &txtsize);
if (txtsize.cx > ptedata->maxLen || ptedata->maxLen == 0) {
ptedata->maxLen = txtsize.cx;
ptedata->maxNode = node;
}
else if (txtsize.cx >= ptedata->secLen) {
ptedata->secLen = txtsize.cx;
ptedata->secNode = node;
}
}
ReleaseDC (hdc);
return 0;
}
static int
revise_max_len (HWND hWnd, PTEDATA ptedata, TextNode *node, int textlen)
{
if (textlen > ptedata->maxLen) {
if (node != ptedata->maxNode) {
ptedata->secLen = ptedata->maxLen;
ptedata->secNode = ptedata->maxNode;
}
ptedata->maxLen = textlen;
ptedata->maxNode = node;
}
else if (textlen > ptedata->secLen) {
if (node != ptedata->maxNode) {
ptedata->secLen = textlen;
ptedata->secNode = node;
return 0; /* no need to reset content width */
}
else {
ptedata->maxLen = textlen;
}
}
else { //FIXME
if (node == ptedata->maxNode) {
recalc_max_len (hWnd, ptedata);
return 1;
}
else if (node == ptedata->secNode) {
recalc_max_len (hWnd, ptedata);
return 0;
}
return 0;
}
/* need to reset content width */
return 1;
}
/* set text node line width, for non wrap mode */
static int set_line_width (HWND hWnd, PTEDATA ptedata, TextNode *node, int indent)
{
SIZE txtsize;
HDC hdc;
if (!node) {
fprintf (stderr, "Warning: pass NULL text node to set_line_width\n");
return -1;
}
if (BE_WRAP(hWnd))
return -1;
hdc = GetClientDC (hWnd);
SelectFont (hdc, GetWindowFont(hWnd));
GetTabbedTextExtent(hdc, node->content.string, node->content.txtlen, &txtsize);
ReleaseDC (hdc);
if (revise_max_len (hWnd, ptedata, node, txtsize.cx + indent) > 0)
scrolled_set_cont_width (hWnd, ptescr, ptedata->maxLen + 1);
return 0;
}
/*
static int set_line_size (HWND hWnd, PTEDATA ptedata, TextNode *node)
{
int linenr = 1, indent;
if (!node)
return 0;
indent = teGetLineIndent (ptedata, node);
linenr = get_line_nr(hWnd, ptedata, node, indent);
set_line_width (hWnd, ptedata, node, indent);
return scrollview_set_item_height (hWnd, (HSVITEM)node->addData,
ptedata->nLineHeight*linenr);
}
*/
/*
* get_node_by_idx : Get node and y position by node index
*/
static TextNode* get_node_by_idx (PTEDATA ptedata, int line, int *item_y)
{
TextDoc *txtdoc = &ptedata->txtdoc;
TextNode *node;
int nr = 0, ypos = 0;
if (line < 0)
return NULL;
node = FIRSTNODE(txtdoc);
while (node) {
if (nr == line)
break;
nr ++;
ypos += NODE_HEIGHT(node);
node = TXTNODE_NEXT(node);
}
if (nr != line)
return NULL;
if (item_y)
*item_y = ypos;
return node;
}
static void teNodeInit (TextDoc *txtdoc, TextNode* node, TextNode *prenode)
{
SVITEMINFO svii;
HWND hWnd = (HWND)txtdoc->fn_data;
PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2(hWnd);
int linenr = 1, indent;
HSVITEM preitem = 0;
if (!node) return;
indent = teGetLineIndent (ptedata, node);
linenr = get_line_nr(hWnd, ptedata, node, indent);
set_line_width (hWnd, ptedata, node, indent);
svii.nItemHeight = ptedata->nLineHeight * linenr;
svii.addData = (DWORD)node;
svii.nItem = -1;
if (prenode)
preitem = (HSVITEM)prenode->addData;
node->addData = (DWORD) scrollview_add_item (hWnd, &ptedata->svdata,
preitem, &svii, NULL);
}
static void teNodeDel (TextDoc *txtdoc, TextNode *node)
{
HWND hWnd = (HWND)txtdoc->fn_data;
PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2(hWnd);
scrollview_del_item (hWnd, &ptedata->svdata, 0, (HSVITEM)node->addData);
}
static void teNodeChange (TextDoc *txtdoc, BOOL bSel)
{
PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2((HWND)txtdoc->fn_data);
if (!bSel) {
ptedata->curItemY = scrollview_get_item_ypos (&ptedata->svdata,
(HSVITEM)txtdoc->insert.curNode->addData);
}
#ifdef _SELECT_SUPPORT
else {
ptedata->selItemY = scrollview_get_item_ypos (&ptedata->svdata,
(HSVITEM)txtdoc->selection.curNode->addData);
}
#endif
}
static void teChangeCont (TextDoc *txtdoc, TextNode *node)
{
HWND hWnd = (HWND)txtdoc->fn_data;
PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2(hWnd);
int indent, linenr;
if (!node)
return;
indent = teGetLineIndent (ptedata, node);
linenr = get_line_nr(hWnd, ptedata, node, indent);
scrollview_set_item_height (hWnd, (HSVITEM)node->addData,
ptedata->nLineHeight*linenr);
set_line_width (hWnd, ptedata, node, indent);
}
/*
* textdoc_reset : resets or initializes the properties of a textdoc to
* default values
*/
static int textdoc_reset (HWND hWnd, TextDoc *txtdoc)
{
txtdoc->lnsep = DEF_LINESEP;
txtdoc->nDefLineSize = DEF_LINE_BUFFER_SIZE;
txtdoc->nBlockSize = DEF_LINE_BLOCK_SIZE;
txtdoc->init_fn = teNodeInit;
txtdoc->change_fn = teNodeChange;
txtdoc->change_cont = teChangeCont;
txtdoc->del_fn = teNodeDel;
txtdoc->fn_data = (void*)hWnd;
return 0;
}
/*
* teResetData : resets status data
*/
static void teResetData (PTEDATA ptedata)
{
ptedata->des_caret_x = 0;
ptedata->curItemY = 0;
#ifdef _SELECT_SUPPORT
ptedata->selItemY = 0;
#endif
ptedata->maxNode = NULL;
ptedata->maxLen = 0;
ptedata->secNode = NULL;
ptedata->secLen = 0;
ptedata->flags = 0;
}
/* -------------------------------------------------------------------------- */
#ifdef _SELECT_SUPPORT
int textdoc_copy_to_cb (PTEDATA ptedata, char *buffer, int len, BOOL bCB)
{
TextDoc *txtdoc = &ptedata->txtdoc;
int pos_start, pos_end;
TextNode *node, *endnode;
TextMark *markStart, *markEnd;
int org_len = len;
if (!txtdoc->selection.curNode)
return 0;
markStart = get_start_mark (ptedata);
markEnd = (markStart == &txtdoc->insert) ?
&txtdoc->selection : &txtdoc->insert;
node = markStart->curNode;
endnode = markEnd->curNode;
/* clear clipboard */
SetClipBoardData (CBNAME_TEXT, NULL, 0, CBOP_NORMAL);
while (1) {
get_selection_points (ptedata, node, &pos_start, &pos_end);
if (bCB) {
SetClipBoardData (CBNAME_TEXT, node->content.string + pos_start,
pos_end - pos_start, CBOP_APPEND);
}
else {
int output;
output = MIN(len, pos_end - pos_start);
strncpy (buffer, node->content.string + pos_start, output);
buffer += output;
len -= output;
}
if(node != endnode)
node = TXTNODE_NEXT (node);
else
break;
}
return org_len - len;
}
#endif
static void te_make_caret_visible (HWND hWnd, PTEDATA ptedata, BOOL bSel)
{
POINT pt;
if (!bSel)
myGetCaretPos (&pt);
#ifdef _SELECT_SUPPORT
else
myGetSelPos (&pt);
#endif
if (pt.y > ptescr->nContY)
pt.y = (pt.y / ptedata->nLineHeight + 1) * ptedata->nLineHeight;
else
pt.y = (pt.y / ptedata->nLineHeight) * ptedata->nLineHeight;
scrolled_make_pos_visible (hWnd, ptescr, pt.x, pt.y);
if (!bSel) {
mySetCaretPos (hWnd, -1, -1);
ShowCaret (hWnd);
}
}
/*
* teSetCaretPos : sets the caret position according to the current insertion
* point or sets the selection caret position according to the
* current selection point of the text doc.
* Description : should be called after the current insert point or the
* selection point of the text document is changed
*/
static void teSetCaretPos (HWND hWnd, PTEDATA ptedata)
{
TextDoc *txtdoc = &ptedata->txtdoc;
TextNode *node;
TextMark *mark;
int h, indent, endh;
HDC hdc;
hdc = GetClientDC (hWnd);
mark = GETMARK(txtdoc->selection.curNode);
node = mark->curNode;
SelectFont (hdc, GetWindowFont(hWnd));
#ifdef _SELECT_SUPPORT
if (txtdoc->selection.curNode)
h = ptedata->selItemY;
else
#endif
h = ptedata->curItemY;
indent = teGetLineIndent (ptedata, node);
if (BE_WRAP(hWnd)) {
RECT rc;
int w;
SIZE txtsize = {0, 0};
int txtlen, linenr, lineidx;
const unsigned char *pLine, *pIns;
DTFIRSTLINE fl;
rc.left = 0;
rc.top = 0;
rc.right = ptedata->svdata.scrdata.nContWidth;
rc.bottom = GetWindowFont(hWnd)->size;
linenr = NODE_LINENR(node);
pLine = node->content.string;
pIns = pLine + mark->pos_lnOff;
txtlen = node->content.txtlen;
/*
if (pLine[txtlen-1] == txtdoc->lnsep)
txtlen --;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -