/* ********************************************************************************************************* * 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 #include #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 */