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

📄 textedit.c

📁 这是ARM嵌入式系统的实验教程中的MINIGUI的实验源代码!
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
** $Id: textedit.c,v 1.107 2004/10/18 00:49:28 snig Exp $
**
** textedit.c: text edit control
**
** Copyright (C) 2004 Feynman Software.
** 
** Current maintainer: Zhong Shuyi (zhongsy@minigui.org).
**
** Create date: 2004/03/01
**
** Note:
**    the textedit control is written from scratch
**    to replace the buggy medit control.
**
**    The textedit control inherits scrollview.
**
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*
 * TODO
 * tab
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "common.h"
#include "minigui.h"
#include "gdi.h"
#include "window.h"
#include "control.h"
#include "cliprect.h"
#include "internals.h"
#include "ctrlclass.h"

#ifdef _CTRL_TEXTEDIT

#include "ctrlmisc.h"
#include "scrolled.h"
#include "scrollview.h"
#include "text.h"
#include "textedit.h"


#ifdef _UNDO_SUPPORT
static void teUndoBackup (TextDoc *txtoc);
#endif

#undef _TEXTEDIT_DEBUG
//#define _TEXTEDIT_DEBUG

#ifdef _TEXTEDIT_DEBUG
static void dump_text (TextDoc *txtdoc, BOOL bSel)
{
    list_t *me;
    TextNode *node;
    SIZE txtsize;
    HWND hWnd = (HWND)txtdoc->fn_data;
    HDC hdc;

    printf ("\n\n\n\n");
    printf ("------------------------------------------------------\n");
    list_for_each (me, &txtdoc->queue) {
        node  = list_entry (me, TextNode, list);
        /*
        if (scrollview_is_item_selected ((HSVITEM)node->addData)) {
            printf ("sv select---<< %s\n", node->content.string);
        }
        */
#ifdef _SELECT_SUPPORT
        if (bSel && textnode_is_selected(txtdoc, node)) {
            printf ("%d:\n", node->content.txtlen);
            printf ("%s----->", node->content.string);
        }
#endif
    }
    hdc = GetClientDC (hWnd);
    GetTabbedTextExtent(hdc, "\t", 1, &txtsize);
    ReleaseDC (hdc);
    printf ("tab size = %d\n", txtsize.cx);
}

static void print_selected (TextDoc *txtdoc)
{
    dump_text (txtdoc, TRUE);
}

#endif


/* ------------------------------ text document/buffer ------------------------ */

/* 
 * set_current_node : Sets a node as the current insertion/selection node,
 *                    must be called when the current node is/will be changed.
 * Params           : newnode - the new node with insertion/selection point
 *                    bSel    - insertion or selection
 *                    bChange - Whether to call change function
 * Return           : TRUE on changed, FALSE otherwise.
 */
static BOOL
set_current_node (TextDoc *txtdoc, TextNode *newnode, BOOL bSel, BOOL bChange)
{
    TextMark *mark;
    TextNode *oldnode;

    mark = GETMARK(bSel);
    oldnode = mark->curNode;

    if (newnode == oldnode)
        return FALSE;

    mark->curNode = newnode;
    mark->pos_lnOff = 0;

    /* called when the current insertion node is changed */
    if (bChange && txtdoc->change_fn)
        txtdoc->change_fn (txtdoc, bSel);

    return TRUE;
}

/* 
 * textnode_create: creat a new text node and initialize it with text
 */
static TextNode* textnode_create (TextDoc *txtdoc, const char *line, int len)
{
    TextNode *newnode;

    if ( !(newnode = textnode_alloc ()) )
        return NULL;

    /* create a new blank line */
    if (!line || len < 0) len = 0;

    if ( !(testr_alloc (&newnode->content, len, txtdoc->nBlockSize)) ) {
        textnode_free (newnode);
        return NULL;
    }

    testr_setstr (&newnode->content, line, len);
    newnode->addData = 0;

    return newnode;
}

/* 
 * textnode_destroy: destroy a text node
 */
static void textnode_destroy (TextNode *node)
{
    if (node) {
        list_del (&node->list);
        testr_free (&node->content);
        textnode_free (node);
    }
}

/* 
 * textdoc_free : free TextDoc nodes
 * Description  : only changes the status fields of a TextDoc object, does not 
 *                affect the properties.
 */
