📄 textedit.c
字号:
* some special operations (inserts line sep, del, bs, ...) * params : enode - the specified node to operate on * insert_pos - the designed insert position * newtext - text to insert * len - len of text to insert or remove */static inttextdoc_insert_string_ex (TextDoc *txtdoc, TextNode *enode, int insert_pos, const char* newtext, int len){ HWND hWnd = (HWND)txtdoc->fn_data; TextNode *curnode, *newnode; StrBuffer *strbuff; unsigned char *pIns;#ifdef _UNDO_SUPPORT //teUndoBackup (txtdoc);#endif#ifdef _SELECT_SUPPORT if (!enode && txtdoc->selection.curNode) { insert_pos = delete_selection (txtdoc); if (len == 1 && (*newtext == '\b' || *newtext == 127) ) return insert_pos; else { txtdoc->insert.pos_lnOff = insert_pos; } }#endif if (!enode) { //operates on the current insertion point curnode = txtdoc->insert.curNode; insert_pos = txtdoc->insert.pos_lnOff; } else { curnode = enode; } strbuff = &curnode->content; pIns = strbuff->string + insert_pos; if ( len == 1 || (len == 2 && strcmp(newtext, CH_RN) == 0) ) { if ( *newtext == txtdoc->lnsep || (strncmp(newtext, CH_RN, 2) == 0) ) { /* add a new line */ newnode = insert_ln_sep (txtdoc, curnode, insert_pos, len == 2); if (!enode) { txtdoc->insert.curNode = newnode; insert_pos = 0; } return insert_pos; } /* len == 1, other cases */ switch (*newtext) { case '\b': //BS if (pIns == strbuff->string) { //line head TextNode *node; if (BE_FIRST_NODE(curnode)) return insert_pos; node = TXTNODE_PREV(curnode); /* adds the previous line at the beginning of the current line */ insert_pos += textdoc_insert_string_ex ( txtdoc, enode, insert_pos, node->content.string, node->content.txtlen-1 ); /* deletes the previous line */ txtDelNode (txtdoc, node); txtdoc->change_fn (txtdoc, FALSE); return insert_pos; } len = - CHLENPREV(strbuff->string, pIns); break; case 127: //DEL if (*pIns == '\0') return insert_pos; if ( *pIns == txtdoc->lnsep || is_rn_sep(pIns) ) { TextNode *node = TXTNODE_NEXT(curnode); int oldpos = insert_pos; if (node->content.string[0] != txtdoc->lnsep && !is_rn_sep(node->content.string)) { *pIns = '\0'; curnode->content.txtlen = pIns - curnode->content.string; textdoc_insert_string_ex ( txtdoc, enode, insert_pos, node->content.string, node->content.txtlen ); insert_pos = oldpos; } txtDelNode (txtdoc, node); return insert_pos; } else { int chlen = CHLENNEXT( pIns, (curnode->content.txtlen + strbuff->string - pIns) ); pIns += chlen; insert_pos += chlen; len = -chlen; } break; } } insert_string (txtdoc, curnode, insert_pos, newtext, len); insert_pos += len; return insert_pos;}/* * textdoc_insert_text : insert a multi-line text at the insertion point */static inttextdoc_insert_text (TextDoc *txtdoc, const char* newtext, int len){ const char *pLine, *ptmp; TextNode *node, *newnode, *nextnode; int leftlen = len; if (!txtdoc || !newtext || len < 0) return -1; pLine = ptmp = newtext; /* insert first strings */ while (*ptmp != txtdoc->lnsep && *ptmp != '\0' && leftlen > 0) { ptmp ++; leftlen --; } textdoc_insert_string (txtdoc, pLine, ptmp-pLine); if (*ptmp == '\0' || leftlen <= 0) return 0; node = txtdoc->insert.curNode; /* make next node */ if (ptmp > pLine && is_rn_sep(ptmp - 1)) { textdoc_insert_string (txtdoc, CH_RN, 2); } else { textdoc_insert_string (txtdoc, &txtdoc->lnsep, 1); } ptmp ++; leftlen --; pLine = ptmp; nextnode = TXTNODE_NEXT (node); /* insert lines */ newnode = node; while (leftlen > 0 && *ptmp != '\0') { if (*ptmp == txtdoc->lnsep) { newnode = txtAddNode (txtdoc, pLine, ptmp-pLine+1, newnode); pLine = ptmp + 1; } ptmp ++; leftlen --; }#ifdef _SELECT_SUPPORT txtdoc->selection.curNode =NULL; txtdoc->selection.pos_lnOff = 0;#endif /* insert last strings */ //FIXME if (!nextnode) { fprintf (stderr, "Warning : nextnode is NULL!\n"); //set_current_node (txtdoc, LASTNODE(txtdoc), FALSE, TRUE); } else { set_current_node (txtdoc, nextnode, FALSE, TRUE); textdoc_insert_string (txtdoc, pLine, ptmp-pLine); } return 0;}/* ---------------------------------------------------------------------------- */#ifdef _TITLE_SUPPORTstatic int teGetTitleIndent (HWND hWnd, PTEDATA ptedata, HDC hdc){ SIZE txtsize = {0, 0}; if (ptedata->title) GetTextExtent(hdc, ptedata->title, strlen(ptedata->title), &txtsize); return txtsize.cx;}#endif/* paint textedit base lines */static void tePaint(HWND hWnd, HDC hdc, RECT *rcDraw){ RECT *rc = rcDraw; PTEDATA ptedata; int h, indent = 0; ptedata = (PTEDATA)GetWindowAdditionalData2(hWnd); h = ptedata->nLineHeight - 1; if (GetWindowStyle(hWnd) & ES_BASELINE) { SetPenColor (hdc, GetWindowElementColorEx (hWnd, FGC_CONTROL_NORMAL)); while (h < RECTHP(rc)) {#ifdef _TITLE_SUPPORT indent = (h == ptedata->nLineHeight - 1) ? ptedata->titleIndent : 0;#endif DrawHDotLine (hdc, rc->left + indent, rc->top+h, RECTWP(rc)-indent); h += ptedata->nLineHeight; } }}static void setup_dc (HWND hWnd, HDC hdc, BOOL bSel){ if (!bSel) { SetBkMode (hdc, BM_TRANSPARENT); SetTextColor (hdc, GetWindowElementColorEx (hWnd, GetWindowStyle(hWnd)&WS_DISABLED? FGC_CONTROL_DISABLED:FGC_CONTROL_NORMAL)); } else { SetBkMode (hdc, BM_OPAQUE); SetBkColor (hdc, GetWindowElementColorEx (hWnd, BKC_HILIGHT_NORMAL)); SetTextColor (hdc, GetWindowElementColorEx (hWnd, FGC_HILIGHT_NORMAL)); }}/* * teDrawItem : draw text node/item, including multi lines in wrap mode */static void teDrawItem (HWND hWnd, HSVITEM hsvi, HDC hdc, RECT *rcDraw){ RECT rcTxt = *rcDraw; TextNode *node; char *content; int txtlen, outlen, indent; UINT format; PTEDATA ptedata; TextDoc *txtdoc;#ifdef _SELECT_SUPPORT int i, pos_start, pos_end, outchars, line_nr, outw, selout = 0; DTFIRSTLINE fl;#endif unsigned char chln = 0; ptedata = (PTEDATA)GetWindowAdditionalData2(hWnd); txtdoc = &ptedata->txtdoc; node = (TextNode*) scrollview_get_item_adddata(hsvi); content = node->content.string; txtlen = node->content.txtlen; indent = teGetLineIndent (ptedata, node); if (txtlen <= 0 && indent <= 0) return; setup_dc (hWnd, hdc, FALSE); format = TE_FORMAT; if (BE_WRAP(hWnd)) format |= DT_WORDBREAK; SetTextAboveLineExtra (hdc, ptedata->nLineAboveH); SetTextBellowLineExtra (hdc, ptedata->nLineBaseH);#ifdef _TITLE_SUPPORT /* draw title */ if (ptedata->title && indent > 0) DrawText (hdc, ptedata->title, strlen(ptedata->title), &rcTxt, format);#endif outlen = txtlen; if (outlen > 0 && content[outlen-1] == txtdoc->lnsep) { outlen --; if (txtdoc->lnsep == '\n' && content[outlen-1] == '\r') outlen --; if (ptedata->lnChar) { outlen ++; chln = content[outlen-1]; content[outlen-1] = ptedata->lnChar; } } /* draw not selected node line text */#ifdef _SELECT_SUPPORT if (!textnode_is_selected(txtdoc, node)) { DrawTextEx (hdc, content, outlen, &rcTxt, indent, format); if (chln) content[outlen-1] = chln; return; } /* draw selected node */ get_selection_points (ptedata, node, &pos_start, &pos_end); line_nr = RECTH(rcTxt) / ptedata->nLineHeight; for (i = 0; i < line_nr; i++) { int startx, starty; if (i > 0) indent = 0; /* calc line info */ DrawTextEx2(hdc, content, outlen, &rcTxt, indent, format, &fl); startx = rcTxt.left; starty = rcTxt.top; outw = indent; outchars = 0; if (pos_start > 0) { //first: not selected section setup_dc (hWnd, hdc, FALSE); outchars = MIN(pos_start,fl.nr_chars); outw += TabbedTextOutLen (hdc, startx + outw, starty, content, outchars); content += outchars; } if (pos_start < fl.nr_chars && pos_end > 0) { //second: selected section outchars = MIN(pos_end, fl.nr_chars) - MAX(pos_start,0); if (!ptedata->drawSelected) { setup_dc (hWnd, hdc, TRUE); outw += TabbedTextOutLen (hdc, startx + outw, starty, content, outchars); } else { SetBkMode (hdc, BM_OPAQUE); outw += ptedata->drawSelected(hWnd, hdc, startx+outw, starty, content, outchars, selout); } content += outchars; selout += outchars; } if (pos_end < fl.nr_chars) { //third: not selected section setup_dc (hWnd, hdc, FALSE); outchars = fl.nr_chars - MAX(pos_end, 0); outw += TabbedTextOutLen (hdc, startx + outw, starty, content, outchars); content += outchars; } pos_start -= fl.nr_chars; pos_end -= fl.nr_chars; outlen -= fl.nr_chars; rcTxt.top += ptedata->nLineHeight; }#else DrawTextEx (hdc, content, outlen, &rcTxt, indent, format);#endif if (chln) content[outlen-1] = chln;}/*static void teDestroyItem (HWND hWnd, HSVITEM hsvi){ TextNode *node = (TextNode*)scrollview_get_item_adddata(hsvi); textnode_destroy (node);}*//* --------------------------- size and position calculation ---------------- */static int get_caret_width (HWND hWnd, PTEDATA ptedata){ if (ptedata->caretShape == ED_CARETSHAPE_LINE) { return 1; } else if (ptedata->caretShape == ED_CARETSHAPE_BLOCK) { TextDoc *txtdoc = &ptedata->txtdoc; TextNode *node = txtdoc->insert.curNode; char *pIns = node->content.string + txtdoc->insert.pos_lnOff; int chlen = CHLENNEXT(pIns, node->content.txtlen - txtdoc->insert.pos_lnOff); int width = GetWindowFont(hWnd)->size; if (chlen == 0) { if (ptedata->getCaretWidth) { int cw = ptedata->getCaretWidth (hWnd, width); if (cw > 0) width = cw; } } else { SIZE chsize = {0, 0}; HDC hdc = GetClientDC (hWnd); GetTextExtent (hdc, pIns, chlen, &chsize); ReleaseDC (hdc); if (chsize.cx > 0) width = chsize.cx; } return width; } return 1;}/* sets the current caret position in the virtual content window */static void mySetCaretPos (HWND hWnd, int x, int y){ PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2 (hWnd); //no change, should return?/* if ( (x < 0 || x == ptedata->caret_x) && (y < 0 || y == ptedata->caret_y) ) return;*/ if (x >= 0) ptedata->caret_x = x; else x = ptedata->caret_x; if (y >= 0) ptedata->caret_y = y; else y = ptedata->caret_y; if (scrolled_content_to_visible (ptescr, &x, &y) < 0) { HideCaret (hWnd); } else { scrolled_visible_to_window (ptescr, &x, &y); SetCaretPos (hWnd, x, y); ChangeCaretSize (hWnd, get_caret_width(hWnd, ptedata), ptedata->nLineHeight - ptedata->nLineAboveH); if ( (ptedata->flags & TEST_FOCUSED) && !(ptedata->flags & TEST_NOCARET) #ifdef _SELECT_SUPPORT && !(ptedata->txtdoc.selection.curNode)#endif ) { ActiveCaret (hWnd); ShowCaret (hWnd); } }}static void textedit_set_svlist (HWND hWnd, PSCRDATA pscrdata, BOOL visChanged){ PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2 (hWnd); /* reset caret pos in the real window */ if (ptedata->flags & TEST_FOCUSED) mySetCaretPos (hWnd, -1, -1); //FIXME: should be ScrollWindow ? //InvalidateRect (hWnd, NULL, TRUE); scrollview_set_svlist (hWnd, pscrdata, visChanged);}/* * set_caret_pos : Sets the caret/selection position in a node according to * x,y values */static intset_caret_pos (HWND hWnd, PTEDATA ptedata, TextNode *node, int x, int y, BOOL bSel){ TextDoc *txtdoc = &ptedata->txtdoc; const unsigned char *string = node->content.string; const unsigned char *pLine = string; int txtlen = node->content.txtlen; int line, indent, h = 0, out_chars, ln_chars; RECT rc; SIZE txtsize; DTFIRSTLINE fl; HDC hdc; indent = teGetLineIndent (ptedata, node); line = y / ptedata->nLineHeight; if (!bSel) h = ptedata->curItemY + line * ptedata->nLineHeight;#ifdef _SELECT_SUPPORT else h = ptedata->selItemY + line * ptedata->nLineHeight;#endif if (txtlen == 0 || string[0] == txtdoc->lnsep || is_rn_sep(string)) { if (!bSel) { txtdoc->insert.pos_lnOff = 0; mySetCaretPos (hWnd, 0 + indent, h + ptedata->nLineAboveH); }#ifdef _SELECT_SUPPORT else { txtdoc->selection.pos_lnOff = 0; mySetSelPos (0 + indent, h + ptedata->nLineAboveH); }#endif return 0; } //FIXME hdc = GetClientDC (hWnd); if (NODE_LINENR(node) > 1) { /* multi line case */ int i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -