⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 textedit.c

📁 这是ARM嵌入式系统的实验教程中的MINIGUI的实验源代码!
💻 C
📖 第 1 页 / 共 5 页
字号:
        *pIns = txtdoc->lnsep;
    *(pIns + len) = '\0';

    return newnode;
}

/* 
 * textdoc_insert_string_ex : 
 *          inserts a text string(not including line seperator) into 
 *          the text buffer at the specified insertion point, or makes
 *          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 int
textdoc_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 int
textdoc_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_SUPPORT
static 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 ---------------- */

/* sets the current caret position in the virtual content window */
static void mySetCaretPos (HWND hWnd, int x, int y)
{
    PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2 (hWnd);

    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);
        if (ptedata->flags & TEST_FOCUSED) {
            ShowCaret (hWnd);
            ActiveCaret (hWnd);
        }
        SetCaretPos (hWnd, x, y);
    }
}

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 int
set_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;

        rc.left = 0;
        rc.top = 0;
        rc.right = scrolled_get_contwidth(ptescr);
        rc.bottom = ptedata->nLineHeight;

        i = 0;
        while (1) {
            if (i > 0) indent = 0;
            DrawTextEx2 (hdc, pLine, txtlen, &rc, indent, 
                    TE_FORMAT | DT_WORDBREAK | DT_CALCRECT, &fl);
            if (i == line)
                break;
            pLine += fl.nr_chars;
            txtlen -= fl.nr_chars;
            i++;
        }
        ln_chars = fl.nr_chars;
    }
    else {
        pLine = string;
        ln_chars = txtlen;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -