This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/lib/lcd/gui/Widget/MULTIEDIT.c

1828 lines
54 KiB
C

/*
*********************************************************************************************************
* uC/GUI
* Universal graphic software for embedded applications
*
* (c) Copyright 2002, Micrium Inc., Weston, FL
* (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH
*
* µC/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:
* Find out if the current position of the cursor is still in the
* visible area. If it is not, the scroll position is updated.
* Needs to be called every time the cursor is move, wrap, font or
* window size are changed.
*/
static void _CalcScrollPos(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int xCursor, yCursor;
_GetCursorXY(hObj, pObj, &xCursor, &yCursor);
yCursor /= GUI_GetYDistOfFont(pObj->pFont);
WM_CheckScrollPos(&pObj->ScrollStateV, yCursor, 0, 0); /* Vertical */
WM_CheckScrollPos(&pObj->ScrollStateH, xCursor, 30, 30); /* Horizontal */
_SetScrollState(hObj);
}
/*********************************************************************
*
* _GetTextSizeX
*
* Returns the width of the displayed text.
*/
static int _GetTextSizeX(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
if (pObj->InvalidFlags & INVALID_TEXTSIZE) {
pObj->TextSizeX = 0;
if (pObj->hText) {
int NumChars, xSizeLine;
char *pText, *pLine;
GUI_SetFont(pObj->pFont);
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
do {
NumChars = _WrapGetNumCharsDisp(hObj, pObj, pText);
xSizeLine = 0;
pLine = pText;
while (NumChars--) {
xSizeLine += _GetCharDistX(pObj, pLine);
pLine += GUI_UC_GetCharSize(pLine);
}
if (xSizeLine > pObj->TextSizeX) {
pObj->TextSizeX = xSizeLine;
}
pText += _WrapGetNumBytesToNextLine(hObj, pObj, pText);
} while (*pText);
}
pObj->InvalidFlags &= ~INVALID_TEXTSIZE;
}
return pObj->TextSizeX;
}
/*********************************************************************
*
* _GetNumVisLines
*/
static int _GetNumVisLines(MULTIEDIT_HANDLE hObj, const MULTIEDIT_OBJ* pObj) {
GUI_RECT Rect;
WM_GetInsideRectExScrollbar(hObj, &Rect);
return (Rect.y1 - Rect.y0 + 1) / GUI_GetYDistOfFont(pObj->pFont);
}
/*********************************************************************
*
* _GetNumLines
*
* Calculates (if needed) and returns the number of lines
*/
static int _GetNumLines(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ * pObj) {
if (pObj->InvalidFlags & INVALID_NUMLINES) {
int NumLines = 0;
if (pObj->hText) {
int NumChars, NumBytes;
char *pText;
U16 Char;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
GUI_SetFont(pObj->pFont);
do {
NumChars = _WrapGetNumCharsDisp(hObj, pObj, pText);
NumBytes = GUI_UC__NumChars2NumBytes(pText, NumChars);
Char = GUI_UC_GetCharCode(pText + NumBytes);
if (Char) {
NumLines++;
}
pText += _WrapGetNumBytesToNextLine(hObj, pObj, pText);
} while (Char);
}
pObj->NumLines = NumLines + 1;
pObj->InvalidFlags &= ~INVALID_NUMLINES;
}
return pObj->NumLines;
}
/*********************************************************************
*
* _InvalidateNumLines
*
* Invalidates the number of lines
*/
static void _InvalidateNumLines(MULTIEDIT_OBJ * pObj) {
pObj->InvalidFlags |= INVALID_NUMLINES;
}
/*********************************************************************
*
* _InvalidateTextSizeX
*
* Calculates the TextSizeX
*/
static void _InvalidateTextSizeX(MULTIEDIT_OBJ * pObj) {
pObj->InvalidFlags |= INVALID_TEXTSIZE;
}
/*********************************************************************
*
* _CalcScrollParas
*
* Purpose:
* Calculate page size ,number of items & position
*/
static void _CalcScrollParas(MULTIEDIT_HANDLE hObj) {
MULTIEDIT_OBJ* pObj = MULTIEDIT_H2P(hObj);
/* Calc vertical scroll parameters */
pObj->ScrollStateV.NumItems = _GetNumLines(hObj, pObj);
pObj->ScrollStateV.PageSize = _GetNumVisLines(hObj, pObj);
/* Calc horizontal scroll parameters */
pObj->ScrollStateH.NumItems = _GetTextSizeX(hObj, pObj);
pObj->ScrollStateH.PageSize = _GetXSize(hObj, pObj);
_CalcScrollPos(hObj, pObj);
}
/*********************************************************************
*
* _ManageAutoScrollV
*/
static void _ManageAutoScrollV(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
if (pObj->Flags & MULTIEDIT_SF_AUTOSCROLLBAR_V) {
char IsRequired = _GetNumVisLines(hObj, pObj) < _GetNumLines(hObj, pObj);
if (WM_SetScrollbarV(hObj, IsRequired) != IsRequired) {
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
_InvalidateCursorXY(pObj);
_ClearCache(pObj);
}
}
}
/*********************************************************************
*
* _ManageScrollers
*
* Function:
* If autoscroll mode is enabled, add or remove the horizonatal and
* vertical scrollbars as required.
* Caution: This routine should not be called as reaction to a message
* From the child, as this could lead to a recursion problem
*/
static void _ManageScrollers(MULTIEDIT_HANDLE hObj) {
MULTIEDIT_OBJ* pObj;
pObj = MULTIEDIT_H2P(hObj);
/* 1. Step: Check if vertical scrollbar is required */
_ManageAutoScrollV(hObj, pObj);
/* 2. Step: Check if horizontal scrollbar is required */
if (pObj->Flags & MULTIEDIT_SF_AUTOSCROLLBAR_H) {
char IsRequired;
IsRequired = (_GetXSize(hObj, pObj) < _GetTextSizeX(hObj, pObj));
if (WM_SetScrollbarH(hObj, IsRequired) != IsRequired) {
/* 3. Step: Check vertical scrollbar again if horizontal has changed */
_ManageAutoScrollV(hObj, pObj);
}
}
_CalcScrollParas(hObj);
}
/*********************************************************************
*
* _Invalidate
*/
static void _Invalidate(MULTIEDIT_HANDLE hObj) {
_ManageScrollers(hObj);
WM_Invalidate(hObj);
}
/*********************************************************************
*
* _InvalidateTextArea
*
* Invalidates the text area only
*/
static void _InvalidateTextArea(MULTIEDIT_HANDLE hObj) {
GUI_RECT rInsideRect;
_ManageScrollers(hObj);
WM_GetInsideRectExScrollbar(hObj, &rInsideRect);
WM_InvalidateRect(hObj, &rInsideRect);
}
/*********************************************************************
*
* _InvalidateCursorPos
*
* Sets the position of the cursor to an invalid value
*/
static int _InvalidateCursorPos(MULTIEDIT_OBJ * pObj) {
int Value;
Value = pObj->CursorPosChar;
pObj->CursorPosChar = 0xffff;
return Value;
}
/*********************************************************************
*
* _SetFlag
*/
static void _SetFlag(MULTIEDIT_HANDLE hObj, int OnOff, U8 Flag) {
if (hObj) {
MULTIEDIT_OBJ * pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (OnOff) {
pObj->Flags |= Flag;
} else {
pObj->Flags &= ~Flag;
}
_InvalidateTextArea(hObj);
WM_UNLOCK();
}
}
/*********************************************************************
*
* _CalcNextValidCursorPos
*
* Purpose:
* Calculates the next valid cursor position of the desired position.
*
* Parameters:
* hObj, pObj : Obvious
* CursorPosChar : New character position of the cursor
* pCursorPosByte: Pointer to save the cursorposition in bytes. Used to abolish further calculations. Could be 0.
* pCursorLine : Pointer to save the line number of the cursor. Used to abolish further calculations. Could be 0.
*/
static int _CalcNextValidCursorPos(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj, int CursorPosChar, int * pCursorPosByte, int * pCursorLine) {
if (pObj->hText) {
char *pNextLine, *pCursor, *pText;
int CursorLine, NumChars, CursorPosByte;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
NumChars = _GetNumChars(pObj);
/* Set offset in valid range */
if (CursorPosChar < pObj->NumCharsPrompt) {
CursorPosChar = pObj->NumCharsPrompt;
}
if (CursorPosChar > NumChars) {
CursorPosChar = NumChars;
}
CursorPosByte = GUI_UC__NumChars2NumBytes(pText, CursorPosChar);
CursorLine = _GetCursorLine(hObj, pObj, pText, CursorPosChar);
pCursor = pText + CursorPosByte;
pNextLine = _GetpLine(hObj, pObj, CursorLine);
if (pNextLine > pCursor) {
if (pObj->CursorPosChar < CursorPosChar) {
pCursor = pNextLine;
} else {
char *pPrevLine;
int NumChars;
pPrevLine = _GetpLine(hObj, pObj, CursorLine - 1);
NumChars = _WrapGetNumCharsDisp(hObj, pObj, pPrevLine);
pPrevLine += GUI_UC__NumChars2NumBytes(pPrevLine, NumChars);
pCursor = pPrevLine;
}
CursorPosChar = GUI_UC__NumBytes2NumChars(pText, pCursor - pText);
CursorPosByte = GUI_UC__NumChars2NumBytes(pText, CursorPosChar);
CursorLine = _GetCursorLine(hObj, pObj, pText, CursorPosChar);
}
if (pCursorPosByte) {
*pCursorPosByte = CursorPosByte;
}
if (pCursorLine) {
*pCursorLine = CursorLine;
}
return CursorPosChar;
}
return 0;
}
/*********************************************************************
*
* _SetCursorPos
*
* Sets a new cursor position.
*/
static void _SetCursorPos(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj, int CursorPosChar) {
int CursorPosByte, CursorLine;
CursorPosChar = _CalcNextValidCursorPos(hObj, pObj, CursorPosChar, &CursorPosByte, &CursorLine);
/* Assign value and recalc whatever necessary */
if (pObj->CursorPosChar != CursorPosChar) {
/* Save values */
pObj->CursorPosByte = CursorPosByte;
pObj->CursorPosChar = CursorPosChar;
pObj->CursorLine = CursorLine;
_InvalidateCursorXY(pObj); /* Invalidate X/Y position */
_CalcScrollPos(hObj, pObj);
}
}
/*********************************************************************
*
* _SetWrapMode
*/
static int _SetWrapMode(MULTIEDIT_HANDLE hObj, GUI_WRAPMODE WrapMode) {
int r;
r = 0;
if (hObj) {
MULTIEDIT_OBJ * pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
r = pObj->WrapMode;
if (pObj->WrapMode != WrapMode) {
int Position;
pObj->WrapMode = WrapMode;
_ClearCache(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
_InvalidateTextArea(hObj);
Position = _InvalidateCursorPos(pObj);
_SetCursorPos(hObj, pObj, Position);
}
WM_UNLOCK();
}
return r;
}
/*********************************************************************
*
* _SetCursorXY
*
* Sets the cursor position from window coordinates.
*/
static void _SetCursorXY(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj, int x, int y) {
int CursorPosChar = 0;
if ((x < 0) || (y < 0)) {
return;
}
if (pObj->hText) {
char *pLine, *pText;
int CursorLine, WrapChars;
int SizeX = 0;
U16 Char;
GUI_SetFont(pObj->pFont);
CursorLine = y / GUI_GetFontDistY();
pLine = _GetpLine(hObj, pObj, CursorLine);
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
WrapChars = _WrapGetNumCharsDisp(hObj, pObj, pLine);
Char = GUI_UC__GetCharCode(pLine + GUI_UC__NumChars2NumBytes(pLine, WrapChars));
if (pObj->Flags & MULTIEDIT_SF_PASSWORD) {
if (!Char) {
WrapChars++;
}
} else {
if (!Char || (Char == '\n') || ((Char == ' ') && (pObj->WrapMode == GUI_WRAPMODE_WORD))) {
WrapChars++;
}
}
while (--WrapChars > 0) {
Char = GUI_UC_GetCharCode(pLine);
SizeX += _GetCharDistX(pObj, pLine);
if (!Char || (SizeX > x)) {
break;
}
pLine += GUI_UC_GetCharSize(pLine);
}
CursorPosChar = GUI_UC__NumBytes2NumChars(pText, pLine - pText);
}
_SetCursorPos(hObj, pObj, CursorPosChar);
}
/*********************************************************************
*
* _MoveCursorUp
*/
static void _MoveCursorUp(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int xPos, yPos;
_GetCursorXY(hObj, pObj, &xPos, &yPos);
yPos -= GUI_GetYDistOfFont(pObj->pFont);
_SetCursorXY(hObj, pObj, xPos, yPos);
}
/*********************************************************************
*
* _MoveCursorDown
*/
static void _MoveCursorDown(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int xPos, yPos;
_GetCursorXY(hObj, pObj, &xPos, &yPos);
yPos += GUI_GetYDistOfFont(pObj->pFont);
_SetCursorXY(hObj, pObj, xPos, yPos);
}
/*********************************************************************
*
* _MoveCursor2NextLine
*/
static void _MoveCursor2NextLine(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int xPos, yPos;
_GetCursorXY(hObj, pObj, &xPos, &yPos);
yPos += GUI_GetYDistOfFont(pObj->pFont);
_SetCursorXY(hObj, pObj, 0, yPos);
}
/*********************************************************************
*
* _MoveCursor2LineEnd
*/
static void _MoveCursor2LineEnd(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int xPos, yPos;
_GetCursorXY(hObj, pObj, &xPos, &yPos);
_SetCursorXY(hObj, pObj, 0x7FFF, yPos);
}
/*********************************************************************
*
* _MoveCursor2LinePos1
*/
static void _MoveCursor2LinePos1(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int xPos, yPos;
_GetCursorXY(hObj, pObj, &xPos, &yPos);
_SetCursorXY(hObj, pObj, 0, yPos);
}
/*********************************************************************
*
* _IsOverwriteAtThisChar
*/
static int _IsOverwriteAtThisChar(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
int r = 0;
if (pObj->hText && !(pObj->Flags & MULTIEDIT_CF_INSERT)) {
const char *pText;
int CurPos, Line1, Line2;
U16 Char;
pText = (const char *)GUI_ALLOC_h2p(pObj->hText);
Line1 = pObj->CursorLine;
CurPos = _CalcNextValidCursorPos(hObj, pObj, pObj->CursorPosChar + 1, 0, 0);
Line2 = _GetCursorLine(hObj, pObj, pText, CurPos);
pText += pObj->CursorPosByte;
Char = GUI_UC_GetCharCode(pText);
if (Char) {
if ((Line1 == Line2) || (pObj->Flags & MULTIEDIT_SF_PASSWORD)) {
r = 1;
} else {
if (Char != '\n') {
if ((Char != ' ') || (pObj->WrapMode == GUI_WRAPMODE_CHAR)) {
r = 1;
}
}
}
}
}
return r;
}
/*********************************************************************
*
* _GetCursorSizeX
*
* Returns the width of the cursor to be draw according to the
* insert mode flag and the cursor position.
*/
static int _GetCursorSizeX(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
if (_IsOverwriteAtThisChar(hObj, pObj)) {
const char *pText;
pText = (const char *)GUI_ALLOC_h2p(pObj->hText);
pText += pObj->CursorPosByte;
return _GetCharDistX(pObj, pText);
} else {
return 2;
}
}
/*********************************************************************
*
* static code, buffer management
*
**********************************************************************
*/
/*********************************************************************
*
* _IncrementBuffer
*
* Increments the buffer size by AddBytes.
*/
static int _IncrementBuffer(MULTIEDIT_OBJ* pObj, unsigned AddBytes) {
WM_HMEM hNew;
int NewSize;
NewSize = pObj->BufferSize + AddBytes;
hNew = GUI_ALLOC_Realloc(pObj->hText, NewSize);
if (hNew) {
if (!(pObj->hText)) {
char* pText;
pText = (char*) GUI_ALLOC_h2p(hNew);
*pText = 0;
}
pObj->BufferSize = NewSize;
pObj->hText = hNew;
return 1;
}
return 0;
}
/*********************************************************************
*
* _IsSpaceInBuffer
*
* Checks the available space in the buffer. If there is not enough
* space left this function attempts to get more.
*
* Returns:
* 1 = requested space is available
* 0 = failed to get enough space
*/
static int _IsSpaceInBuffer(MULTIEDIT_OBJ* pObj, int BytesNeeded) {
int NumBytes = 0;
if (pObj->hText) {
NumBytes = strlen((char*)GUI_ALLOC_h2p(pObj->hText));
}
BytesNeeded = (BytesNeeded + NumBytes + 1) - pObj->BufferSize;
if (BytesNeeded > 0) {
if (!_IncrementBuffer(pObj, BytesNeeded + MULTIEDIT_REALLOC_SIZE)) {
return 0;
}
}
return 1;
}
/*********************************************************************
*
* _IsCharsAvailable
*
* Checks weither the maximum number of characters is reached or not.
*
* Returns:
* 1 = requested number of chars is available
* 0 = maximum number of chars have reached
*/
static int _IsCharsAvailable(MULTIEDIT_OBJ* pObj, int CharsNeeded) {
if ((CharsNeeded > 0) && (pObj->MaxNumChars > 0)) {
int NumChars = 0;
if (pObj->hText) {
NumChars = _GetNumChars(pObj);
}
if ((CharsNeeded + NumChars) > pObj->MaxNumChars) {
return 0;
}
}
return 1;
}
/*********************************************************************
*
* static code, string manipulation routines
*
**********************************************************************
*/
/*********************************************************************
*
* _DeleteChar
*
* Deletes a character at the current cursor position and moves
* all bytes after the cursor position.
*/
static void _DeleteChar(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj) {
if (pObj->hText) {
unsigned CursorOffset;
char* s;
s = (char*) GUI_ALLOC_h2p(pObj->hText);
CursorOffset = pObj->CursorPosByte;
if (CursorOffset < strlen(s)) {
char *pCursor, *pLine, *pEndLine;
int CursorLine, NumChars, NumBytes;
pCursor = s + CursorOffset;
CursorLine = pObj->CursorLine;
pLine = _GetpLine(hObj, pObj, CursorLine);
NumChars = _WrapGetNumCharsDisp(hObj, pObj, pLine);
pEndLine = pLine + GUI_UC__NumChars2NumBytes(pLine, NumChars);
pLine = pLine + _WrapGetNumBytesToNextLine(hObj, pObj, pLine);
if (pCursor == pEndLine) {
NumBytes = pLine - pEndLine;
} else {
NumBytes = GUI_UC_GetCharSize(pCursor);
}
NumChars = GUI_UC__NumBytes2NumChars(pCursor, NumBytes);
strcpy(pCursor, pCursor + NumBytes);
WM_NotifyParent(hObj, WM_NOTIFICATION_VALUE_CHANGED);
pObj->NumChars -= NumChars;
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
_InvalidateCursorXY(pObj); /* Invalidate X/Y position */
_ClearCache(pObj);
pObj->CursorLine = _GetCursorLine(hObj, pObj, s, pObj->CursorPosChar);
}
}
}
/*********************************************************************
*
* _InsertChar
*
* Create space at the current cursor position and inserts a character.
*/
static int _InsertChar(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj, U16 Char) {
if (_IsCharsAvailable(pObj, 1)) {
int BytesNeeded;
BytesNeeded = GUI_UC__CalcSizeOfChar(Char);
if (_IsSpaceInBuffer(pObj, BytesNeeded)) {
int CursorOffset;
char* pText;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
CursorOffset = pObj->CursorPosByte;
pText += CursorOffset;
memmove(pText + BytesNeeded, pText, strlen(pText) + 1);
GUI_UC_Encode(pText, Char);
WM_NotifyParent(hObj, WM_NOTIFICATION_VALUE_CHANGED);
pObj->NumChars += 1;
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
_ClearCache(pObj);
return 1;
}
}
return 0;
}
/*********************************************************************
*
* static code
*
**********************************************************************
*/
/*********************************************************************
*
* _MULTIEDIT_Paint
*/
static void _MULTIEDIT_Paint(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ * pObj) {
int ScrollPosX, ScrollPosY, EffectSize, HBorder;
int x, y, xOff, yOff, ColorIndex, FontSizeY;
GUI_RECT r, rClip;
const GUI_RECT *prOldClip;
/* Init some values */
GUI_SetFont(pObj->pFont);
FontSizeY = GUI_GetFontDistY();
ScrollPosX = pObj->ScrollStateH.v;
ScrollPosY = pObj->ScrollStateV.v;
EffectSize = pObj->Widget.pEffect->EffectSize;
HBorder = pObj->HBorder;
xOff = EffectSize + HBorder - ScrollPosX ;
yOff = EffectSize - ScrollPosY * FontSizeY;
ColorIndex = ((pObj->Flags & MULTIEDIT_SF_READONLY) ? 1 : 0);
/* Set colors and draw the background */
LCD_SetBkColor(pObj->aBkColor[ColorIndex]);
LCD_SetColor(pObj->aColor[ColorIndex]);
GUI_Clear();
/* Draw the text if necessary */
rClip.x0 = EffectSize + HBorder;
rClip.y0 = EffectSize;
rClip.x1 = WM_GetWindowSizeX(hObj) - EffectSize - HBorder - 1;
rClip.y1 = WM_GetWindowSizeY(hObj) - EffectSize - 1;
prOldClip = WM_SetUserClipRect(&rClip);
if (pObj->hText) {
const char* pText;
int Line = 0;
int xSize = _GetXSize(hObj, pObj);
int NumVisLines = _GetNumVisLines(hObj, pObj);
/* Get the text */
pText = (const char *)GUI_ALLOC_h2p(pObj->hText);
/* Set the rectangle for drawing */
r.x0 = xOff;
r.y0 = EffectSize;
r.x1 = xSize + EffectSize + HBorder - 1;
r.y1 = pObj->Widget.Win.Rect.y1 - pObj->Widget.Win.Rect.y0 + 1;
/* Use cached position of first visible byte if possible */
if (ScrollPosY >= pObj->CacheFirstVisibleLine) {
if (pObj->CacheFirstVisibleByte) {
pText += pObj->CacheFirstVisibleByte;
Line = pObj->CacheFirstVisibleLine;
}
}
/* Do the drawing of the text */
do {
/* Cache the position of the first visible byte and the depending line number */
if (pObj->CacheFirstVisibleLine != ScrollPosY) {
if (Line == ScrollPosY) {
pObj->CacheFirstVisibleByte = pText - (const char *)GUI_ALLOC_h2p(pObj->hText);
pObj->CacheFirstVisibleLine = ScrollPosY;
}
}
/* Draw it */
if ((Line >= ScrollPosY) && ((Line - ScrollPosY) <= NumVisLines)) {
_DispString(hObj, pObj, pText, &r);
r.y0 += FontSizeY; /* Next line */
}
pText += _WrapGetNumBytesToNextLine(hObj, pObj, pText);
Line++;
} while (GUI_UC_GetCharCode(pText) && ((Line - ScrollPosY) <= NumVisLines));
}
/* Draw cursor if necessary */
if (WM_HasFocus(hObj)) {
_GetCursorXY(hObj, pObj, &x, &y);
r.x0 = x + xOff;
r.y0 = y + yOff;
r.x1 = r.x0 + _GetCursorSizeX(hObj, pObj) - 1;
r.y1 = r.y0 + FontSizeY - 1;
GUI_InvertRect(r.x0, r.y0, r.x1, r.y1);
}
WM_SetUserClipRect(prOldClip);
/* Draw the 3D effect (if configured) */
WIDGET__EFFECT_DrawDown(&pObj->Widget);
}
/*********************************************************************
*
* _OnTouch
*/
static void _OnTouch(MULTIEDIT_HANDLE hObj, MULTIEDIT_OBJ* pObj, WM_MESSAGE*pMsg) {
int Notification;
const GUI_PID_STATE* pState = (const GUI_PID_STATE*)pMsg->Data.p;
if (pMsg->Data.p) { /* Something happened in our area (pressed or released) */
if (pState->Pressed) {
int Effect, xPos, yPos;
Effect = pObj->Widget.pEffect->EffectSize;
xPos = pState->x + pObj->ScrollStateH.v - Effect - pObj->HBorder;
yPos = pState->y + pObj->ScrollStateV.v * GUI_GetYDistOfFont(pObj->pFont) - Effect;
_SetCursorXY(hObj, pObj, xPos, yPos);
_Invalidate(hObj);
Notification = WM_NOTIFICATION_CLICKED;
} else {
Notification = WM_NOTIFICATION_RELEASED;
}
} else {
Notification = WM_NOTIFICATION_MOVED_OUT;
}
WM_NotifyParent(hObj, Notification);
}
/*********************************************************************
*
* _AddKey
*
* Returns: 1 if Key has been consumed
* 0 else
*/
static int _AddKey(MULTIEDIT_HANDLE hObj, U16 Key) {
int r = 0; /* Key has not been consumed */
MULTIEDIT_OBJ* pObj;
pObj = MULTIEDIT_H2P(hObj);
switch (Key) {
case GUI_KEY_UP:
_MoveCursorUp(hObj, pObj);
r = 1; /* Key has been consumed */
break;
case GUI_KEY_DOWN:
_MoveCursorDown(hObj, pObj);
r = 1; /* Key has been consumed */
break;
case GUI_KEY_RIGHT:
_SetCursorPos(hObj, pObj, pObj->CursorPosChar + 1);
r = 1; /* Key has been consumed */
break;
case GUI_KEY_LEFT:
_SetCursorPos(hObj, pObj, pObj->CursorPosChar - 1);
r = 1; /* Key has been consumed */
break;
case GUI_KEY_END:
_MoveCursor2LineEnd(hObj, pObj);
r = 1; /* Key has been consumed */
break;
case GUI_KEY_HOME:
_MoveCursor2LinePos1(hObj, pObj);
r = 1; /* Key has been consumed */
break;
case GUI_KEY_BACKSPACE:
if (!(pObj->Flags & MULTIEDIT_SF_READONLY)) {
if (pObj->CursorPosChar > pObj->NumCharsPrompt) {
_SetCursorPos(hObj, pObj, pObj->CursorPosChar - 1);
_DeleteChar(hObj, pObj);
}
r = 1; /* Key has been consumed */
}
break;
case GUI_KEY_DELETE:
if (!(pObj->Flags & MULTIEDIT_SF_READONLY)) {
_DeleteChar(hObj, pObj);
r = 1; /* Key has been consumed */
}
break;
case GUI_KEY_INSERT:
if (!(pObj->Flags & MULTIEDIT_CF_INSERT)) {
pObj->Flags |= MULTIEDIT_CF_INSERT;
} else {
pObj->Flags &= ~MULTIEDIT_CF_INSERT;
}
r = 1; /* Key has been consumed */
break;
case GUI_KEY_ENTER:
if (pObj->Flags & MULTIEDIT_SF_READONLY) {
_MoveCursor2NextLine(hObj, pObj);
} else {
if (_InsertChar(hObj, pObj, (U8)('\n'))) {
if (pObj->Flags & MULTIEDIT_SF_PASSWORD) {
_SetCursorPos(hObj, pObj, pObj->CursorPosChar + 1);
} else {
_MoveCursor2NextLine(hObj, pObj);
}
}
}
r = 1; /* Key has been consumed */
break;
case GUI_KEY_ESCAPE:
break;
default:
if (!(pObj->Flags & MULTIEDIT_SF_READONLY) && (Key >= 0x20)) {
if (_IsOverwriteAtThisChar(hObj, pObj)) {
_DeleteChar(hObj, pObj);
}
if (_InsertChar(hObj, pObj, Key)) {
_SetCursorPos(hObj, pObj, pObj->CursorPosChar + 1);
}
r = 1; /* Key has been consumed */
}
}
_InvalidateTextArea(hObj);
return r;
}
/*********************************************************************
*
* _MULTIEDIT_Callback
*/
static void _MULTIEDIT_Callback (WM_MESSAGE *pMsg) {
MULTIEDIT_HANDLE hObj;
MULTIEDIT_OBJ* pObj;
WM_SCROLL_STATE ScrollState;
hObj = pMsg->hWin;
/* Let widget handle the standard messages */
if (WIDGET_HandleActive(hObj, pMsg) == 0) {
return;
}
pObj = MULTIEDIT_H2P(hObj);
switch (pMsg->MsgId) {
case WM_NOTIFY_CLIENTCHANGE:
_InvalidateCursorXY(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
_ClearCache(pObj);
_CalcScrollParas(hObj);
break;
case WM_SIZE:
_InvalidateCursorXY(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
_ClearCache(pObj);
_Invalidate(hObj);
break;
case WM_NOTIFY_PARENT:
switch (pMsg->Data.v) {
case WM_NOTIFICATION_VALUE_CHANGED:
if (pMsg->hWinSrc == WM_GetScrollbarV(hObj)) {
WM_GetScrollState(pMsg->hWinSrc, &ScrollState);
pObj->ScrollStateV.v = ScrollState.v;
WM_InvalidateWindow(hObj);
WM_NotifyParent(hObj, WM_NOTIFICATION_SCROLL_CHANGED);
} else if (pMsg->hWinSrc == WM_GetScrollbarH(hObj)) {
WM_GetScrollState(pMsg->hWinSrc, &ScrollState);
pObj->ScrollStateH.v = ScrollState.v;
WM_InvalidateWindow(hObj);
WM_NotifyParent(hObj, WM_NOTIFICATION_SCROLL_CHANGED);
}
break;
case WM_NOTIFICATION_SCROLLBAR_ADDED:
_SetScrollState(hObj);
break;
}
break;
case WM_PAINT:
_MULTIEDIT_Paint(hObj, pObj);
return;
case WM_TOUCH:
_OnTouch(hObj, pObj, pMsg);
break;
case WM_DELETE:
GUI_ALLOC_FreePtr(&pObj->hText);
break;
case WM_KEY:
if (((const WM_KEY_INFO*)(pMsg->Data.p))->PressedCnt >0) {
int Key = ((const WM_KEY_INFO*)(pMsg->Data.p))->Key;
/* Leave code for test purpose
switch (Key) {
case '1': Key = GUI_KEY_LEFT; break;
case '2': Key = GUI_KEY_UP; break;
case '3': Key = GUI_KEY_RIGHT; break;
case '4': Key = GUI_KEY_DOWN; break;
}
*/
if (_AddKey(hObj, Key)) {
return;
}
} else {
if (!(pObj->Flags & MULTIEDIT_SF_READONLY)) {
return; /* Key release is consumed (not sent to parent) */
}
}
}
WM_DefaultProc(pMsg);
}
/*********************************************************************
*
* Exported routines: Create
*
**********************************************************************
*/
/* Note: the parameters to a create function may vary.
Some widgets may have multiple create functions */
/*********************************************************************
*
* MULTIEDIT_CreateEx
*/
MULTIEDIT_HANDLE MULTIEDIT_CreateEx(int x0, int y0, int xsize, int ysize, WM_HWIN hParent, int WinFlags, int ExFlags,
int Id, int BufferSize, const char* pText)
{
MULTIEDIT_HANDLE hObj;
/* Create the window */
WM_LOCK();
if ((xsize == 0) && (ysize == 0) && (x0 == 0) && (y0 == 0)) {
GUI_RECT Rect;
WM_GetClientRectEx(hParent, &Rect);
xsize = Rect.x1 - Rect.x0 + 1;
ysize = Rect.y1 - Rect.y0 + 1;
}
hObj = WM_CreateWindowAsChild(x0, y0, xsize, ysize, hParent, WinFlags, &_MULTIEDIT_Callback,
sizeof(MULTIEDIT_OBJ) - sizeof(WM_Obj));
if (hObj) {
int i;
MULTIEDIT_OBJ* pObj = MULTIEDIT_H2P(hObj);
/* init widget specific variables */
WIDGET__Init(&pObj->Widget, Id, WIDGET_STATE_FOCUSSABLE);
/* init member variables */
MULTIEDIT_INIT_ID(pObj);
for (i = 0; i < NUM_DISP_MODES; i++) {
pObj->aBkColor[i] = _aDefaultBkColor[i];
pObj->aColor[i] = _aDefaultColor[i];
}
pObj->pFont = _pDefaultFont;
pObj->Flags = ExFlags;
pObj->CursorPosChar = 0;
pObj->CursorPosByte = 0;
pObj->HBorder = 1;
pObj->MaxNumChars = 0;
pObj->NumCharsPrompt = 0;
pObj->BufferSize = 0;
pObj->hText = 0;
if (BufferSize > 0) {
WM_HWIN hText;
if ((hText = GUI_ALLOC_AllocZero(BufferSize)) != 0) {
pObj->BufferSize = BufferSize;
pObj->hText = hText;
} else {
GUI_DEBUG_ERROROUT("MULTIEDIT_CreateEx failed to alloc buffer");
WM_DeleteWindow(hObj);
hObj = 0;
}
}
MULTIEDIT_SetText(hObj, pText);
_ManageScrollers(hObj);
} else {
GUI_DEBUG_ERROROUT_IF(hObj==0, "MULTIEDIT_CreateEx failed")
}
WM_UNLOCK();
return hObj;
}
/*********************************************************************
*
* Exported routines: Various methods
*
**********************************************************************
*/
/*********************************************************************
*
* MULTIEDIT_AddKey
*/
int MULTIEDIT_AddKey(MULTIEDIT_HANDLE hObj, U16 Key) {
int r = 0;
if (hObj) {
WM_LOCK();
r = _AddKey(hObj, Key);
WM_UNLOCK();
}
return r;
}
/*********************************************************************
*
* MULTIEDIT_SetText
*/
void MULTIEDIT_SetText(MULTIEDIT_HANDLE hObj, const char* pNew) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
int NumCharsNew = 0, NumCharsOld = 0;
int NumBytesNew = 0, NumBytesOld = 0;
char* pText;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (pObj->hText) {
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
pText += GUI_UC__NumChars2NumBytes(pText, pObj->NumCharsPrompt);
NumCharsOld = GUI__GetNumChars(pText);
NumBytesOld = GUI_UC__NumChars2NumBytes(pText, NumCharsOld);
}
if (pNew) {
NumCharsNew = GUI__GetNumChars(pNew);
NumBytesNew = GUI_UC__NumChars2NumBytes(pNew, NumCharsNew);
}
if (_IsCharsAvailable(pObj, NumCharsNew - NumCharsOld)) {
if (_IsSpaceInBuffer(pObj, NumBytesNew - NumBytesOld)) {
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
pText += GUI_UC__NumChars2NumBytes(pText, pObj->NumCharsPrompt);
if (pNew) {
strcpy(pText, pNew);
} else {
*pText = 0;
}
_SetCursorPos(hObj, pObj, pObj->NumCharsPrompt);
_InvalidateTextArea(hObj);
_InvalidateNumChars(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
}
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_GetText
*/
void MULTIEDIT_GetText(MULTIEDIT_HANDLE hObj, char* sDest, int MaxLen) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (pObj) {
char* pText;
int Len;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
pText += GUI_UC__NumChars2NumBytes(pText, pObj->NumCharsPrompt);
Len = strlen(pText);
if (Len > (MaxLen - 1)) {
Len = MaxLen - 1;
}
memcpy(sDest, pText, Len);
*(sDest + Len) = 0;
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_GetPrompt
*/
void MULTIEDIT_GetPrompt(MULTIEDIT_HANDLE hObj, char * sDest, int MaxLen) {
if (hObj) {
MULTIEDIT_OBJ * pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (pObj) {
char* sSource = (char*)GUI_ALLOC_h2p(pObj->hText);
int Len = GUI_UC__NumChars2NumBytes(sSource, pObj->NumCharsPrompt);
if (Len > (MaxLen - 1)) {
Len = MaxLen - 1;
}
memcpy(sDest, sSource, Len);
*(sDest + Len) = 0;
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetWrapWord
*/
void MULTIEDIT_SetWrapWord(MULTIEDIT_HANDLE hObj) {
_SetWrapMode(hObj, GUI_WRAPMODE_WORD);
}
/*********************************************************************
*
* MULTIEDIT_SetWrapChar
*/
void MULTIEDIT_SetWrapChar(MULTIEDIT_HANDLE hObj) {
_SetWrapMode(hObj, GUI_WRAPMODE_CHAR);
}
/*********************************************************************
*
* MULTIEDIT_SetWrapNone
*/
void MULTIEDIT_SetWrapNone(MULTIEDIT_HANDLE hObj) {
_SetWrapMode(hObj, GUI_WRAPMODE_NONE);
}
/*********************************************************************
*
* MULTIEDIT_SetInsertMode
*/
void MULTIEDIT_SetInsertMode(MULTIEDIT_HANDLE hObj, int OnOff) {
_SetFlag(hObj, OnOff, MULTIEDIT_SF_INSERT);
}
/*********************************************************************
*
* MULTIEDIT_SetReadOnly
*/
void MULTIEDIT_SetReadOnly(MULTIEDIT_HANDLE hObj, int OnOff) {
_SetFlag(hObj, OnOff, MULTIEDIT_SF_READONLY);
}
/*********************************************************************
*
* MULTIEDIT_SetPasswordMode
*/
void MULTIEDIT_SetPasswordMode(MULTIEDIT_HANDLE hObj, int OnOff) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
_SetFlag(hObj, OnOff, MULTIEDIT_SF_PASSWORD);
_InvalidateCursorXY(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetAutoScrollV
*/
void MULTIEDIT_SetAutoScrollV(MULTIEDIT_HANDLE hObj, int OnOff) {
_SetFlag(hObj, OnOff, MULTIEDIT_SF_AUTOSCROLLBAR_V);
}
/*********************************************************************
*
* MULTIEDIT_SetAutoScrollH
*/
void MULTIEDIT_SetAutoScrollH(MULTIEDIT_HANDLE hObj, int OnOff) {
_SetFlag(hObj, OnOff, MULTIEDIT_SF_AUTOSCROLLBAR_H);
}
/*********************************************************************
*
* MULTIEDIT_SetHBorder
*/
void MULTIEDIT_SetHBorder(MULTIEDIT_HANDLE hObj, unsigned HBorder) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if ((unsigned)pObj->HBorder != HBorder) {
pObj->HBorder = HBorder;
_Invalidate(hObj);
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetFont
*/
void MULTIEDIT_SetFont(MULTIEDIT_HANDLE hObj, const GUI_FONT GUI_UNI_PTR * pFont) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (pObj->pFont != pFont) {
pObj->pFont = pFont;
_InvalidateTextArea(hObj);
_InvalidateCursorXY(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetBkColor
*/
void MULTIEDIT_SetBkColor(MULTIEDIT_HANDLE hObj, unsigned Index, GUI_COLOR color) {
if (hObj && (Index < NUM_DISP_MODES)) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
pObj->aBkColor[Index] = color;
_InvalidateTextArea(hObj);
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetCursorOffset
*/
void MULTIEDIT_SetCursorOffset(MULTIEDIT_HANDLE hObj, int Offset) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
_SetCursorPos(hObj, pObj, Offset);
WM_Invalidate(hObj);
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetTextColor
*/
void MULTIEDIT_SetTextColor(MULTIEDIT_HANDLE hObj, unsigned Index, GUI_COLOR color) {
if (hObj && (Index < NUM_DISP_MODES)) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
pObj->aColor[Index] = color;
WM_Invalidate(hObj);
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetPrompt
*/
void MULTIEDIT_SetPrompt(MULTIEDIT_HANDLE hObj, const char* pPrompt) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
int NumCharsNew = 0, NumCharsOld = 0;
int NumBytesNew = 0, NumBytesOld = 0;
char* pText;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (pObj->hText) {
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
NumCharsOld = pObj->NumCharsPrompt;
NumBytesOld = GUI_UC__NumChars2NumBytes(pText, NumCharsOld);
}
if (pPrompt) {
NumCharsNew = GUI__GetNumChars(pPrompt);
NumBytesNew = GUI_UC__NumChars2NumBytes(pPrompt, NumCharsNew);
}
if (_IsCharsAvailable(pObj, NumCharsNew - NumCharsOld)) {
if (_IsSpaceInBuffer(pObj, NumBytesNew - NumBytesOld)) {
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
memmove(pText + NumBytesNew, pText + NumBytesOld, strlen(pText + NumBytesOld) + 1);
if (pPrompt) {
memcpy(pText, pPrompt, NumBytesNew);
}
pObj->NumCharsPrompt = NumCharsNew;
_SetCursorPos(hObj, pObj, NumCharsNew);
_InvalidateTextArea(hObj);
_InvalidateNumChars(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
}
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetBufferSize
*/
void MULTIEDIT_SetBufferSize(MULTIEDIT_HANDLE hObj, int BufferSize) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_HMEM hText;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if ((hText = GUI_ALLOC_AllocZero(BufferSize)) == 0) {
GUI_DEBUG_ERROROUT("MULTIEDIT_SetBufferSize failed to alloc buffer");
} else {
GUI_ALLOC_FreePtr(&pObj->hText);
pObj->hText = hText;
pObj->BufferSize = BufferSize;
pObj->NumCharsPrompt = 0;
_SetCursorPos(hObj, pObj, 0);
_InvalidateNumChars(pObj);
_InvalidateCursorXY(pObj);
_InvalidateNumLines(pObj);
_InvalidateTextSizeX(pObj);
}
_InvalidateTextArea(hObj);
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_SetMaxNumChars
*/
void MULTIEDIT_SetMaxNumChars(MULTIEDIT_HANDLE hObj, unsigned MaxNumChars) {
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
pObj->MaxNumChars = MaxNumChars;
if (MaxNumChars < (unsigned)pObj->NumCharsPrompt) {
pObj->NumCharsPrompt = MaxNumChars;
}
if (pObj->hText && MaxNumChars) {
char* pText;
int Offset;
pText = (char*) GUI_ALLOC_h2p(pObj->hText);
Offset = GUI_UC__NumChars2NumBytes(pText, MaxNumChars);
if (Offset < pObj->BufferSize) {
pText += Offset;
*pText = 0;
_SetCursorPos(hObj, pObj, Offset);
_InvalidateTextArea(hObj);
_InvalidateNumChars(pObj);
}
}
WM_UNLOCK();
}
}
/*********************************************************************
*
* MULTIEDIT_GetTextSize
*
* Purpose:
* Returns the number of bytes required to store the text.
* It is typically used when allocating a buffer to pass to
* MULTIEDIT_GetText().
*/
int MULTIEDIT_GetTextSize(MULTIEDIT_HANDLE hObj) {
int r = 0;
if (hObj) {
MULTIEDIT_OBJ* pObj;
WM_LOCK();
pObj = MULTIEDIT_H2P(hObj);
if (pObj->hText) {
const char* s;
s = (const char*)GUI_ALLOC_h2p(pObj->hText);
s += GUI_UC__NumChars2NumBytes(s, pObj->NumCharsPrompt);
r = 1 + strlen(s);
}
WM_UNLOCK();
}
return r;
}
#else /* avoid empty object files */
void MULTIEDIT_C(void);
void MULTIEDIT_C(void){}
#endif /* #if GUI_WINSUPPORT */