📄 multiedit.c
字号:
/*
*********************************************************************************************************
* uC/GUI
* Universal graphic software for embedded applications
*
* (c) Copyright 2002, Micrium Inc., Weston, FL
* (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH
*
* 礐/GUI is protected by international copyright laws. Knowledge of the
* source code may not be used to write a similar product. This file may
* only be used in accordance with a license and should not be redistributed
* in any way. We appreciate your understanding and fairness.
*
----------------------------------------------------------------------
File : MULTIEDIT.c
Purpose : Implementation of MULTIEDIT widget
---------------------------END-OF-HEADER------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include "MULTIEDIT.h"
#include "WIDGET.h"
#include "WM_Intern.h"
#if GUI_WINSUPPORT
/*********************************************************************
*
* Private config defaults
*
**********************************************************************
*/
/* Define default fonts */
#ifndef MULTIEDIT_FONT_DEFAULT
#define MULTIEDIT_FONT_DEFAULT &GUI_Font13_1
#endif
/* Define colors */
#ifndef MULTIEDIT_BKCOLOR0_DEFAULT
#define MULTIEDIT_BKCOLOR0_DEFAULT GUI_WHITE
#endif
#ifndef MULTIEDIT_BKCOLOR1_DEFAULT
#define MULTIEDIT_BKCOLOR1_DEFAULT 0xC0C0C0
#endif
#ifndef MULTIEDIT_TEXTCOLOR0_DEFAULT
#define MULTIEDIT_TEXTCOLOR0_DEFAULT GUI_BLACK
#endif
#ifndef MULTIEDIT_TEXTCOLOR1_DEFAULT
#define MULTIEDIT_TEXTCOLOR1_DEFAULT GUI_BLACK
#endif
/* Define character for password mode */
#define MULTIEDIT_PASSWORD_CHAR '*'
/*********************************************************************
*
* Object definition
*
**********************************************************************
*/
#define NUM_DISP_MODES 2
#define INVALID_NUMCHARS (1 << 0)
#define INVALID_NUMLINES (1 << 1)
#define INVALID_TEXTSIZE (1 << 2)
#define INVALID_CURSORXY (1 << 3)
#define INVALID_LINEPOSB (1 << 4)
typedef struct {
WIDGET Widget;
GUI_COLOR aBkColor[NUM_DISP_MODES];
GUI_COLOR aColor[NUM_DISP_MODES];
WM_HMEM hText;
U16 MaxNumChars; /* Maximum number of characters including the prompt */
U16 NumChars; /* Number of characters (text and prompt) in object */
U16 NumCharsPrompt; /* Number of prompt characters */
U16 NumLines; /* Number of text lines needed to show all data */
U16 TextSizeX; /* Size in X of text depending of wrapping mode */
U16 BufferSize;
U16 CursorLine; /* Number of current cursor line */
U16 CursorPosChar; /* Character offset number of cursor */
U16 CursorPosByte; /* Byte offset number of cursor */
U16 CursorPosX; /* Cursor position in X */
U16 CursorPosY; /* Cursor position in Y */
U16 CacheLinePosByte; /* */
U16 CacheLineNumber; /* */
U16 CacheFirstVisibleLine;
U16 CacheFirstVisibleByte;
WM_SCROLL_STATE ScrollStateV;
WM_SCROLL_STATE ScrollStateH;
const GUI_FONT GUI_UNI_PTR * pFont;
U8 Flags;
U8 InvalidFlags; /* Flags to save validation status */
U8 EditMode;
U8 HBorder;
GUI_WRAPMODE WrapMode;
#if GUI_DEBUG_LEVEL >1
int DebugId;
#endif
} MULTIEDIT_OBJ;
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static GUI_COLOR _aDefaultBkColor[2] = {
MULTIEDIT_BKCOLOR0_DEFAULT,
MULTIEDIT_BKCOLOR1_DEFAULT,
};
static GUI_COLOR _aDefaultColor[2] = {
MULTIEDIT_TEXTCOLOR0_DEFAULT,
MULTIEDIT_TEXTCOLOR1_DEFAULT,
};
static const GUI_FONT GUI_UNI_PTR * _pDefaultFont = MULTIEDIT_FONT_DEFAULT;
/*********************************************************************
*
* Macros for internal use
*
**********************************************************************
*/
#define MULTIEDIT_ID 0x8793 /* Magic numer, should be unique if possible */
#define MULTIEDIT_H2P(h) (MULTIEDIT_OBJ*) WM_H2P(h)
#define MULTIEDIT_REALLOC_SIZE 16
#if GUI_DEBUG_LEVEL > 1
#define MULTIEDIT_ASSERT_IS_VALID_PTR(p) DEBUG_ERROROUT_IF(p->DebugId != MULTIEDIT_ID, "MULTIEDIT.c: Wrong handle type or Object not init'ed")
#define MULTIEDIT_INIT_ID(p) p->DebugId = MULTIEDIT_ID
#define MULTIEDIT_DEINIT_ID(p) p->DebugId = MULTIEDIT_ID+1
#else
#define MULTIEDIT_ASSERT_IS_VALID_PTR(p)
#define MULTIEDIT_INIT_ID(p)
#define MULTIEDIT_DEINIT_ID(p)
#endif
/*********************************************************************
*
* static code, helper functions
*
**********************************************************************
*/
/*********************************************************************
*
* _InvalidateNumChars
*
* Invalidates the number of characters including the prompt
*/
static void _InvalidateNumChars(MULTIEDIT_OBJ * pObj) {
pObj->InvalidFlags |= INVALID_NUMCHARS;
}
/*********************************************************************
*
* _GetNumChars
*
* Calculates (if needed) and returns the number of characters including the prompt
*/
static int _GetNumChars(MULTIEDIT_OBJ * pObj) {
if (pObj->InvalidFlags & INVALID_NUMCHARS) {
char * pText;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
pObj->NumChars = GUI__GetNumChars(pText);
pObj->InvalidFlags &= ~INVALID_NUMCHARS;
}
return pObj->NumChars;
}
/*********************************************************************
*
* _GetXSize
*
* Returns the x size for displaying text.
*/
static int _GetXSize(MULTIEDIT_HANDLE hObj, const MULTIEDIT_OBJ* pObj) {
GUI_RECT Rect;
WM_GetInsideRectExScrollbar(hObj, &Rect);
return Rect.x1 - Rect.x0 - (pObj->HBorder * 2) - 1;
}
/*********************************************************************
*
* _GetNumCharsInPrompt
*/
static int _GetNumCharsInPrompt(const MULTIEDIT_OBJ* pObj, const char GUI_UNI_PTR * pText) {
char *pString, *pEndPrompt;
int r = 0;
pString = (char*) GUI_ALLOC_h2p(pObj->hText);
pEndPrompt = pString + GUI_UC__NumChars2NumBytes(pString, pObj->NumCharsPrompt);
if (pText < pEndPrompt) {
r = GUI_UC__NumBytes2NumChars(pText, pEndPrompt - pText);
}
return r;
}
/*********************************************************************
*
* _NumChars2XSize
*/
static int _NumChars2XSize(const char GUI_UNI_PTR * pText, int NumChars) {
int xSize = 0;
U16 Char;
while (NumChars--) {
Char = GUI_UC__GetCharCodeInc(&pText);
xSize += GUI_GetCharDistX(Char);
}
return xSize;
}
/*********************************************************************
*
* _WrapGetNumCharsDisp
*/
static int _WrapGetNumCharsDisp(MULTIEDIT_HANDLE hObj, const MULTIEDIT_OBJ* pObj, const char GUI_UNI_PTR * pText) {
int xSize, r;
xSize = _GetXSize(hObj, pObj);
if (pObj->Flags & MULTIEDIT_SF_PASSWORD) {
int NumCharsPrompt;
NumCharsPrompt = _GetNumCharsInPrompt(pObj, pText);
r = GUI__WrapGetNumCharsDisp(pText, xSize, pObj->WrapMode);
if (r >= NumCharsPrompt) {
int x;
switch (pObj->WrapMode) {
case GUI_WRAPMODE_NONE:
r = GUI__GetNumChars(pText);
break;
default:
r = NumCharsPrompt;
x = _NumChars2XSize(pText, NumCharsPrompt);
pText += GUI_UC__NumChars2NumBytes(pText, NumCharsPrompt);
while (GUI_UC__GetCharCodeInc(&pText) != 0) {
x += GUI_GetCharDistX(MULTIEDIT_PASSWORD_CHAR);
if (r && (x > xSize)) {
break;
}
r++;
}
break;
}
}
} else {
r = GUI__WrapGetNumCharsDisp(pText, xSize, pObj->WrapMode);
}
return r;
}
/*********************************************************************
*
* _WrapGetNumBytesToNextLine
*/
static int _WrapGetNumBytesToNextLine(MULTIEDIT_HANDLE hObj, const MULTIEDIT_OBJ* pObj, const char* pText) {
int xSize, r;
xSize = _GetXSize(hObj, pObj);
if (pObj->Flags & MULTIEDIT_SF_PASSWORD) {
int NumChars, NumCharsPrompt;
NumCharsPrompt = _GetNumCharsInPrompt(pObj, pText);
NumChars = _WrapGetNumCharsDisp(hObj, pObj, pText);
r = GUI_UC__NumChars2NumBytes(pText, NumChars);
if (NumChars < NumCharsPrompt) {
if (*(pText + r) == '\n') {
r++;
}
}
} else {
r = GUI__WrapGetNumBytesToNextLine(pText, xSize, pObj->WrapMode);
}
return r;
}
/*********************************************************************
*
* _GetCharDistX
*/
static int _GetCharDistX(const MULTIEDIT_OBJ* pObj, const char* pText) {
int r;
if ((pObj->Flags & MULTIEDIT_SF_PASSWORD) && (_GetNumCharsInPrompt(pObj, pText) == 0)) {
r = GUI_GetCharDistX(MULTIEDIT_PASSWORD_CHAR);
} else {
U16 c;
c = GUI_UC_GetCharCode(pText);
r = GUI_GetCharDistX(c);
}
return r;
}
/*********************************************************************
*
* _DispString
*/
static void _DispString(MULTIEDIT_HANDLE hObj, const MULTIEDIT_OBJ* pObj, const char* pText, GUI_RECT* pRect) {
int NumCharsDisp;
NumCharsDisp = _WrapGetNumCharsDisp(hObj, pObj, pText);
if (pObj->Flags & MULTIEDIT_SF_PASSWORD) {
int x, NumCharsPrompt, NumCharsLeft = 0;
NumCharsPrompt = _GetNumCharsInPrompt(pObj, pText);
if (NumCharsDisp < NumCharsPrompt) {
NumCharsPrompt = NumCharsDisp;
} else {
NumCharsLeft = NumCharsDisp - NumCharsPrompt;
}
GUI_DispStringInRectMax(pText, pRect, GUI_TA_LEFT, NumCharsPrompt);
x = pRect->x0 + _NumChars2XSize(pText, NumCharsPrompt);
if (NumCharsLeft) {
GUI_DispCharAt(MULTIEDIT_PASSWORD_CHAR, x, pRect->y0);
GUI_DispChars(MULTIEDIT_PASSWORD_CHAR, NumCharsLeft - 1);
}
} else {
GUI_DispStringInRectMax(pText, pRect, GUI_TA_LEFT, NumCharsDisp);
}
}
/*********************************************************************
*
* static code, cursor routines
*
**********************************************************************
*/
/*********************************************************************
*
* _GetpLine
*
* Returns a pointer to the beginning of the line with the
* given line number.
*/
static char * _GetpLine(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj, unsigned LineNumber) {
char * pText, * pLine;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
if ((unsigned)pObj->CacheLineNumber != LineNumber) {
if (LineNumber > (unsigned)pObj->CacheLineNumber) {
/* If new line number > cache we can start with old pointer */
int OldNumber = pObj->CacheLineNumber;
pLine = pText + pObj->CacheLinePosByte;
pObj->CacheLineNumber = LineNumber;
LineNumber -= OldNumber;
} else {
/* If new line number < cache we need to start with first byte */
pLine = pText;
pObj->CacheLineNumber = LineNumber;
}
while (LineNumber--) {
pLine += _WrapGetNumBytesToNextLine(hObj, pObj, pLine);
}
pObj->CacheLinePosByte = pLine - pText;
}
return pText + pObj->CacheLinePosByte;
}
/*********************************************************************
*
* _ClearCache
*
* Clears the cached position of the linenumber and the first byte
* of the line which holds the cursor.
*/
static void _ClearCache(MULTIEDIT_OBJ* pObj) {
pObj->CacheLineNumber = 0;
pObj->CacheLinePosByte = 0;
pObj->CacheFirstVisibleByte = 0;
pObj->CacheFirstVisibleLine = 0;
}
/*********************************************************************
*
* _GetCursorLine
*
* Returns the line number of the cursor position.
*/
static int _GetCursorLine(MULTIEDIT_HANDLE hObj, const MULTIEDIT_OBJ* pObj, const char* pText, int CursorPosChar) {
const char *pCursor;
const char *pEndLine;
int NumChars, ByteOffsetNewCursor, LineNumber = 0;
ByteOffsetNewCursor = GUI_UC__NumChars2NumBytes(pText, CursorPosChar);
pCursor = pText + ByteOffsetNewCursor;
if (pObj->CacheLinePosByte < ByteOffsetNewCursor) {
/* If cache pos < new position we can use it as start position */
pText += pObj->CacheLinePosByte;
LineNumber += pObj->CacheLineNumber;
}
while (*pText && (pCursor > pText)) {
NumChars = _WrapGetNumCharsDisp(hObj, pObj, pText);
pEndLine = pText + GUI_UC__NumChars2NumBytes(pText, NumChars);
pText += _WrapGetNumBytesToNextLine(hObj, pObj, pText);
if (pCursor <= pEndLine) {
if ((pCursor == pEndLine) && (pEndLine == pText) && *pText) {
LineNumber++;
}
break;
}
LineNumber++;
}
return LineNumber;
}
/*********************************************************************
*
* _GetCursorXY
*/
static void _GetCursorXY(MULTIEDIT_HANDLE hObj, /*const*/ MULTIEDIT_OBJ* pObj, int* px, int* py) {
if (pObj->InvalidFlags & INVALID_CURSORXY) {
int CursorLine = 0, x = 0;
GUI_SetFont(pObj->pFont);
if (pObj->hText) {
const char *pLine;
const char *pCursor;
pLine = (const char *)GUI_ALLOC_h2p(pObj->hText);
pCursor = pLine + pObj->CursorPosByte;
CursorLine = pObj->CursorLine;
pLine = _GetpLine(hObj, pObj, CursorLine);
while (pLine < pCursor) {
x += _GetCharDistX(pObj, pLine);
pLine += GUI_UC_GetCharSize(pLine);
}
}
pObj->CursorPosX = x;
pObj->CursorPosY = CursorLine * GUI_GetFontDistY();
pObj->InvalidFlags &= ~INVALID_CURSORXY;
}
*px = pObj->CursorPosX;
*py = pObj->CursorPosY;
}
/*********************************************************************
*
* _InvalidateCursorXY
*/
static void _InvalidateCursorXY(MULTIEDIT_OBJ * pObj) {
pObj->InvalidFlags |= INVALID_CURSORXY;
}
/*********************************************************************
*
* _SetScrollState
*/
static void _SetScrollState(WM_HWIN hObj) {
MULTIEDIT_OBJ* pObj = MULTIEDIT_H2P(hObj);
WIDGET__SetScrollState(hObj, &pObj->ScrollStateV, &pObj->ScrollStateH);
}
/*********************************************************************
*
* _CalcScrollPos
*
* Purpose:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -