Files
MiniGUI/src/control/textedit_impl.h
T

487 lines
15 KiB
C

///////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT NOTICE
//
// The following open source license statement does not apply to any
// entity in the Exception List published by FMSoft.
//
// For more information, please visit:
//
// https://www.fmsoft.cn/exception-list
//
//////////////////////////////////////////////////////////////////////////////
/*
* This file is part of MiniGUI, a mature cross-platform windowing
* and Graphics User Interface (GUI) support system for embedded systems
* and smart IoT devices.
*
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
* Copyright (C) 1998~2002, WEI Yongming
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* Or,
*
* As this program is a library, any link to this program must follow
* GNU General Public License version 3 (GPLv3). If you cannot accept
* GPLv3, you need to be licensed from FMSoft.
*
* If you have got a commercial license of this program, please use it
* under the terms and conditions of the commercial license.
*
* For more information about the commercial license, please refer to
* <http://www.minigui.com/blog/minigui-licensing-policy/>.
*/
/*
** textedit.h: header file of TextEdit control.
**
*/
#ifndef _TEXTEDIT_IMPL_H_
#define _TEXTEDIT_IMPL_H_
#ifdef __cplusplus
extern "C"
{
#endif
/* ---------------------- configuration options ----------------------- */
/* supports text selection */
#define _SELECT_SUPPORT 1
/* supports text undo/redo operations */
#undef _UNDO_SUPPORT
/* #define _UNDO_SUPPORT 1 */
/* support title text */
#define _TITLE_SUPPORT 1
/* -------------------------------------------------------------------- */
/* default base line height */
#define DEF_LINE_BASE_H ( (GetWindowStyle(hWnd) & TES_BASELINE) ? 2 : 0 )
/* default line above height */
#define DEF_LINE_ABOVE_H 4
/* minimal line above height */
#define MIN_LINE_ABOVE_H 1
/* default line height */
#define DEF_LINE_HEIGHT ( GetWindowFont(hWnd)->size + DEF_LINE_BASE_H + \
DEF_LINE_ABOVE_H )
/* default line buffer size */
#define DEF_LINE_BUFFER_SIZE 128
/* default line step block size */
#define DEF_LINE_BLOCK_SIZE 32
/* default line seperator '\n' */
#define DEF_LINESEP '\n'
#define CH_RN "\r\n"
/* default title length */
#define DEF_TITLE_LEN 63
/* draw text format */
#define TE_FORMAT (DT_LEFT | DT_TOP | DT_NOCLIP | DT_EXPANDTABS)
#ifdef _UNDO_SUPPORT
#define DEF_UNDO_DEPTH 3
/* undo operation types */
#define UNDO_OP_EDIT 1
#define UNDO_OP_ADD 2
#define UNDO_OP_DEL 3
#endif
/* -------------------------------------------------------------------- */
/* internal status flags */
#define TEST_SELECT 0x0001
#define TEST_FOCUSED 0x0002
#define TEST_TMP 0x0004
#define TEST_REPLACE 0x0008
#define TEST_MOVE 0x0010
#define TEST_NOCARET 0x0020
#define TEST_EX_SETFOCUS 0x0040
#define TEST_EX_KILLFOCUS 0x0080
/* ------------------------------- text document/buffer ------------------------ */
/* content type, reserved */
typedef enum {
CT_TEXT,
CT_BMP,
CT_ICON
} ContentType;
/* text format, reserved */
typedef enum {
TF_PLAINTEXT,
TF_RICHTEXT,
TF_MEDIATEXT
} TextFormat;
/* one text line (end with '\n') is a scrollview item */
/* structure of text node/line */
typedef struct _textnode
{
list_t list; /* list element */
StrBuffer content;
#if 0
ContentType type; /* text node content type, reserved */
#endif
DWORD addData; /* for storing scrollview item handle */
} TextNode;
/* structure of a text mark, recording insert position or selection range */
typedef struct _textmark
{
int pos_lnOff; /* mark offset in the text node*/
TextNode *curNode; /* text node containing the mark*/
} TextMark;
/* structure of text document data */
typedef struct _textdoc
{
list_t queue; /* text line/node head */
/* setup field */
unsigned char lnsep; /* line seperator (default is "\n") */
int nDefLineSize; /* default line buffer size*/
int nBlockSize; /* line buffer block size */
#if 0
TextFormat txtFormat; /* text format, reserved */
#endif
/* node init function executed when creating node */
void (*init_fn) (struct _textdoc *, TextNode *, TextNode *);
/* node change function executed when changing current insertion/selection node */
void (*change_fn) (struct _textdoc *, BOOL bSel);
/* node content change function executed when string content of a node is changed */
void (*change_cont) (struct _textdoc *, TextNode *node);
/* node destroy function */
void (*del_fn) (struct _textdoc *, TextNode *);
void *fn_data; /* data passed to init_fn */
/* status field */
TextMark insert; /* cursor/insertion mark */
#ifdef _SELECT_SUPPORT
TextMark selection; /* selection mark */
#endif
} TextDoc;
/* -------------------------------------------------------------------------- */
#ifdef _UNDO_SUPPORT
#define ACTION_COUNT 5
/* backup data struct */
typedef struct _status_data
{
DWORD flags; /* editor status */
int des_caret_x; /* the desired caret x position, changed by mouse and <- , -> */
int caret_x; /* caret x position in the virtual content window */
int caret_y; /* caret y position in the virtual content window */
#ifdef _SELECT_SUPPORT
int sel_x; /* selection point x position in the virtual content window */
int sel_y; /* selection point y position in the virtual content window */
#endif
TextNode *maxNode; /* node with the max length */
int maxLen; /* max line length */
TextNode *secNode; /* node with the second max length */
int secLen; /* seconde max line length */
int curItemY; /* y position of the current insertion node */
#ifdef _SELECT_SUPPORT
int selItemY; /* y position of the selection node */
#endif
} STATDATA;
typedef STATDATA* PSTATDATA;
/* structure of backup text node/line */
typedef struct _bk_textnode
{
list_t list; /* list element */
StrBuffer content; /* text content */
} BkNode;
typedef struct _backup_data
{
STATDATA statData;
TextMark bkIns; /* backup insertion point */
TextMark bkSel; /* backup selection point */
int opType; /* operation type */
list_t bkQueue; /* backup text nodes */
} BKDATA;
typedef BKDATA* PBKDATA;
#endif
/* structure of textedit control data */
typedef struct _tedata
{
SVDATA svdata; /* scrollview object */
TextDoc txtdoc; /* text document object */
StrBuffer tebuff; /* temp text content */
int nr_diff_line; /*first different line*/
int w_nochanged; /*width not changed of first different line*/
int w_lastline; /* width of last line*/
int hardLimit; /* hard limit */
int curlen; /* current tedata's len, not include char '\n' */
/* ----------------- properties ------------------- */
int nLineHeight; /* line height */
int nLineAboveH; /* height of above-line area */
int nLineBaseH; /* height of base-line area */
unsigned char lnChar; /* the char used to represent line seperator */
unsigned char caretShape; /* shape of the caret */
#ifdef _TITLE_SUPPORT
char *title; /* title text displayed before content text */
int titleIndent; /* title indent */
#endif
/* ----------------- status ----------------------- */
/* don't move this field */
DWORD flags; /* editor status */
DWORD ex_flags; /* editor extends status */
BOOL cont_dirty; /*content changed flags in text field*/
int des_caret_x; /* the desired caret x position, changed by mouse and <- , -> */
int caret_x; /* caret x position in the virtual content window */
int caret_y; /* caret y position in the virtual content window */
#ifdef _SELECT_SUPPORT
int sel_x; /* selection point x position in the virtual content window */
int sel_y; /* selection point y position in the virtual content window */
#endif
TextNode *maxNode; /* node with the max length */
int maxLen; /* max line length */
TextNode *secNode; /* node with the second max length */
int secLen; /* seconde max line length */
int curItemY; /* y position of the current insertion node */
#ifdef _SELECT_SUPPORT
int selItemY; /* y position of the selection node */
#endif
#ifdef _UNDO_SUPPORT
BKDATA *bkData; /* backup status data */
int undo_level; /* current undo level */
int cur_undo_depth; /* current undo depth */
int undo_depth; /* depth of undo stack */
int act_count; /* user action count */
#endif
HDC buf_dc;
ED_DRAWSEL_FUNC drawSelected;
int (*getCaretWidth) (HWND hWnd, int def_width);
} TEDATA;
typedef TEDATA* PTEDATA;
/* -------------------------------------------------------------------------- */
/* alloc for text node */
/* TODO */
static inline TextNode* textnode_alloc (void)
{
return malloc (sizeof(TextNode));
}
static inline void textnode_free (TextNode * node)
{
free (node);
}
#define ptescr (&ptedata->svdata.scrdata)
/* gets the current caret position in the virtual content window */
#define myGetCaretPos(pt) \
( (pt)->x = ptedata->caret_x, \
(pt)->y = ptedata->caret_y )
#ifdef _SELECT_SUPPORT
#define myGetSelPos(pt) \
( (pt)->x = ptedata->sel_x, \
(pt)->y = ptedata->sel_y )
#define mySetSelPos(x, y) \
( ptedata->sel_x = x >= 0 ? x : ptedata->sel_x, \
ptedata->sel_y = y >= 0 ? y : ptedata->sel_y )
#endif
#define BE_WRAP(hWnd) (GetWindowStyle(hWnd) & TES_AUTOWRAP)
#define BE_FIRST_NODE(node) \
(node->list.prev == &txtdoc->queue)
#define BE_LAST_NODE(node) \
(node->list.next == &txtdoc->queue)
#define FIRSTNODE(txtdoc) \
(list_entry((txtdoc)->queue.next, TextNode, list))
#define LASTNODE(txtdoc) \
(list_entry((txtdoc)->queue.prev, TextNode, list))
#define NODE_LINENR(node) \
( scrollview_get_item_height((HSVITEM)(node)->addData) / ptedata->nLineHeight )
#define NODE_HEIGHT(node) \
(scrollview_get_item_height((HSVITEM)(node)->addData))
#define NODE_INDEX(node) \
(scrollview_get_item_index(hWnd, (HSVITEM)(node)->addData))
static inline int teGetLineIndent (PTEDATA ptedata, TextNode *node)
{
#ifdef _TITLE_SUPPORT
if (node && node->list.prev == &ptedata->txtdoc.queue) {
return ptedata->titleIndent;
}
#endif
return 0;
}
#define TXTNODE_NEXT(node) \
( ((node)->list.next == &txtdoc->queue) ? NULL : \
list_entry((node)->list.next, TextNode, list) )
#define TXTNODE_PREV(node) \
( ((node)->list.prev == &txtdoc->queue) ? NULL : \
list_entry((node)->list.prev, TextNode, list) )
#ifdef _SELECT_SUPPORT
static BOOL textnode_is_selected (TextDoc *txtdoc, TextNode *node)
{
if (!txtdoc->selection.curNode)
return FALSE;
return scrollview_is_item_selected ((HSVITEM)node->addData);
}
#define NODE_IS_SELECTED(node) \
scrollview_is_item_selected ((HSVITEM)node->addData)
#define SELECT_NODE(node, bsel) \
scrollview_select_item (&ptedata->svdata, (HSVITEM)(node)->addData, bsel)
#endif
#define is_rn_sep(pIns) (txtdoc->lnsep == '\n' && *(pIns) == '\r' && *(pIns+1) == '\n')
#define check_caret() \
if (txtdoc->selection.curNode) { \
if (txtdoc->selection.curNode == txtdoc->insert.curNode && \
txtdoc->selection.pos_lnOff == txtdoc->insert.pos_lnOff) { \
ShowCaret (hWnd); \
txtdoc->selection.curNode = NULL; \
} \
else \
HideCaret (hWnd); \
} \
else \
ShowCaret (hWnd);
#define REFRESH_NODE_EX(node, rcInv) \
scrollview_refresh_item_ex(&ptedata->svdata, \
(HSVITEM)(node)->addData, rcInv)
#define REFRESH_NODE(node) \
scrollview_refresh_item(&ptedata->svdata, (HSVITEM)(node)->addData)
static int
textdoc_insert_string_ex (TextDoc *txtdoc, TextNode *enode, int insert_pos,
const char* newtext, int len);
static inline int
textdoc_insert_string_ex_2 (TextDoc *txtdoc, TextNode *enode, int insert_pos,
const char* newtext, int len)
{
TextNode *node=NULL;
BOOL bDel;
int ret;
bDel = (txtdoc->selection.curNode && !enode) ? TRUE : FALSE;
/* must use enode here */
ret = textdoc_insert_string_ex (txtdoc, enode, insert_pos, newtext, len);
if (!enode)
txtdoc->insert.pos_lnOff = ret;
/*when newtext is '\b' and all text is selected ,
* txtdoc->insert.curNode change after call
* funciton textdoc_insert_string_ex*/
node = enode ? enode : txtdoc->insert.curNode;
if (txtdoc->change_cont && node) {
txtdoc->change_cont (txtdoc, node);
}
return !bDel;
}
#define textdoc_insert_string(txtdoc, newtext, len) \
textdoc_insert_string_ex_2(txtdoc, NULL, 0, newtext, len)
#ifdef _SELECT_SUPPORT
#define GETMARK(cond) ( (cond) ? (&txtdoc->selection) : \
(&txtdoc->insert) )
#define SETITEMY(cond, item_y) \
if (cond) \
ptedata->selItemY = item_y; \
else \
ptedata->curItemY = item_y;
#else
#define GETMARK(cond) ((cond)? NULL : &txtdoc->insert)
#define SETITEMY(cond, item_y) \
if (!cond) \
ptedata->curItemY = item_y;
#endif
#ifdef _UNDO_SUPPORT
#define BACKUP_STDATA(stdata) \
memcpy (stdata, (void*)&ptedata->flags, sizeof(STATDATA));
#define UNDO_STDATA(stdata) \
memcpy ((void*)&ptedata->flags, stdata, sizeof(STATDATA));
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _TEXTEDIT_IMPL_H_ */