static void textdoc_free (TextDoc *txtdoc)
{
    TextNode *node;
    if (!txtdoc) return;

    while (!list_empty(&txtdoc->queue)) {
        node = list_entry (txtdoc->queue.next, TextNode, list);
        textnode_destroy (node);
    }
    txtdoc->insert.pos_lnOff = 0;
    txtdoc->insert.curNode = NULL;
#ifdef _SELECT_SUPPORT
    txtdoc->selection.curNode = 0;
    txtdoc->selection.pos_lnOff = 0;
#endif
}

/*
 * txtAddNode : add a textnode after a specified node
 * params     : node - the previous text node, if NULL, the new node will be
 *                     inserted at the tail.
 */
static TextNode*
txtAddNode (TextDoc *txtdoc, const char*pLine, int len, TextNode *node)
{
    TextNode *newnode;

    if ( !(newnode = textnode_create (txtdoc, pLine, len)) )
        return NULL;

    if (node)
        list_add (&newnode->list, &node->list);
    else
        list_add_tail (&newnode->list, &txtdoc->queue);

    if (txtdoc->init_fn) txtdoc->init_fn(txtdoc, newnode, node);

    return newnode;
}

/*
 * txtDelNode : deletes a text node
 */
static void txtDelNode (TextDoc *txtdoc, TextNode *node)
{
    /* deletes scrollview item */
    if (txtdoc->del_fn)
        txtdoc->del_fn(txtdoc, node);

    textnode_destroy (node);
}

/*
 * textdoc_get_textlen : gets the total length of the text document
 */
static int textdoc_get_textlen (TextDoc *txtdoc)
{
    list_t *me;
    TextNode *node;
    int total_len = 0;

    list_for_each (me, &txtdoc->queue) {
        node = list_entry (me, TextNode, list);
        total_len += node->content.txtlen;
    }
    return total_len;
}

/*
 * textdoc_gettext : get text string from text document
 */
static int textdoc_gettext (TextDoc *txtdoc, int len, unsigned char *buffer)
{
    list_t *me;
    TextNode *node;
    unsigned char *pch = buffer;
    int total_len = 0, copy_len = 0;

    if (!buffer || len <= 0)
        return 0;

    list_for_each (me, &txtdoc->queue) {
        node = list_entry (me, TextNode, list);
        copy_len = MIN(node->content.txtlen, len - total_len);
        if (copy_len <= 0) break;
        memcpy (pch, node->content.string, copy_len);
        pch += copy_len;
        total_len += copy_len;
    }
    *pch = '\0';
    return total_len;
}

/* 
 * textdoc_settext : setting TextDoc object using a new text content and 
 *                   free the old one
 * Params          : content - new text content, if NULL, the content of the 
 *                             TextDoc object will not be changed; if content
 *                             is a null string, txtdoc content will be cleared.
 * TODO            : for not null-terminated text
 */
static int textdoc_settext (TextDoc *txtdoc, const char*content)
{
    const char *pLine, *ptmp;

    if (!txtdoc || !content) return -1;

    /* free the old text content */
    textdoc_free (txtdoc);

    ptmp = pLine = content;
    if (content) {
        while (*ptmp != '\0') {
            if (*ptmp == txtdoc->lnsep) {
                /* adds a new line, including the line seperator */
                txtAddNode (txtdoc, pLine, ptmp-pLine+1, NULL);
                pLine = ptmp + 1;
            }
            ptmp ++;
        }
    }
    /* adds a new blank line or the last line without a line seperator */
    txtAddNode (txtdoc, pLine, ptmp-pLine, NULL);

    set_current_node (txtdoc, FIRSTNODE(txtdoc), FALSE, TRUE);

    return 0;
}

static void
insert_string (TextDoc *txtdoc, TextNode *curnode, int insert_pos, 
               const char *newtext, int len)
{
    StrBuffer *strbuff = &curnode->content;
    unsigned char *pLn, *pIns;

    if (len > 0) {
        pLn = testr_realloc (strbuff, strbuff->txtlen + len);
        if (!pLn) return;
        pIns = pLn + insert_pos;
        memmove (pIns + len, pIns, strbuff->txtlen+1 - insert_pos);
        memcpy (pIns, newtext, len);
    }
    else {
        pIns = strbuff->string + insert_pos;
        memmove (pIns + len, pIns, strbuff->txtlen+1 - insert_pos);
        pLn = testr_realloc (strbuff, strbuff->txtlen + len);
    }

    strbuff->txtlen += len;
}

