/////////////////////////////////////////////////////////////////////////////// // // IMPORTANT NOTICE // // The following open source license statement does not apply to any // entity in the Exception List published by FMSoft. // // For more information, please visit: // // https://www.fmsoft.cn/exception-list // ////////////////////////////////////////////////////////////////////////////// /* * This file is part of MiniGUI, a mature cross-platform windowing * and Graphics User Interface (GUI) support system for embedded systems * and smart IoT devices. * * Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd. * Copyright (C) 1998~2002, WEI Yongming * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Or, * * As this program is a library, any link to this program must follow * GNU General Public License version 3 (GPLv3). If you cannot accept * GPLv3, you need to be licensed from FMSoft. * * If you have got a commercial license of this program, please use it * under the terms and conditions of the commercial license. * * For more information about the commercial license, please refer to * . */ /* ** edit.c: the Single Line Edit Control module. ** ** Create date: 1999/8/26 ** ** TODO: ** * Replace ** * Undo. **/ #include #include #include #include #include "common.h" #ifdef _MGCTRL_SLEDIT #include "minigui.h" #include "gdi.h" #include "window.h" #include "ctrl/ctrlhelper.h" #include "ctrl/edit.h" #include "cliprect.h" #include "internals.h" #include "ctrlclass.h" #include "clipboard.h" #include "text.h" #include "edit_impl.h" static void set_line_width (HWND hWnd, PSLEDITDATA sled); static void mySetCaretPos (HWND hWnd, PSLEDITDATA sled, int x); static LRESULT SLEditCtrlProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static void sledit_refresh_caret (HWND hWnd, PSLEDITDATA sled, BOOL bInited); static BOOL make_charpos_visible (HWND hWnd, PSLEDITDATA sled, int charPos, int *cx); /* * for bug 4894, when select text don't hide caret, because this will close * the ime window. by humingming 2010.8.17 */ /*#define check_caret() \ if(sled->selStart != sled->selEnd) \ HideCaret(hWnd); \ else \ ShowCaret(hWnd); */ #define check_caret() ShowCaret(hWnd); #define shift_one_char_r(pos) \ { \ int len = CHLENNEXT((sled->content.string + sled->pos), (sled->content.txtlen - sled->pos)); \ sled->pos += len; \ } #define shift_one_char_l(pos) \ { \ int len = CHLENPREV((const char* )(sled->content.string),(const char* )(sled->content.string + sled->pos) ); \ sled->pos -= len; \ } #define PASSWORD_REPLACEMENT '*' BOOL RegisterSLEditControl (void) { WNDCLASS WndClass; WndClass.spClassName = CTRL_SLEDIT; WndClass.dwStyle = WS_NONE; WndClass.dwExStyle = WS_EX_NONE; WndClass.hCursor = GetSystemCursor (IDC_IBEAM); #ifdef _MGSCHEMA_COMPOSITING WndClass.dwBkColor = GetWindowElementAttr (HWND_NULL, WE_BGC_WINDOW); #else WndClass.iBkColor = GetWindowElementPixelEx (HWND_NULL, HDC_SCREEN, WE_BGC_WINDOW); #endif WndClass.WinProc = SLEditCtrlProc; if (gui_AddNewControlClass (&WndClass) != ERR_OK) return FALSE; WndClass.spClassName = CTRL_EDIT; return gui_AddNewControlClass (&WndClass) == ERR_OK; } /* -------------------------------------------------------------------------- */ static void setup_dc (HWND hWnd, SLEDITDATA *sled, HDC hdc, BOOL bSel) { DWORD dwStyle = GetWindowStyle (hWnd); if (!bSel) { SetBkMode (hdc, BM_TRANSPARENT); if (dwStyle & WS_DISABLED) SetTextColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_FGC_DISABLED_ITEM)); else SetTextColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_FGC_WINDOW)); SetBkColor (hdc, GetWindowBkColor (hWnd)); } else { SetBkMode (hdc, BM_OPAQUE); if (dwStyle & WS_DISABLED) SetTextColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_FGC_DISABLED_ITEM)); else SetTextColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_FGC_SELECTED_ITEM)); if (sled->status & EST_FOCUSED) SetBkColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_BGC_SELECTED_ITEM)); else SetBkColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_BGC_SELECTED_LOSTFOCUS)); } } /* -------------------------------------------------------------------------- */ static int sledit_settext (PSLEDITDATA sled, const char *newtext) { int len, txtlen; txtlen = strlen (newtext); len = (txtlen <= 0) ? sled->nBlockSize : txtlen; if (sled->hardLimit >= 0 && txtlen > sled->hardLimit) { return -1; } /* free the old text */ if (sled->content.string) testr_free (&sled->content); if (!testr_alloc (&sled->content, len, sled->nBlockSize)) return -1; if (newtext && txtlen > 0) testr_setstr (&sled->content, newtext, txtlen); else sled->content.txtlen = 0; return 0; } static void get_content_width (HWND hWnd, PSLEDITDATA sled) { GetClientRect (hWnd, &sled->rcVis); sled->rcVis.left += sled->leftMargin; sled->rcVis.top += sled->topMargin; sled->rcVis.right -= sled->rightMargin; sled->rcVis.bottom -= sled->bottomMargin; sled->nVisW = sled->rcVis.right - sled->rcVis.left; } static void recalcSize (HWND hWnd, PSLEDITDATA sled, BOOL bInited) { get_content_width (hWnd, sled); sled->nContX = 0; sled->nContW = sled->rcVis.right - sled->rcVis.left; set_line_width (hWnd, sled); sled->starty = sled->topMargin + ( sled->rcVis.bottom - sled->rcVis.top - GetWindowFont (hWnd)->size - 1 ) / 2; sledit_refresh_caret (hWnd, sled, bInited); } static int sledit_init (HWND hWnd, PSLEDITDATA sled) { PCONTROL pCtrl; if (!sled) return -1; pCtrl = gui_Control(hWnd); pCtrl->dwAddData2 = (DWORD)sled; sled->status = 0; sled->editPos = 0; sled->selStart = 0; sled->selEnd = 0; sled->leftMargin = MARGIN_EDIT_LEFT; sled->topMargin = MARGIN_EDIT_TOP; sled->rightMargin = MARGIN_EDIT_RIGHT; sled->bottomMargin = MARGIN_EDIT_BOTTOM; sled->passwdChar = PASSWORD_REPLACEMENT; sled->changed = FALSE; sled->bShowCaret = FALSE; sled->nBlockSize = DEF_LINE_BLOCK_SIZE; sled->hardLimit = -1; if (pCtrl->dwStyle & ES_TIP) { sled->tiptext = FixStrAlloc (DEF_TIP_LEN + 1); sled->tiptext[0] = 0; } else sled->tiptext = NULL; sled->content.string = NULL; sled->content.buffsize = 0; sled->content.txtlen = 0; sledit_settext (sled, pCtrl->spCaption); if (pCtrl->dwStyle & ES_PASSWORD) { pCtrl->pLogFont = GetSystemFont (SYSLOGFONT_DEFAULT); } CreateCaret (hWnd, NULL, 1, pCtrl->pLogFont->size); recalcSize (hWnd, sled, TRUE); return 0; } static void sledit_destroy (HWND hWnd, PSLEDITDATA sled) { DestroyCaret (hWnd); if ( (GetWindowStyle(hWnd) & ES_TIP) && sled->tiptext) FreeFixStr (sled->tiptext); testr_free (&sled->content); } static inline BOOL sleContentToVisible (PSLEDITDATA sled, int *x) { if (x) *x -= sled->nContX; else return -1; if (*x < 0 || *x > sled->nVisW) return -1; return 0; } static inline BOOL sleVisibleToWindow (PSLEDITDATA sled, int *x) { if (x) *x += sled->leftMargin; return TRUE; } static inline void sleContentToWindow (PSLEDITDATA sled, int *x) { sleContentToVisible (sled, x); sleVisibleToWindow (sled, x); } static inline void sleWindowToContent (PSLEDITDATA sled, int *x) { *x -= sled->leftMargin; *x += sled->nContX; } /* sets the current caret position in the virtual content window */ static void mySetCaretPos (HWND hWnd, PSLEDITDATA sled, int x) { if (sleContentToVisible(sled, &x) < 0) { HideCaret (hWnd); } else { sleVisibleToWindow (sled, &x); SetCaretPos (hWnd, x, sled->starty); ActiveCaret (hWnd); /* fix bug 4349: CENTER style does not work when startup*/ if (sled->status & EST_FOCUSED) { ShowCaret (hWnd); } } } static int get_caretpos_x(HWND hWnd) { PCONTROL pWin = (PCONTROL)hWnd; if (!pWin->pCaretInfo) return FALSE; return pWin->pCaretInfo->x; } static void slePaint (HWND hWnd, HDC hdc, PSLEDITDATA sled) { char* dispBuffer, *passwdBuffer = NULL; DWORD dwStyle = GetWindowStyle(hWnd); StrBuffer *content = &sled->content; int starty = sled->starty; int outw = 0; int startx; //FIXME, normal case of ES_TIP? if (dwStyle & ES_TIP && content->txtlen <= 0 && GetFocus(GetParent(hWnd)) != hWnd) { setup_dc (hWnd, sled, hdc, FALSE); TextOut (hdc, sled->leftMargin, starty, sled->tiptext); return; } if (dwStyle & ES_PASSWORD) { dispBuffer = FixStrAlloc (content->txtlen); memset (dispBuffer, sled->passwdChar, content->txtlen); passwdBuffer = dispBuffer; } else { dispBuffer = (char*)content->string; } if (dwStyle & ES_BASELINE) { SetPenColor (hdc, GetWindowElementPixelEx (hWnd, hdc, WE_FGC_WINDOW)); #ifdef _PHONE_WINDOW_STYLE MoveTo (hdc, sled->leftMargin, sled->rcVis.bottom); LineTo (hdc, sled->rcVis.right, sled->rcVis.bottom); #else DrawHDotLine (hdc, sled->leftMargin, sled->rcVis.bottom, sled->rcVis.right - sled->rcVis.left); #endif } ClipRectIntersect (hdc, &sled->rcVis); if (sled->selStart != sled->selEnd) {//select chars startx = sled->startx; sleContentToWindow (sled, &startx); /* draw first normal chars */ if (sled->selStart > 0) { setup_dc (hWnd, sled, hdc, FALSE); outw += TextOutLen (hdc, startx, starty, dispBuffer, sled->selStart); dispBuffer += sled->selStart; } /* draw selected chars */ setup_dc (hWnd, sled, hdc, TRUE); outw += TextOutLen (hdc, startx + outw, starty, dispBuffer, sled->selEnd - sled->selStart); dispBuffer += sled->selEnd - sled->selStart; /* draw others */ if (sled->selEnd < content->txtlen) { setup_dc (hWnd, sled, hdc, FALSE); outw += TextOutLen (hdc, startx + outw, starty, dispBuffer, content->txtlen - sled->selEnd); } } else { setup_dc (hWnd, sled, hdc, FALSE); startx = sled->startx; sleContentToWindow (sled, &startx); outw += TextOutLen (hdc, startx, starty, dispBuffer, content->txtlen); } if (dwStyle & ES_PASSWORD) FreeFixStr (passwdBuffer); } static int sleSetSel (HWND hWnd, PSLEDITDATA sled, int sel_start, int sel_end) { if (sled->content.txtlen <= 0) return -1; if (sel_start < 0) sel_start = 0; if (sel_end < 0) sel_end = sled->content.txtlen; if (sel_start == sel_end) return -1; sled->selStart = sel_start; sled->selEnd = sel_end; /* houhh 20101129, set cart position to sled->selEnd. */ if (sled->selEnd >= sled->selStart) { int cx = 0; make_charpos_visible (hWnd, sled, sled->selEnd, &cx); mySetCaretPos (hWnd, sled, cx); } /* * for bug 4894, when select text don't hide caret, because this will close * the ime window. by humingming 2010.8.17 */ //HideCaret(hWnd); InvalidateRect(hWnd, NULL, TRUE); return sled->selEnd - sled->selStart; } /* * set caret position according to the new desired x coordinate. */ static void set_caret_pos (HWND hWnd, PSLEDITDATA sled, int x, BOOL bSel) { int out_chars; HDC hdc; SIZE txtsize; hdc = GetClientDC (hWnd); sleWindowToContent (sled, &x); if (x - sled->startx <= 0) { out_chars = 0; txtsize.cx = 0; } else { /* DK [10/05/07] for fix bug4542: Replace content of edit to a same length * string which is made up of '*' character when the edit control include * ES_PASSWORD style, for take the right content width. */ if ((GetWindowStyle(hWnd) & ES_PASSWORD)) { int sled_width = x - sled->startx; int max_char_len = 0; GetTextExtent(hdc, "*", 1, &txtsize); max_char_len = sled_width / txtsize.cx; out_chars = sled->content.txtlen > max_char_len ? max_char_len : sled->content.txtlen; txtsize.cx *= out_chars; } else { const char* sled_string = (const char*)sled->content.string; out_chars = GetTextExtentPoint (hdc, sled_string, sled->content.txtlen, x - sled->startx, NULL, NULL, NULL, &txtsize); } } if (!bSel) { sled->editPos = out_chars; sled->selStart = sled->selEnd = sled->editPos; //mySetCaretPos (hWnd, sled, txtsize.cx + sled->startx); } else { if (out_chars > sled->editPos) { sled->selStart = sled->editPos; sled->selEnd = out_chars; } else { sled->selEnd = sled->editPos; sled->selStart = out_chars; } } /* move caret with select end. */ if (sled->editPos == sled->selStart) make_charpos_visible (hWnd, sled, sled->selEnd, NULL); else make_charpos_visible (hWnd, sled, sled->selStart, NULL); mySetCaretPos (hWnd, sled, txtsize.cx + sled->startx); ReleaseDC (hdc); } static BOOL make_pos_visible (HWND hWnd, PSLEDITDATA sled, int x) { if (x - sled->nContX > sled->nVisW) { sled->nContX = x - sled->nVisW; return TRUE; } else if (x < sled->nContX) { sled->nContX = x; return TRUE; } return FALSE; } static BOOL make_charpos_visible (HWND hWnd, PSLEDITDATA sled, int charPos, int *cx) { SIZE txtsize; HDC hdc; if (charPos <= 0) txtsize.cx = 0; else { char* string = (char*)sled->content.string; int dwStyle = GetWindowStyle(hWnd); hdc = GetClientDC (hWnd); if (dwStyle & ES_PASSWORD) { string = FixStrAlloc (sled->content.txtlen); memset (string, sled->passwdChar, sled->content.txtlen); } GetTextExtent (hdc, (const char*)string, charPos, &txtsize); if (dwStyle & ES_PASSWORD) FreeFixStr (string); ReleaseDC (hdc); } if (cx) *cx = sled->startx + txtsize.cx; return make_pos_visible (hWnd, sled, sled->startx + txtsize.cx); } static void calc_content_width(HWND hWnd, PSLEDITDATA sled, int charPos, int *cx) { SIZE txtsize; HDC hdc; if (charPos <= 0) txtsize.cx = 0; else { hdc = GetClientDC (hWnd); GetTextExtent (hdc, (const char*)sled->content.string, charPos, &txtsize); ReleaseDC (hdc); } if (cx) *cx = txtsize.cx; } static void calc_charpos_cx (HWND hWnd, PSLEDITDATA sled, int charPos, int *cx) { SIZE txtsize; HDC hdc; if (charPos <= 0) txtsize.cx = 0; else { hdc = GetClientDC (hWnd); GetTextExtent (hdc, (const char*)sled->content.string, charPos, &txtsize); ReleaseDC (hdc); } if (cx) *cx = sled->startx + txtsize.cx; } /* * set caret position according to the current edit position. */ static BOOL edtSetCaretPos (HWND hWnd, PSLEDITDATA sled) { BOOL bRefresh; int cx; bRefresh = make_charpos_visible (hWnd, sled, sled->editPos, &cx); mySetCaretPos (hWnd, sled, cx); if (bRefresh) { InvalidateRect (hWnd, NULL, TRUE); } return bRefresh; } static void set_edit_caret_pos(HWND hWnd, PSLEDITDATA sled) { int cx; make_charpos_visible (hWnd, sled, sled->editPos, &cx); mySetCaretPos (hWnd, sled, cx); } static int sleMouseMove (HWND hWnd, PSLEDITDATA sled, LPARAM lParam) { int selStart, selEnd; int mouseX, mouseY; RECT rcClient; mouseX = LOSWORD(lParam); mouseY = HISWORD(lParam); ScreenToClient(hWnd, &mouseX, &mouseY); GetClientRect(hWnd, &rcClient); selStart = sled->selStart; selEnd = sled->selEnd; if (mouseX < 0) { mouseX = 0; if (sled->selStart > 0) { shift_one_char_l (selStart); make_charpos_visible (hWnd, sled, sled->selStart, NULL); } else { return -1; } } if (mouseX > RECTW(rcClient)) { mouseX = RECTW(rcClient) - 1; if (sled->selEnd < sled->content.txtlen) { shift_one_char_r (selEnd); make_charpos_visible (hWnd, sled, sled->selEnd, NULL); } else { return -1; } } set_caret_pos (hWnd, sled, mouseX, TRUE); check_caret(); if (selStart != sled->selStart || selEnd != sled->selEnd) InvalidateRect(hWnd, NULL, TRUE); return 0; } static void set_line_width (HWND hWnd, PSLEDITDATA sled) { SIZE txtsize; HDC hdc; DWORD dwStyle = GetWindowStyle(hWnd); int old_w = sled->nContW; hdc = GetClientDC (hWnd); SelectFont (hdc, GetWindowFont(hWnd)); GetTextExtent(hdc, (const char*)(sled->content.string), sled->content.txtlen, &txtsize); ReleaseDC (hdc); if (txtsize.cx > sled->nVisW) sled->nContW = txtsize.cx; else sled->nContW = sled->nVisW; if (dwStyle & ES_RIGHT) { sled->nContX += (sled->nContW - old_w); } else if (dwStyle & ES_CENTER) { sled->nContX += (sled->nContW - old_w) >> 1; } if (sled->nContX + sled->nVisW > sled->nContW) { sled->nContX = sled->nContW - sled->nVisW; } else if (sled->nContX < 0) sled->nContX = 0; if (sled->nContW > sled->nVisW) sled->startx = 0; else if (dwStyle & ES_RIGHT) { sled->startx = sled->nVisW - txtsize.cx; } else if (dwStyle & ES_CENTER) { sled->startx = (sled->nVisW - txtsize.cx) >> 1; } else { sled->startx = 0; } } static inline void edtChangeCont (HWND hWnd, PSLEDITDATA sled) { set_line_width (hWnd, sled); } /* check input validity for password style */ static void check_valid_passwd (char *newtext) { char *ptmp = newtext; while (*ptmp) { if (!isprint(*ptmp)) *ptmp = PASSWORD_REPLACEMENT; ptmp ++; } } static int sleInsertText (HWND hWnd, PSLEDITDATA sled, char *newtext, int inserting) { int deleted; unsigned char *pIns, *content = sled->content.string; if ( (GetWindowStyle(hWnd) & ES_PASSWORD) && newtext && inserting > 0 ) { check_valid_passwd (newtext); } //delete the seleted if(sled->selStart != sled->selEnd) { deleted = sled->selEnd - sled->selStart; memmove (content + sled->selStart, content + sled->selEnd, sled->content.txtlen - sled->selEnd); sled->content.txtlen -= deleted; sled->editPos = sled->selStart; sled->selEnd = sled->selStart; ShowCaret(hWnd); if (!newtext) inserting = 0; } if ( !(sled->status & EST_REPLACE) && inserting > 0 && sled->hardLimit >= 0 && ((sled->content.txtlen + inserting) > sled->hardLimit)) { Ping (); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_MAXTEXT); inserting = sled->hardLimit - sled->content.txtlen; return 0; } else if ( (sled->status & EST_REPLACE) && inserting > 0 && sled->hardLimit >= 0 && (sled->editPos + inserting > sled->hardLimit) ) { Ping (); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_MAXTEXT); inserting = sled->hardLimit - sled->editPos; } if (inserting > 0) { content = testr_realloc (&sled->content, sled->content.txtlen + inserting); pIns = content + sled->editPos; if ( !(sled->status & EST_REPLACE) ) memmove (pIns + inserting, pIns, sled->content.txtlen+1 - sled->editPos); memcpy (pIns, newtext, inserting); } else if (inserting < 0) { pIns = content + sled->editPos; memmove (pIns + inserting, pIns, sled->content.txtlen+1 - sled->editPos); content = testr_realloc (&sled->content, sled->content.txtlen + inserting); } if (inserting <= 0 || !(sled->status & EST_REPLACE)) sled->content.txtlen += inserting; else { int add_len = inserting - sled->content.txtlen + sled->editPos; if (add_len > 0) { sled->content.txtlen += add_len; sled->content.string[sled->content.txtlen] = '\0'; } } sled->editPos += inserting; sled->selStart = sled->selEnd = sled->editPos; //FIXME edtChangeCont (hWnd, sled); InvalidateRect (hWnd, NULL, TRUE); if (!edtSetCaretPos (hWnd, sled)) { InvalidateRect (hWnd, NULL, TRUE); } sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); return 0; } static int sleInsertText_refresh (HWND hWnd, PSLEDITDATA sled, char *newtext, int inserting) { int deleted; unsigned char *pIns, *content = sled->content.string; if ( (GetWindowStyle(hWnd) & ES_PASSWORD) && newtext && inserting > 0 ) { check_valid_passwd (newtext); } //delete the seleted if(sled->selStart != sled->selEnd) { deleted = sled->selEnd - sled->selStart; memmove (content + sled->selStart, content + sled->selEnd, sled->content.txtlen - sled->selEnd); sled->content.txtlen -= deleted; sled->editPos = sled->selStart; sled->selEnd = sled->selStart; ShowCaret(hWnd); if (!newtext) inserting = 0; } if ( !(sled->status & EST_REPLACE) && inserting > 0 && sled->hardLimit >= 0 && ((sled->content.txtlen + inserting) > sled->hardLimit)) { Ping (); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_MAXTEXT); inserting = sled->hardLimit - sled->content.txtlen; //return 0; } else if ( (sled->status & EST_REPLACE) && inserting > 0 && sled->hardLimit >= 0 && (sled->editPos + inserting > sled->hardLimit) ) { Ping (); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_MAXTEXT); inserting = sled->hardLimit - sled->editPos; } if (inserting > 0) { content = testr_realloc (&sled->content, sled->content.txtlen + inserting); pIns = content + sled->editPos; if ( !(sled->status & EST_REPLACE) ) memmove (pIns + inserting, pIns, sled->content.txtlen+1 - sled->editPos); memcpy (pIns, newtext, inserting); } else if (inserting < 0) { pIns = content + sled->editPos; memmove (pIns + inserting, pIns, sled->content.txtlen+1 - sled->editPos); content = testr_realloc (&sled->content, sled->content.txtlen + inserting); } if (inserting <= 0 || !(sled->status & EST_REPLACE)) sled->content.txtlen += inserting; else { int add_len = inserting - sled->content.txtlen + sled->editPos; if (add_len > 0) { sled->content.txtlen += add_len; sled->content.string[sled->content.txtlen] = '\0'; } } sled->editPos += inserting; sled->selStart = sled->selEnd = sled->editPos; //FIXME edtChangeCont (hWnd, sled); return 0; } static int sleCaseText (char* txt, BOOL bupper) { char *str; char (*tocase)(char); if (NULL == txt) return -1; if (bupper) tocase = (char(*)(char))toupper; else tocase = (char(*)(char))tolower; str = txt; while (*str != '\0') { str[0] = tocase(str[0]); str ++; } return 0; } #ifdef _MGHAVE_CLIPBOARD static int sleInsertCbText (HWND hWnd, PSLEDITDATA sled) { int inserting; unsigned char *txtBuffer; if (GetWindowStyle(hWnd) & ES_READONLY) { return 0; } inserting = GetClipBoardDataLen (CBNAME_TEXT); txtBuffer = ALLOCATE_LOCAL (inserting); GetClipBoardData (CBNAME_TEXT, txtBuffer, inserting); txtBuffer[inserting]=0; if (GetWindowStyle(hWnd) & ES_UPPERCASE) sleCaseText((char *)txtBuffer, TRUE); else if (GetWindowStyle(hWnd) & ES_LOWERCASE) sleCaseText((char *)txtBuffer, FALSE); sleInsertText (hWnd, sled, (char *)txtBuffer, inserting); DEALLOCATE_LOCAL(txtBuffer); return 0; } #endif static void esright_backspace_refresh(HWND hWnd, PSLEDITDATA sled, int del) { RECT scroll_rc, refresh_rc; int sel_start_x, sel_end_x; int old_caret_x, cur_caret_x; int scroll_len; int old_editpos_x, cur_editpos_x; scroll_rc.top = sled->rcVis.top; scroll_rc.bottom = sled->rcVis.bottom; if (sled->nContW <= sled->nVisW){ if (sled->selStart != sled->selEnd){ calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); if (sled->selStart < sled->selEnd){ scroll_rc.right = sel_end_x + 1; } else{ scroll_rc.right = sel_start_x + 1; } scroll_rc.left = sled->rcVis.left; sleInsertText_refresh (hWnd, sled, NULL, del); scroll_len = abs(sel_start_x - sel_end_x); ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); edtSetCaretPos (hWnd, sled); } else{ calc_charpos_cx(hWnd, sled, sled->editPos, &old_editpos_x); scroll_rc.left = sled->rcVis.left; calc_charpos_cx(hWnd, sled, sled->editPos + del, &cur_editpos_x); sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); scroll_rc.right = old_editpos_x + 1; scroll_len = abs(cur_editpos_x - old_editpos_x); ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); } } else{ if (sled->nContX <= 0){//left scroll window while the head of text is in the sled->rcVis if (sled->selStart != sled->selEnd){ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.right = sled->rcVis.right; scroll_rc.right = sled->rcVis.right; calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); if (sled->selStart < sled->selEnd){ scroll_rc.left = sel_start_x + 1; } else{ scroll_rc.left = sel_end_x + 1; } sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); scroll_len = abs(sel_start_x - sel_end_x); refresh_rc.left = refresh_rc.right - scroll_len; ScrollWindow(hWnd, -scroll_len, 0, &scroll_rc, NULL); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } } else{ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.right = sled->rcVis.right; scroll_rc.right = sled->rcVis.right; old_caret_x = get_caretpos_x(hWnd); sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); cur_caret_x = get_caretpos_x(hWnd); scroll_rc.left = cur_caret_x; scroll_len = abs(cur_caret_x - old_caret_x); refresh_rc.left = refresh_rc.right - scroll_len; ScrollWindow(hWnd, -scroll_len, 0, &scroll_rc, NULL); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } } } else{//right scroll window while sled->nContX > 0 if (sled->selStart != sled->selEnd){ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.left = sled->rcVis.left; calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); if (sled->selStart < sled->selEnd){ scroll_rc.right = sel_end_x + 1 - sled->nContX; } else{ scroll_rc.right = sel_start_x + 1 - sled->nContX; } scroll_rc.left = sled->rcVis.left; sleInsertText_refresh (hWnd, sled, NULL, del); scroll_len = abs(sel_start_x - sel_end_x); refresh_rc.right = refresh_rc.left + scroll_len; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); edtSetCaretPos (hWnd, sled); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } if (sled->nContX <= 0){ InvalidateRect(hWnd, NULL, TRUE); } } else{ int old_ncontw; refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.left = sled->rcVis.left; scroll_rc.left = sled->rcVis.left; old_ncontw = sled->nContW; sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); cur_caret_x = get_caretpos_x(hWnd); scroll_rc.right = cur_caret_x; scroll_len = abs(sled->nContW - old_ncontw); refresh_rc.right = refresh_rc.left + abs(scroll_len); ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } if (sled->nContX <= 0){ InvalidateRect(hWnd, NULL, TRUE); } } } } sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); } static void esright_del_refresh(HWND hWnd, PSLEDITDATA sled, int del) { RECT scroll_rc, refresh_rc; int sel_start_x, sel_end_x; int old_caret_x, cur_caret_x; int scroll_len; int old_editpos_x, cur_editpos_x; scroll_rc.top = sled->rcVis.top; scroll_rc.bottom = sled->rcVis.bottom; if (sled->nContW <= sled->nVisW){ if (sled->selStart != sled->selEnd){ calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); if (sled->selStart < sled->selEnd){ scroll_rc.right = sel_end_x + 1; } else{ scroll_rc.right = sel_start_x + 1; } scroll_rc.left = sled->rcVis.left; sleInsertText_refresh (hWnd, sled, NULL, del); scroll_len = abs(sel_start_x - sel_end_x); ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); edtSetCaretPos (hWnd, sled); } else{ old_caret_x = get_caretpos_x(hWnd); scroll_rc.left = sled->rcVis.left; sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); cur_caret_x = get_caretpos_x(hWnd); scroll_rc.right = cur_caret_x; scroll_len = cur_caret_x - old_caret_x; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); } } else{ if (sled->nContX <=0){//left scroll window while the head of text is in the sled->rcVis if (sled->selStart != sled->selEnd){ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.right = sled->rcVis.right; scroll_rc.right = sled->rcVis.right; calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); if (sled->selStart < sled->selEnd){ scroll_rc.left = sel_start_x + 1; } else{ scroll_rc.left = sel_end_x + 1; } sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); scroll_len = abs(sel_start_x - sel_end_x); refresh_rc.left = refresh_rc.right - scroll_len; ScrollWindow(hWnd, -scroll_len, 0, &scroll_rc, NULL); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } } else{ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.right = sled->rcVis.right; scroll_rc.right = sled->rcVis.right; scroll_rc.left = get_caretpos_x(hWnd); calc_charpos_cx(hWnd, sled, sled->editPos, &old_editpos_x); sleInsertText_refresh (hWnd, sled, NULL, del); calc_charpos_cx(hWnd, sled, sled->editPos, &cur_editpos_x); edtSetCaretPos (hWnd, sled); scroll_len = old_editpos_x - cur_editpos_x; refresh_rc.left = refresh_rc.right - scroll_len; ScrollWindow(hWnd, -scroll_len, 0, &scroll_rc, NULL); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } } } else{//right scroll window while sled->nContX > 0 if (sled->selStart != sled->selEnd){ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.left = sled->rcVis.left; calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); if (sled->selStart < sled->selEnd){ scroll_rc.right = sel_end_x + 1 - sled->nContX; } else{ scroll_rc.right = sel_start_x + 1 - sled->nContX; } scroll_rc.left = sled->rcVis.left; sleInsertText_refresh (hWnd, sled, NULL, del); scroll_len = abs(sel_start_x - sel_end_x); refresh_rc.right = refresh_rc.left + scroll_len; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); edtSetCaretPos (hWnd, sled); InvalidateRect(hWnd, &refresh_rc, TRUE); if (scroll_len >= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } if (sled->nContX <= 0){ InvalidateRect(hWnd, NULL, TRUE); } } else{ refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; refresh_rc.left = sled->rcVis.left; old_caret_x = get_caretpos_x(hWnd); scroll_rc.left = sled->rcVis.left; sleInsertText_refresh (hWnd, sled, NULL, del); edtSetCaretPos (hWnd, sled); cur_caret_x = get_caretpos_x(hWnd); scroll_rc.right = cur_caret_x; scroll_len = cur_caret_x - old_caret_x; refresh_rc.right = refresh_rc.left + abs(scroll_len); ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); InvalidateRect(hWnd, &refresh_rc, TRUE); if (sled->nContW <= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } if (sled->nContX <= 0){ InvalidateRect(hWnd, NULL, TRUE); } } } } sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); } static void esleft_del_refresh(HWND hWnd, PSLEDITDATA sled, int del) { int old_nContX = sled->nContX; RECT scroll_rc, del_rc, refresh_rc; int txtlen_x; int sel_start_x, sel_end_x; int old_caret_x, cur_caret_x; int scroll_len; scroll_rc.top = sled->rcVis.top; scroll_rc.bottom = sled->rcVis.bottom; del_rc.bottom = sled->rcVis.bottom; del_rc.top = sled->rcVis.top; refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; if (sled->selStart != sled->selEnd){ if (sled->selStart < sled->selEnd){ calc_charpos_cx(hWnd, sled, sled->selEnd, &sel_end_x); scroll_rc.left = sel_end_x; } else{ calc_charpos_cx(hWnd, sled, sled->selStart, &sel_start_x); scroll_rc.left = sel_start_x; } scroll_rc.right = sled->rcVis.right; } else{ calc_charpos_cx(hWnd, sled, sled->editPos, &scroll_rc.left); scroll_rc.left = scroll_rc.left - old_nContX; scroll_rc.right = sled->rcVis.right; } old_caret_x = get_caretpos_x(hWnd); calc_charpos_cx(hWnd, sled, sled->content.txtlen, &txtlen_x); sleInsertText_refresh (hWnd, sled, NULL, del); calc_charpos_cx(hWnd, sled, sled->editPos, &del_rc.left); del_rc.left = del_rc.left - old_nContX; del_rc.right = scroll_rc.left; scroll_len = del_rc.left - scroll_rc.left; if (abs(sel_start_x - sel_end_x) >= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } else{ if ((old_nContX > 0) && ((txtlen_x - old_nContX) <= sled->rcVis.right)){ cur_caret_x = get_caretpos_x(hWnd); if (cur_caret_x != old_caret_x){ scroll_len = cur_caret_x - old_caret_x; scroll_rc.left = sled->rcVis.left; scroll_rc.right = old_caret_x; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = old_caret_x; refresh_rc.right = cur_caret_x; InvalidateRect(hWnd, &refresh_rc, TRUE); } else if (sled->selStart != sled->selEnd) { scroll_len = sel_start_x - sel_end_x; scroll_rc.left = sled->rcVis.left; scroll_rc.right = old_caret_x; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = old_caret_x; refresh_rc.right = cur_caret_x; InvalidateRect(hWnd, &refresh_rc, TRUE); } else{ InvalidateRect(hWnd, NULL, TRUE); } } else{ int rl; InvalidateRect(hWnd, &del_rc, TRUE); ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); calc_charpos_cx(hWnd, sled, sled->content.txtlen, &rl); if (((sled->nContW - sled->nContX) == sled->nVisW) && (old_nContX > 0)){ InvalidateRect(hWnd, NULL, TRUE); } else if (rl < sled->nVisW){ refresh_rc.left = rl; refresh_rc.right = sled->rcVis.right; InvalidateRect(hWnd, &refresh_rc, TRUE); } else{ refresh_rc.left = sled->rcVis.right - abs(scroll_len); refresh_rc.right = sled->rcVis.right; InvalidateRect(hWnd, &refresh_rc, TRUE); } } } } static int sleKeyDown (HWND hWnd, WPARAM wParam, LPARAM lParam) { BOOL bChange = FALSE; DWORD dwStyle = GetWindowStyle (hWnd); PCONTROL pCtrl = gui_Control(hWnd); PSLEDITDATA sled = (PSLEDITDATA) (pCtrl->dwAddData2); switch (LOWORD (wParam)) { case SCANCODE_KEYPADENTER: case SCANCODE_ENTER: NotifyParent (hWnd, pCtrl->id, EN_ENTER); return 0; case SCANCODE_HOME: { BOOL refresh = FALSE; if(lParam & KS_SHIFT) { make_pos_visible (hWnd, sled, sled->startx); sled->selStart = 0; sled->selEnd = sled->editPos; check_caret(); //InvalidateRect (hWnd, NULL, TRUE); InvalidateRect (hWnd, &sled->rcVis, TRUE); NotifyParent (hWnd, pCtrl->id, EN_SELCHANGED); return 0; } if (sled->selStart != sled->selEnd) { ShowCaret(hWnd); refresh = TRUE; } sled->editPos = 0; sled->selStart = sled->selEnd = 0; if (!edtSetCaretPos (hWnd, sled) && refresh) //InvalidateRect (hWnd, NULL, TRUE); InvalidateRect (hWnd, &sled->rcVis, TRUE); return 0; } case SCANCODE_END: { BOOL refresh = FALSE; if(lParam & KS_SHIFT) { sled->selStart = sled->editPos; sled->selEnd = sled->content.txtlen; check_caret(); make_charpos_visible (hWnd, sled, sled->selEnd, NULL); InvalidateRect(hWnd, NULL, TRUE); NotifyParent (hWnd, pCtrl->id, EN_SELCHANGED); return 0; } if (sled->selStart != sled->selEnd) { ShowCaret(hWnd); refresh = TRUE; } sled->editPos = sled->content.txtlen; sled->selStart = sled->selEnd = sled->editPos; if (!edtSetCaretPos (hWnd, sled) && refresh) InvalidateRect (hWnd, NULL, TRUE); return 0; } case SCANCODE_CURSORBLOCKLEFT: { BOOL refresh = FALSE; if(lParam & KS_SHIFT) { if (sled->selStart == sled->selEnd) { sled->selStart = sled->selEnd = sled->editPos; } if (sled->selStart < sled->editPos || sled->selStart == sled->selEnd) { if (sled->selStart > 0) shift_one_char_l(selStart); } else { shift_one_char_l(selEnd); } check_caret (); make_charpos_visible (hWnd, sled, sled->selStart, NULL); InvalidateRect (hWnd, NULL, TRUE); NotifyParent (hWnd, pCtrl->id, EN_SELCHANGED); return 0; } if (sled->selStart != sled->selEnd) { if (sled->editPos != sled->selEnd) sled->editPos = sled->selEnd; else sled->editPos = sled->selStart; } if (sled->editPos > 0) { shift_one_char_l (editPos); } if (sled->selStart != sled->selEnd) { ShowCaret (hWnd); ActiveCaret (hWnd); refresh = TRUE; } sled->selStart = sled->selEnd = sled->editPos; if (!edtSetCaretPos (hWnd, sled) && refresh) { InvalidateRect (hWnd, NULL, TRUE); } return 0; } case SCANCODE_CURSORBLOCKRIGHT: { BOOL refresh = FALSE; if(lParam & KS_SHIFT) { if(sled->selStart == sled->selEnd) sled->selStart = sled->selEnd = sled->editPos; if (sled->selStart == sled->selEnd || sled->selEnd > sled->editPos) { if (sled->selEnd < sled->content.txtlen) shift_one_char_r (selEnd); } else { shift_one_char_r (selStart); } check_caret (); make_charpos_visible (hWnd, sled, sled->selEnd, NULL); InvalidateRect (hWnd, NULL, TRUE); NotifyParent (hWnd, pCtrl->id, EN_SELCHANGED); return 0; } if (sled->selStart != sled->selEnd) { if (sled->editPos != sled->selEnd) sled->editPos = sled->selEnd; else sled->editPos = sled->selStart; } if (sled->editPos < sled->content.txtlen) { shift_one_char_r (editPos); } if (sled->selStart != sled->selEnd) { ShowCaret (hWnd); ActiveCaret (hWnd); refresh = TRUE; } sled->selStart = sled->selEnd = sled->editPos; if (!edtSetCaretPos (hWnd, sled) && refresh) InvalidateRect (hWnd, NULL, TRUE); } return 0; case SCANCODE_REMOVE: { int del; int oldpos = sled->editPos; if ((dwStyle & ES_READONLY)) return 0; if (sled->editPos == sled->content.txtlen && sled->selStart == sled->selEnd) return 0; if (sled->selStart == sled->selEnd && sled->editPos < sled->content.txtlen) { shift_one_char_r(editPos); } del = oldpos - sled->editPos; if (dwStyle & ES_LEFT) { esleft_del_refresh(hWnd, sled, del); if (!edtSetCaretPos (hWnd, sled)) { InvalidateRect (hWnd, NULL, TRUE); } sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); } else if (dwStyle & ES_RIGHT) { esright_del_refresh(hWnd, sled, del); //sleInsertText (hWnd, sled, NULL, del); } else if (dwStyle & ES_CENTER) { sleInsertText (hWnd, sled, NULL, del); } else { sleInsertText (hWnd, sled, NULL, del); } } break; case SCANCODE_BACKSPACE: { int del; if (dwStyle & ES_READONLY) return 0; if (sled->editPos == 0 && sled->selStart == sled->selEnd) return 0; del = - CHLENPREV( sled->content.string, (sled->content.string + sled->editPos) ); sleInsertText (hWnd, sled, NULL, del); } break; case SCANCODE_A: { if (lParam & KS_CTRL) { sleSetSel (hWnd, sled, 0, sled->content.txtlen); } return 0; } #ifdef _MGHAVE_CLIPBOARD case SCANCODE_C: case SCANCODE_X: { if ((lParam & KS_CTRL) && (sled->selEnd - sled->selStart > 0)) { SetClipBoardData (CBNAME_TEXT, sled->content.string + sled->selStart, sled->selEnd - sled->selStart, CBOP_NORMAL); if (wParam == SCANCODE_X && !(GetWindowStyle(hWnd) & ES_READONLY)) { sleInsertText (hWnd, sled, NULL, 0); } } return 0; } case SCANCODE_V: { if (!(lParam & KS_CTRL)) return 0; return sleInsertCbText (hWnd, sled); } #endif /* _MGHAVE_CLIPBOARD */ case SCANCODE_INSERT: sled->status ^= EST_REPLACE; break; default: break; } //end switch if (bChange){ sled->changed = TRUE; NotifyParent (hWnd, pCtrl->id, EN_CHANGE); } return 0; } static void esright_input_char_refresh (HWND hWnd, PSLEDITDATA sled, char *charBuffer, int chars) { RECT scroll_rc; int scroll_len; int old_ncontw, cur_ncontw; int cur_caret_x; if (sled->selStart != sled->selEnd) { sleInsertText (hWnd, sled, (char* )charBuffer, chars); } else {//left scroll window scroll_rc.top = sled->rcVis.top; scroll_rc.bottom = sled->rcVis.bottom; calc_content_width(hWnd, sled, sled->content.txtlen, &old_ncontw); sleInsertText_refresh (hWnd, sled, (char* )charBuffer, chars); calc_content_width(hWnd, sled, sled->content.txtlen, &cur_ncontw); scroll_len = abs(old_ncontw- cur_ncontw); cur_caret_x = get_caretpos_x(hWnd); scroll_rc.left = sled->rcVis.left; scroll_rc.right = cur_caret_x; ScrollWindow(hWnd, -scroll_len, 0, &scroll_rc, NULL); UpdateInvalidClient(hWnd, TRUE); edtSetCaretPos (hWnd, sled); sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); } } static void esleft_input_char_refresh (HWND hWnd, PSLEDITDATA sled, char *charBuffer, int chars) { int old_caretpos_x; int old_sel_start, old_sel_end; int old_sel_start_x, old_sel_end_x, cur_sel_start_x; RECT scroll_rc, refresh_rc; int scroll_len; int old_edit_pos_x, cur_edit_pos_x; int old_nContX; //char_size is width of input chars; sel_size is width of the selected area int char_size, sel_size; int txtlen_x; old_sel_start = sled->selStart; old_sel_end = sled->selEnd; old_caretpos_x = get_caretpos_x(hWnd); calc_charpos_cx(hWnd, sled, sled->editPos, &old_edit_pos_x); calc_charpos_cx(hWnd, sled, sled->content.txtlen, &txtlen_x); old_nContX= sled->nContX; calc_charpos_cx(hWnd, sled, old_sel_start, &old_sel_start_x); calc_charpos_cx(hWnd, sled, old_sel_end, &old_sel_end_x); old_sel_start_x = old_sel_start_x - sled->nContX; old_sel_end_x = old_sel_end_x - sled->nContX; sleInsertText_refresh (hWnd, sled, (char* )charBuffer, chars); calc_charpos_cx(hWnd, sled, sled->editPos, &cur_edit_pos_x); calc_charpos_cx(hWnd, sled, old_sel_start, &cur_sel_start_x); /* Not used var int cur_caretpos_x, cur_ncontx; cur_ncontx = sled->nContX; cur_caretpos_x = get_caretpos_x(hWnd); */ char_size = cur_edit_pos_x - cur_sel_start_x; sel_size = abs(old_sel_start_x - old_sel_end_x); scroll_rc.top = sled->rcVis.top; scroll_rc.bottom = sled->rcVis.bottom; refresh_rc.top = sled->rcVis.top; refresh_rc.bottom = sled->rcVis.bottom; if (char_size >= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } else{ if (old_sel_start != old_sel_end){ if (sel_size >= sled->nVisW){ InvalidateRect(hWnd, NULL, TRUE); } else{ if (char_size < sel_size){ //right scroll window if ((old_nContX > 0) && ((txtlen_x - old_nContX) <= sled->rcVis.right)) { scroll_len = sel_size - char_size; scroll_rc.left = sled->rcVis.left; scroll_rc.right = old_sel_start_x < old_sel_end_x ? old_sel_start_x : old_sel_end_x; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = scroll_rc.right; refresh_rc.right = refresh_rc.left + sel_size + scroll_len; InvalidateRect(hWnd, &refresh_rc, TRUE); } else{//left scroll window scroll_len = -(sel_size - char_size); scroll_rc.left = old_sel_start_x < old_sel_end_x ? old_sel_end_x : old_sel_start_x; scroll_rc.right = sled->rcVis.right; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = scroll_rc.left - sel_size; refresh_rc.right = scroll_rc.left; InvalidateRect(hWnd, &refresh_rc, TRUE); } } else{//when char_size > sel_size right scroll window scroll_len = char_size - sel_size; scroll_rc.left = old_sel_start_x < old_sel_end_x ? old_sel_end_x : old_sel_start_x; scroll_rc.right = sled->rcVis.right; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = scroll_rc.left - sel_size; refresh_rc.right = refresh_rc.left + char_size + 1; InvalidateRect(hWnd, &refresh_rc, TRUE); } } } else{ int right; char_size = cur_edit_pos_x - old_edit_pos_x; calc_charpos_cx(hWnd, sled, sled->content.txtlen, &right); if (old_caretpos_x < sled->rcVis.right){//right scroll window scroll_len = cur_edit_pos_x - old_edit_pos_x; if ((sled->rcVis.right - old_caretpos_x) < scroll_len){// scroll_len = -(scroll_len - (sled->rcVis.right- old_caretpos_x)); scroll_rc.left = sled->rcVis.left; scroll_rc.right = old_caretpos_x; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = sled->rcVis.right - char_size; refresh_rc.right = sled->rcVis.right; InvalidateRect(hWnd, &refresh_rc, TRUE); } else{ scroll_rc.left = old_caretpos_x; scroll_rc.right = (right < sled->rcVis.right) ? right+1 : sled->rcVis.right; ScrollWindow(hWnd, scroll_len, 0, &scroll_rc, NULL); refresh_rc.left = sled->rcVis.right - char_size; refresh_rc.right = sled->rcVis.right; InvalidateRect(hWnd, &refresh_rc, TRUE); } } else{//left scroll window scroll_len = old_edit_pos_x - cur_edit_pos_x; ScrollWindow(hWnd, scroll_len, 0, &sled->rcVis, NULL); refresh_rc.left = sled->rcVis.right - char_size; refresh_rc.right = sled->rcVis.right; InvalidateRect(hWnd, &refresh_rc, TRUE); } if (((sled->nContW - sled->nContX) == sled->nVisW) && (old_nContX > 0)){ InvalidateRect(hWnd, NULL, TRUE); } } } } static void sledit_refresh_caret (HWND hWnd, PSLEDITDATA sled, BOOL bInited) { DWORD dwStyle = GetWindowStyle(hWnd); SIZE txtsize; int outchar; HDC hdc; if (!sled) return; hdc= GetClientDC (hWnd); outchar = GetTextExtentPoint (hdc, (const char*)sled->content.string, sled->content.txtlen, 0, NULL, NULL, NULL, &txtsize); ReleaseDC (hdc); if (bInited) { if (dwStyle & ES_RIGHT) sled->editPos = outchar; else if (dwStyle & ES_CENTER) sled->editPos = outchar/2; else sled->editPos = 0; } if (!edtSetCaretPos (hWnd, sled)) { InvalidateRect (hWnd, NULL, TRUE); } } static int sledit_reset_text (HWND hWnd, PSLEDITDATA sled, char* str) { DWORD dwStyle = GetWindowStyle(hWnd); char* buffer = str; if (!sled || !buffer) return -1; if (dwStyle & ES_PASSWORD) { buffer = strdup (buffer); check_valid_passwd (buffer); } //we must retain the status of this control, it include is ETS_FOCUS state, that //tell this control whether the caret is need //sled->status = 0; sled->selStart = 0; sled->selEnd = 0; if (sled->content.string) { free (sled->content.string); sled->content.string = NULL; sled->content.buffsize = 0; sled->content.txtlen = 0; } sledit_settext (sled, buffer); recalcSize (hWnd, sled, TRUE); if (dwStyle & ES_PASSWORD) { free (buffer); } //sledit_refresh_caret (hWnd, sled, TRUE); sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_UPDATE); return 0; } static int sledit_insert_text (HWND hWnd, PSLEDITDATA sled, const char* newtext, int len) { int i, realen = strlen (newtext); char* tempstr; char* newbuffer; DWORD dwStyle = GetWindowStyle(hWnd); if (len > realen) len = realen; if (!newtext || len <= 0) return -1; if (dwStyle & ES_READONLY) { return 0; } tempstr = (char*) malloc(realen+1); for (i = 0; i < len && newtext[i] != '\0'; i ++) { if (dwStyle & ES_UPPERCASE) { tempstr[i] = toupper (newtext[i]); } else if (dwStyle & ES_LOWERCASE) { tempstr[i] = tolower (newtext[i]); } else tempstr[i] = newtext[i]; } newbuffer = tempstr; sleInsertText (hWnd, sled, (char* )newbuffer, len); free(tempstr); return 0; } static LRESULT SLEditCtrlProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { DWORD dwStyle; HDC hdc; PSLEDITDATA sled = NULL; PMAINWIN pWin = (PMAINWIN)hWnd; RECT rcCaret; dwStyle = GetWindowStyle(hWnd); if (message != MSG_CREATE) sled = (PSLEDITDATA) GetWindowAdditionalData2 (hWnd); switch (message) { case MSG_CREATE: if ( !(sled = calloc (1, sizeof (SLEDITDATA))) ) return -1; if (sledit_init (hWnd, sled) < 0) return -1; break; case MSG_DESTROY: sledit_destroy (hWnd, sled); free (sled); break; case MSG_PAINT: { hdc = BeginPaint (hWnd); slePaint (hWnd, hdc, sled); EndPaint (hWnd, hdc); if (sled->bShowCaret) ShowCaret (hWnd); else HideCaret (hWnd); return 0; } case MSG_SIZECHANGED: recalcSize (hWnd, sled, FALSE); return 0; case MSG_FONTCHANGING: if (dwStyle & ES_PASSWORD) return -1; return 0; case MSG_FONTCHANGED: { sled->starty = sled->topMargin + (sled->rcVis.bottom - sled->rcVis.top - GetWindowFont(hWnd)->size - 1)/2; DestroyCaret (hWnd); CreateCaret (hWnd, NULL, 1, GetWindowFont (hWnd)->size); recalcSize (hWnd, sled, FALSE); return 0; } case MSG_SETCURSOR: if (dwStyle & WS_DISABLED) { SetCursor (GetSystemCursor (IDC_ARROW)); return 0; } break; case MSG_KILLFOCUS: if (sled->status & EST_FOCUSED) { BOOL refresh = FALSE; sled->status &= ~EST_FOCUSED; //HideCaret (hWnd); if (pWin->pCaretInfo) { sled->bShowCaret = FALSE; SetRect (&rcCaret, pWin->pCaretInfo->x, pWin->pCaretInfo->y, pWin->pCaretInfo->x + pWin->pCaretInfo->nWidth, pWin->pCaretInfo->y + pWin->pCaretInfo->nHeight); InvalidateRect (hWnd, &rcCaret, FALSE); } if ( sled->selStart != sled->selEnd || (dwStyle & ES_TIP && sled->content.txtlen <= 0)) { refresh = TRUE; } if (sled->selStart != sled->selEnd && !(dwStyle & ES_NOHIDESEL)) { sled->selStart = sled->selEnd = sled->editPos; } if (refresh) InvalidateRect (hWnd, NULL, TRUE); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_KILLFOCUS); if (sled->changed){ sled->changed = FALSE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CONTCHANGED); } } break; case MSG_SETFOCUS: if (sled->status & EST_FOCUSED) break; sled->status |= EST_FOCUSED; /*[humingming/2010/10/19]:bug 5158: * don't draw the caret here, should in MSG_PAINT. */ ActiveCaret (hWnd); //ShowCaret(hWnd); if (pWin->pCaretInfo) { sled->bShowCaret = TRUE; SetRect (&rcCaret, pWin->pCaretInfo->x, pWin->pCaretInfo->y, pWin->pCaretInfo->x + pWin->pCaretInfo->nWidth, pWin->pCaretInfo->y + pWin->pCaretInfo->nHeight); InvalidateRect (hWnd, &rcCaret, FALSE); } if (dwStyle & ES_AUTOSELECT) { if (sleSetSel (hWnd, sled, 0, sled->content.txtlen) <= 0 && dwStyle & ES_TIP) InvalidateRect (hWnd, NULL, TRUE); if (lParam == 1) sled->status |= EST_TMP; } else if ( (dwStyle & ES_NOHIDESEL && sled->selStart != sled->selEnd) || (dwStyle & ES_TIP && sled->content.txtlen <= 0)) { InvalidateRect (hWnd, NULL, TRUE); } NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_SETFOCUS); break; case MSG_ENABLE: if ( (!(dwStyle & WS_DISABLED) && !wParam) || ((dwStyle & WS_DISABLED) && wParam) ) { if (wParam) ExcludeWindowStyle(hWnd,WS_DISABLED); else IncludeWindowStyle(hWnd,WS_DISABLED); InvalidateRect (hWnd, NULL, TRUE); } return 0; case MSG_GETTEXTLENGTH: return sled->content.txtlen; case MSG_GETTEXT: { char* buffer = (char*)lParam; int len; len = MIN ((int)wParam, sled->content.txtlen); memcpy (buffer, sled->content.string, len); buffer [len] = '\0'; return len; } case MSG_SETTEXT: return sledit_reset_text (hWnd, sled, (char*)lParam); case MSG_KEYDOWN: { return sleKeyDown (hWnd, wParam, lParam); } case MSG_UTF8CHAR: _ERR_PRINTF ("CONTROL>EDIT: MSG_UTF8CHAR is not implemented.\n"); break; case MSG_CHAR: { unsigned char charBuffer [4]; int chars; if (dwStyle & ES_READONLY) return 0; charBuffer [0] = FIRSTBYTE (wParam); charBuffer [1] = SECONDBYTE (wParam); charBuffer [2] = THIRDBYTE (wParam); charBuffer [3] = FOURTHBYTE (wParam); if (charBuffer [3]) { chars = 4; } else if (charBuffer [2]) { chars = 3; } else if (charBuffer [1]) { chars = 2; } else { chars = 1; if (dwStyle & ES_UPPERCASE) { charBuffer [0] = toupper (charBuffer[0]); } else if (dwStyle & ES_LOWERCASE) { charBuffer [0] = tolower (charBuffer[0]); } } if (chars == 1 && (charBuffer[0] == '\b' || charBuffer[0] == 0x7F)) { // ASCII BS or DEL int del; if (sled->editPos == 0 && sled->selStart == sled->selEnd) return 0; del = -CHLENPREV((const char *)(sled->content.string), (sled->content.string + sled->editPos) ); if (dwStyle & ES_LEFT) { esleft_del_refresh(hWnd, sled, del); set_edit_caret_pos(hWnd, sled); sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); } else if (dwStyle & ES_RIGHT) { esright_backspace_refresh(hWnd, sled, del); } else if (dwStyle & ES_CENTER) { sleInsertText (hWnd, sled, NULL, del); } else { sleInsertText (hWnd, sled, NULL, del); } } else if (chars == 1 && charBuffer [0] < 0x20) { // ignore all other ASCII control characters. return 0; } else { if (dwStyle & ES_LEFT) { esleft_input_char_refresh(hWnd, sled, (char*)charBuffer, chars); set_edit_caret_pos(hWnd, sled); sled->changed = TRUE; NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CHANGE); } else if (dwStyle & ES_RIGHT) { esright_input_char_refresh(hWnd, sled, (char*)charBuffer, chars); } else if (dwStyle & ES_CENTER) { sleInsertText (hWnd, sled, (char* )charBuffer, chars); } else { sleInsertText (hWnd, sled, (char* )charBuffer, chars); } } return 0; } case MSG_LBUTTONDBLCLK: sleSetSel (hWnd, sled, 0, sled->content.txtlen); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_DBLCLK); break; case MSG_LBUTTONDOWN: { if ( sled->status & EST_TMP) { sled->status &= ~EST_TMP; break; } if (HISWORD(lParam) < sled->rcVis.top || HISWORD(lParam) > sled->rcVis.bottom) break; set_caret_pos (hWnd, sled, LOSWORD(lParam), FALSE); ActiveCaret (hWnd); ShowCaret(hWnd); SetCapture(hWnd); InvalidateRect(hWnd, NULL, TRUE); break; } case MSG_NCLBUTTONUP: case MSG_LBUTTONUP: if (GetCapture() == hWnd) ReleaseCapture(); NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_CLICKED); if (sled->selStart != sled->selEnd) NotifyParent (hWnd, GetDlgCtrlID(hWnd), EN_SELCHANGED); break; case MSG_MOUSEMOVE: { if (GetCapture () == hWnd) sleMouseMove (hWnd, sled, lParam); return 0; } case MSG_GETDLGCODE: return DLGC_WANTCHARS| DLGC_HASSETSEL| DLGC_WANTARROWS| DLGC_WANTENTER; case MSG_DOESNEEDIME: if (dwStyle & ES_READONLY) return IME_WINDOW_TYPE_READONLY; else if (dwStyle & ES_PASSWORD) return IME_WINDOW_TYPE_PASSWORD; else return IME_WINDOW_TYPE_EDITABLE; case EM_GETCARETPOS: case EM_GETSELPOS: { int nr_chars, pos; int* line_pos = (int *)wParam; int* char_pos = (int *)lParam; if (message == EM_GETSELPOS) pos = (sled->editPos == sled->selStart) ? sled->selEnd : sled->selStart; else pos = sled->editPos; nr_chars = GetTextMCharInfo (GetWindowFont (hWnd), (const char* )(sled->content.string), pos, NULL); if (line_pos) *line_pos = 0; if (char_pos) *char_pos = nr_chars; return pos; } case EM_SETCARETPOS: case EM_SETSEL: { int char_pos = (int)lParam; int nr_chars, pos; int *pos_chars; if (char_pos < 0) return -1; pos_chars = ALLOCATE_LOCAL (sled->content.txtlen * sizeof(int)); nr_chars = GetTextMCharInfo (GetWindowFont (hWnd), (const char* )sled->content.string, sled->content.txtlen, pos_chars); if (char_pos > nr_chars) { DEALLOCATE_LOCAL (pos_chars); return -1; } if (char_pos == nr_chars) pos = sled->content.txtlen; else pos = pos_chars[char_pos]; DEALLOCATE_LOCAL (pos_chars); if (message == EM_SETCARETPOS) { sled->editPos = pos; sled->selStart = sled->selEnd = 0; edtSetCaretPos (hWnd, sled); return sled->editPos; } else { int start, end; if (sled->editPos < pos) { start = sled->editPos; end = pos; } else { start = pos; end = sled->editPos; } return sleSetSel (hWnd, sled, start, end); } } case EM_INSERTTEXT: { return sledit_insert_text (hWnd, sled, (const char*)lParam, wParam); } case EM_SETREADONLY: if (wParam) IncludeWindowStyle (hWnd, ES_READONLY); else ExcludeWindowStyle (hWnd, ES_READONLY); return 0; case EM_SETPASSWORDCHAR: if (sled->passwdChar != (int)wParam) { sled->passwdChar = (int)wParam; if (dwStyle & ES_PASSWORD) { InvalidateRect (hWnd, NULL, TRUE); } } return 0; case EM_GETPASSWORDCHAR: { if (lParam) *((int*)lParam) = sled->passwdChar; return 0; } case EM_GETMAXLIMIT: return sled->hardLimit; case EM_LIMITTEXT: { int newLimit = (int)wParam; if (newLimit >= 0) { if (sled->content.txtlen > newLimit) { Ping (); return -1; } else { sled->hardLimit = newLimit; return 0; } } return -1; } case EM_GETTIPTEXT: { int len, tip_len; char *buffer = (char *)lParam; if (!(dwStyle & ES_TIP)) return -1; tip_len = strlen (sled->tiptext); if (!buffer) return tip_len; if (wParam >= 0) len = (wParam > DEF_TIP_LEN) ? DEF_TIP_LEN : wParam; else len = DEF_TIP_LEN; strncpy (buffer, sled->tiptext, len); buffer[len] = '\0'; return tip_len; } case EM_SETTIPTEXT: { int len; if (!(dwStyle & ES_TIP) || !lParam) return -1; if (wParam >= 0) len = (wParam > DEF_TIP_LEN) ? DEF_TIP_LEN : wParam; else len = DEF_TIP_LEN; strncpy (sled->tiptext, (char *)lParam, len); sled->tiptext[len] = '\0'; if (sled->content.txtlen <= 0) InvalidateRect (hWnd, NULL, TRUE); return strlen(sled->tiptext); } case EM_GETSEL: { char *buffer = (char *)lParam; int len; if (!buffer || sled->selEnd - sled->selStart <= 0) return 0; if (wParam < 0) len = sled->selEnd - sled->selStart; else len = MIN(sled->selEnd - sled->selStart, (int)wParam); strncpy (buffer, (const char*)(sled->content.string + sled->selStart), len); return len; } case EM_INSERTCBTEXT: { #ifdef _CLIPBOAR_SUPPORT return sleInsertCbText (hWnd, sled); #endif } case EM_COPYTOCB: case EM_CUTTOCB: { #ifdef _MGHAVE_CLIPBOARD if (sled->selEnd - sled->selStart > 0) { SetClipBoardData (CBNAME_TEXT, sled->content.string + sled->selStart, sled->selEnd - sled->selStart, CBOP_NORMAL); if (message == EM_CUTTOCB && !(GetWindowStyle(hWnd) & ES_READONLY)) { sleInsertText (hWnd, sled, NULL, 0); } return sled->selEnd - sled->selStart; } #endif return 0; } default: break; } // end switch return DefaultControlProc (hWnd, message, wParam, lParam); } #endif /* _MGCTRL_SLEDIT */