#ifdef _SELECT_SUPPORT
static TextMark* get_start_mark (PTEDATA ptedata)
{
    TextDoc *txtdoc = &ptedata->txtdoc;

    if (ptedata->curItemY < ptedata->selItemY ||
             (ptedata->curItemY == ptedata->selItemY && 
              txtdoc->insert.pos_lnOff < txtdoc->selection.pos_lnOff) )
        return &txtdoc->insert;
    else
        return &txtdoc->selection;
}

/* Gets the start and end selection points in a text node */
static void
get_selection_points (PTEDATA ptedata, TextNode *node, int *pos_start, int *pos_end)
{
    TextDoc *txtdoc = &ptedata->txtdoc;
    TextMark *markStart = get_start_mark (ptedata);
    TextMark *markEnd = (markStart == &txtdoc->insert) ? 
                          &txtdoc->selection : &txtdoc->insert;

    if (node ==  txtdoc->insert.curNode || node == txtdoc->selection.curNode) {
        if (txtdoc->insert.curNode == txtdoc->selection.curNode) {
            *pos_start = markStart->pos_lnOff;
            *pos_end = markEnd->pos_lnOff;
        }
        else if (node == markStart->curNode) {
            *pos_start = markStart->pos_lnOff;
            *pos_end = node->content.txtlen;
        }
        else {
            *pos_start = 0;
            *pos_end = markEnd->pos_lnOff;
        }
    }
    else {
        *pos_start = 0;
        *pos_end = node->content.txtlen;
    }
}

/*
 * delete_selection : deletes the selected texts
 */
static int delete_selection (TextDoc *txtdoc)
{
    int pos_start, pos_end;
    int pos_start2, pos_end2;
    TextNode *node, *startnode, *endnode;
    TextMark *markStart, *markEnd;
    HWND hWnd = (HWND)txtdoc->fn_data;
    PTEDATA ptedata = (PTEDATA)GetWindowAdditionalData2 (hWnd);

    markStart = get_start_mark (ptedata);
    markEnd = (markStart == &txtdoc->insert) ? 
                          &txtdoc->selection : &txtdoc->insert;

    startnode = markStart->curNode;
    endnode = markEnd->curNode;

    get_selection_points (ptedata, endnode, &pos_start, &pos_end);
    get_selection_points (ptedata, startnode, &pos_start2, &pos_end2);

    txtdoc->selection.curNode = NULL;

    scrollview_freeze (hWnd, &ptedata->svdata, TRUE);

    insert_string (txtdoc, endnode, pos_end, NULL, pos_start-pos_end);

    if (startnode != endnode) {

        while ( (node = TXTNODE_NEXT(startnode)) != endnode ) {
            txtDelNode (txtdoc, node);
        }

        if (pos_start2 == 0) {
            txtDelNode (txtdoc, startnode);
            startnode = NULL;
            txtdoc->insert.curNode = endnode;
            txtdoc->insert.pos_lnOff = 0;
            txtdoc->change_fn (txtdoc, FALSE);
        }
        else {
            char del[1] = {127};
            textdoc_insert_string_ex (txtdoc, startnode, pos_end2-1, NULL, 
                                      pos_start2-pos_end2+1);
            textdoc_insert_string_ex_2 (txtdoc, startnode, pos_start2, del, 1);
            txtdoc->insert.curNode = startnode;
            endnode = NULL;
        }
    }

    if (txtdoc->change_cont) {
        txtdoc->change_cont (txtdoc, endnode);
        txtdoc->change_cont (txtdoc, startnode);
    }

    txtdoc->selection.curNode = NULL;
    scrollview_unselect_all (&ptedata->svdata);
    scrollview_freeze (hWnd, &ptedata->svdata, FALSE);

    return pos_start2;
}
#endif

static TextNode*
insert_ln_sep (TextDoc *txtdoc, TextNode *curnode, int insert_pos, 
                           BOOL bChRn)
{
    StrBuffer *strbuff = &curnode->content;
    TextNode *newnode;
    unsigned char *pIns;
    int len = bChRn ? 2 : 1;

    pIns = strbuff->string + insert_pos;

    newnode = txtAddNode ( txtdoc, pIns, strbuff->txtlen - 
                          (pIns-strbuff->string), curnode );

    strbuff->txtlen = insert_pos + len; /* add a line sep */
    if (*pIns == '\0') {
        testr_realloc (strbuff, strbuff->txtlen);
        pIns = strbuff->string + insert_pos ;
    }

    if (bChRn)
        strncpy(pIns, CH_RN, len);
    else

⌨️ 快捷键说明

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