|
|
/*************************************************
* movelst.c * * * * Copyright (C) 1995-1999 Microsoft Inc. * * * *************************************************/
#include <windows.h> // required for all Windows applications
#include <windowsx.h>
#include <stdlib.h>
#include <memory.h>
#include <tchar.h>
#include <htmlhelp.h>
#include "rc.h"
#include "movelst.h"
#include "lctool.h"
#define HELPNAME _TEXT("LCTOOL.CHM")
//Bug #19911
//#define SEQHELPKEY _TEXT("���ܦr������")
#define ID_TIMER 100
#define LINE_WIDTH 1
// style flags for the DrawIndicator() function
#define DI_TOPERASED 0x0001 // erasing a line drawn on the top of the list
#define DI_BOTTOMERASED 0x0002 // erasing a line drawn on the bottom of the list
#define DI_ERASEICON 0x0004 // erasing the icon
static UINT idTimer; // the id for the timer used in scrolling the list
static HFONT hFont; // a new font for the list box
static HCURSOR hCurDrag; // a cursor to indicate dragging
static int nHtItem; // the height of an individual item in the list box
static BOOL bNoIntegralHeight; // does the list box have the LBS_NOINTEGRALHEIGHT style flag
static HWND ghDlg; // handle to the main window
static HWND ghList; // handle to the list box
static HBRUSH ghBrush; // handle to the brush with the color of the windows background
static UINT iCurrentAddr;
void DrawIndicator(HDC hDC, int nYpos, int nWidth, WORD wFlags); WNDPROC lpfnOldListProc, LstProc; BOOL lcRemoveDup( TCHAR *szBuf ); void lcOrgEditWindow();
BOOL lcDisp2Seq( HWND hDlg, UINT iAddr, TCHAR *szDispBuf) { UINT i,j,len; #ifdef UNICODE
TCHAR szPhrase[SEGMENT_SIZE * 2]; #else
UCHAR szPhrase[SEGMENT_SIZE * 2]; #endif
int nRet;
// remove duplicate phrase
if(lcRemoveDup(szDispBuf) && iAddr < MAX_LINE){ SendMessage(hwndPhrase[iAddr],WM_SETTEXT,0, (LPARAM)(LPCTSTR)szDispBuf); }
len=lstrlen(szDispBuf)+1; if((szDispBuf[len-1] == _TEXT(' ')) && (len > 1)) { szDispBuf[len-1]=0; len--; } if(len >= MAX_CHAR_NUM) { //tang must fix
szDispBuf[MAX_CHAR_NUM-1]=0; #ifndef UNICODE
if(is_DBCS_1st(szDispBuf, MAX_CHAR_NUM-2)) szDispBuf[MAX_CHAR_NUM-2]=' '; #endif
len=MAX_CHAR_NUM; }
i = 0; j = 0; for(;;) { if (i == len - 1) { if (i - j + 1 > 0) { lstrcpyn(szPhrase, &szDispBuf[j], i - j + 1); SendDlgItemMessage(hDlg,IDD_SOURCELIST, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szPhrase); } break; } if (szDispBuf[i] == ' ') { lstrcpyn(szPhrase, &szDispBuf[j], i - j + 1); nRet = (int)SendDlgItemMessage(hDlg, IDD_SOURCELIST, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szPhrase); j = i + 1; } i++; } return TRUE; }
BOOL lcSeq2Disp( HWND hDlg, UINT iAddr, TCHAR *szDispBuf) { WORD nCount; TCHAR szPhrase[SEGMENT_SIZE * 2]; int nRet; WORD i;
nCount = (int)SendDlgItemMessage(hDlg,IDD_SOURCELIST, LB_GETCOUNT, 0, 0); if (nCount == LB_ERR) return FALSE;
*szDispBuf = 0; for(i = 0; i < nCount; i++) { nRet = (int)SendDlgItemMessage(hDlg, IDD_SOURCELIST, LB_GETTEXT, (WPARAM)i, (LPARAM)(LPSTR)szPhrase); if (nRet == LB_ERR) return FALSE;
lstrcat(szDispBuf, szPhrase); lstrcat(szDispBuf, _TEXT(" ")); }
SendMessage(hwndPhrase[iAddr],WM_SETTEXT,0, (LPARAM)(LPCTSTR)szDispBuf); SendMessage(hwndPhrase[iAddr], EM_SETMODIFY, TRUE, 0);
return TRUE; }
void lcChangeSequence( HWND hwnd) { int is_OK; BOOL is_WORD; iCurrentAddr=lcGetEditFocus(GetFocus(), &is_WORD); is_OK=(INT)DialogBox(hInst, _TEXT("SEQDIALOG"), hwndMain, ActualDlgProc);
if (is_WORD) SetFocus(hwndWord[iCurrentAddr]); else SetFocus(hwndPhrase[iCurrentAddr]);
if (is_OK) { bSaveFile = TRUE; lcSaveEditText(iDisp_Top, 0); lcOrgEditWindow(); } }
INT_PTR CALLBACK ClassDlgProc(HWND hDlg, UINT message, WPARAM wParam , LPARAM lParam) { return DefDlgProc(hDlg, message, wParam, lParam); } INT_PTR CALLBACK ActualDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { TCHAR szStr[MAX_CHAR_NUM]; BOOL bRet;
switch (message) { case WM_INITDIALOG: { LOGFONT lf; HMENU hSysMenu; // handle to the system menu
HDC hdc; // a dc to find out the number of pixels per logcal inch
LOGBRUSH lb; lb.lbStyle = BS_SOLID; lb.lbColor = GetSysColor(COLOR_WINDOW); lb.lbHatch = 0; ghBrush = CreateBrushIndirect(&lb); hSysMenu = GetSystemMenu(hDlg, FALSE); // disable the "maximize" option in the system menu
EnableMenuItem(hSysMenu, 4, MF_GRAYED|MF_DISABLED|MF_BYPOSITION); // disable the "size" option of the system menu
EnableMenuItem(hSysMenu, 2, MF_GRAYED|MF_DISABLED|MF_BYPOSITION);
SendMessage(hwndPhrase[iCurrentAddr], WM_GETTEXT, MAX_CHAR_NUM-1, (LPARAM)szStr); lcDisp2Seq(hDlg, iCurrentAddr, szStr); ghList = GetDlgItem(hDlg, IDD_SOURCELIST); LstProc = MakeProcInstance(NewListProc,hInst); lpfnOldListProc = (WNDPROC)SetWindowLongPtr(ghList, GWLP_WNDPROC, (LONG_PTR)LstProc); // check to see if it has integral height
bNoIntegralHeight = FALSE; hdc = GetDC(hDlg); memset(&lf, 0, sizeof(lf)); lf.lfHeight = -MulDiv(9, 96, 72); lstrcpy(lf.lfFaceName, _TEXT("MS Sans Serif")); hFont = CreateFontIndirect(&lf); ReleaseDC(hDlg, hdc); SendMessage(ghList, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE); // the drag cursor
hCurDrag = LoadCursor(hInst, _TEXT("IDC_DRAG")); return FALSE; // didn't set the focus
} break; case WM_COMMAND: switch (wParam) { case IDCANCEL: EndDialog(hDlg, FALSE); break; case IDOK: bRet = lcSeq2Disp(hDlg, iCurrentAddr, szStr); EndDialog(hDlg, bRet); break; case ID_HELP: LoadString(hInst, IDS_CHANGEWORDORDER, szStr, sizeof(szStr)/sizeof(TCHAR)); // WinHelp(hDlg, HELPNAME, HELP_PARTIALKEY, (DWORD)szStr);
HtmlHelp(hDlg, HELPNAME, HH_DISPLAY_TOPIC, 0L); break; } return TRUE;
case WM_DESTROY: // clean up
{ DeleteObject(ghBrush); DeleteObject(hFont); DestroyCursor(hCurDrag); } break; default: return FALSE; // we didn't do anyting
} // end switch message
return TRUE; // we did the processing
}
INT_PTR CALLBACK NewListProc(HWND hwndList, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bTracking = FALSE; static BOOL bDrag = FALSE; static HCURSOR hCursorOld = NULL;
switch (message) { case WM_CANCELMODE: // WM_CANCELMODE is sent to the window that has captured the mouse before
// a message box or modal dialog is displayed. If we were dragging the item
// cancel the drag.
bTracking = FALSE; ReleaseCapture(); if (bDrag) SetCursor(hCursorOld); break; case WM_LBUTTONDOWN: { // Was the list box item dragged into the destination?
BOOL bDragSuccess = FALSE; MSG msg; POINTS pts; POINTS points; POINT pt; POINT point; RECT rectIsDrag; // Rectangle to determine if dragging has started.
int nOldPos; int nOldY = -1; // the last place that we drew on
HDC hdc; // dc to draw on
div_t divt; // get remainder a quotient with "div"
int nCount; div_t divVis; // space for scroll bar - starts off at 1 so we don't overwrite the border
int dxScroll = 1; RECT rect; int nVisible; // the number of items visible
int idTimer1; // id for the timer
int nNewPos; // the new position
int nTopIndex; // the top index
GetWindowRect(hwndList, &rect); // Pass the WM_LBUTTONDOWN to the list box window procedure. Then
// fake a WM_LBUTTONUP so that we can track the drag.
CallWindowProc(lpfnOldListProc, hwndList, message, wParam, lParam); // the number of items in the list box
nCount = (int)SendMessage(hwndList, LB_GETCOUNT,0,0L); if (nCount == 0 ) // don't do anything to and empty list box
return 0; // fake the WM_LBUTTONUP
CallWindowProc(lpfnOldListProc, hwndList, WM_LBUTTONUP, wParam, lParam); // get a dc to draw on
hdc = GetDC(hwndList); // the height of each item
nHtItem = (int)SendMessage(hwndList, LB_GETITEMHEIGHT,0,0L); // the current item
nOldPos = (int)SendMessage(hwndList, LB_GETCURSEL,0,0L); divVis = div((rect.bottom - rect.top), nHtItem); // the number of visible items
nVisible = divVis.quot; // some items are invisible - there must be scroll bars - we don't want
// to draw on them
if (nVisible < nCount) dxScroll = GetSystemMetrics(SM_CXVSCROLL) + 1; idTimer1 = 0; idTimer1 = (UINT)SetTimer(hwndList, ID_TIMER,100,NULL); // Create a tiny rectangle to determine if item was dragged or merely clicked on.
// If the user moves outside this rectangle we assume that the dragging has
// started.
points = MAKEPOINTS(lParam); point.x = points.x; point.y = points.y; SetRect(&rectIsDrag, point.x, point.y - nHtItem / 2, point.x, point.y + nHtItem / 2); bTracking = TRUE; SetCapture(hwndList); // Drag loop
while (bTracking) { // Retrieve mouse, keyboard, and timer messages. We retrieve keyboard
// messages so that the system queue is not filled by keyboard messages
// during the drag (This can happen if the user madly types while dragging!)
// If none of these messages are available we wait. Both PeekMessage()
// and Waitmessage() will yield to other apps.
while (!PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) && !PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE) && !PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE)) WaitMessage(); switch(msg.message) { case WM_MOUSEMOVE: { pts = MAKEPOINTS(msg.lParam); pt.x = pts.x; pt.y = pts.y; if (!bDrag) { // Check if the user has moved out of the Drag rect.
// in the vertical direction. This indicates that
// the drag has started.
if ( (pt.y > rectIsDrag.bottom) || (pt.y < rectIsDrag.top)) // !PtInRect(&rectIsDrag,pt))
{ hCursorOld = SetCursor(hCurDrag); bDrag = TRUE; // Drag has started
} } if (bDrag) { SetCursor(hCurDrag); // if we are above or below the list box, then we are scrolling it, and
// we shouldn't be drawing here
ClientToScreen(hwndList, &pt); if ((pt.y >= rect.top) && (pt.y <= rect.bottom)) { // convert the point back to client coordinates
ScreenToClient(hwndList, &pt); divt = div(pt.y,nHtItem); // if we are half way to the item
// AND it is a new item
// AND we are not past the end of the list..
if ( divt.rem < nHtItem / 2 && (nOldY != nHtItem * divt.quot) && (divt.quot < nCount + 1)) { if (nOldY != -1) { // erase the old one
DrawIndicator(hdc, nOldY,(rect.right - rect.left) - dxScroll, DI_ERASEICON); } nOldY = nHtItem * divt.quot; DrawIndicator(hdc, nOldY,(rect.right - rect.left) - dxScroll, 0); } } // end if in the list box window
} // end if bDrag
} break; case WM_TIMER: { POINT pt1; GetCursorPos(&pt1); nTopIndex = (int)SendMessage(hwndList, LB_GETTOPINDEX,0,0L);; if (pt1.y < rect.top) // scroll up
{ if (nTopIndex > 0) { nTopIndex--; SendMessage(hwndList, LB_SETTOPINDEX, nTopIndex,0L); // when you scroll up, the line always stays on the top index
// erase the one we've moved down
DrawIndicator(hdc, nHtItem,(rect.right - rect.left) - dxScroll, DI_TOPERASED|DI_ERASEICON); // draw the new one
DrawIndicator(hdc, 0,(rect.right - rect.left) - dxScroll, 0); // the new one was drawn at y = 0
nOldY = 0; } } else if (pt1.y > rect.bottom) // scroll down
{ // if the number of visible items (ie seen in the list box)
// plus the number above the list is less than the total number
// of items, then we need to scroll down
if (nVisible + nTopIndex < nCount) { if (nOldY - nTopIndex != nVisible) { // if them move below the list REALLY REALLY FAST, then
// the last line will not be on the bottom - so we want to reset the last
// line to be the bottom
// erase the old line
DrawIndicator(hdc, nOldY,(rect.right - rect.left) - dxScroll, DI_ERASEICON); // reset the index
divt.quot = nVisible; nOldY = divt.quot * nHtItem; // draw the new line
DrawIndicator(hdc, nOldY,(rect.right - rect.left) - dxScroll, 0); } // scroll up
nTopIndex++; SendMessage(hwndList, LB_SETTOPINDEX, nTopIndex,0L); // erase the line that has moved up..
DrawIndicator(hdc, nOldY - nHtItem,(rect.right - rect.left) - dxScroll, DI_BOTTOMERASED|DI_ERASEICON); // draw the new one
DrawIndicator(hdc, nOldY,(rect.right - rect.left) - dxScroll, 0); } } } break; case WM_LBUTTONUP: // End of Drag
nTopIndex = (int)SendMessage(hwndList, LB_GETTOPINDEX, 0, 0L); if (bDrag) { // get rid of any line we've drawn - the position of the line
// divided by the height of the itme is where our new index
// is going to be
DrawIndicator(hdc, nOldY,(rect.right - rect.left) - dxScroll, DI_ERASEICON); nNewPos = (nOldY / nHtItem) + nTopIndex; // the old position can't equal the new one
if (nNewPos != nOldPos) bDragSuccess = TRUE; } bTracking = FALSE; break; default: // Process the keyboard messages
TranslateMessage(&msg); DispatchMessage(&msg); break; } }// end while bTracking
ReleaseCapture(); if (bDrag) { SetCursor(hCursorOld); // move the item
if (bDragSuccess) { int nIndex; char s[256]; // we need to store the top index, because deleting and adding a new
// string will change it, and we want to be able to see the item that
// we have moved
nTopIndex = (int)SendMessage(hwndList, LB_GETTOPINDEX,0,0L); // stop most of the blinking..
SendMessage(hwndList, WM_SETREDRAW, FALSE,0L); // get the text of the item - limited to 256 chars!
SendMessage(hwndList, LB_GETTEXT, nOldPos, (LPARAM)(LPSTR)s); /*------------------------------------------------------------------------
| strategy: given ABCD and moving to BCAD do the following: | | 1. delete A -- giving BCD | 2. insert A -- giving BCAD | 3. hilite A | 4. set the top index so A is visible -------------------------------------------------------------------------*/ // delete the original string
SendMessage(hwndList, LB_DELETESTRING, nOldPos, 0L); // if we've moved DOWN the list subtract one from the new index
// (because we've deleted a string but if we are moving UP the list,
// we don't subtract anything (the deleted item is below the new item,
// so our new index hasn't changed
if (nNewPos > nOldPos) nNewPos--; // put it in the new pos
nIndex = (int)SendMessage(hwndList, LB_INSERTSTRING, nNewPos, (LPARAM)(LPSTR)s); SendMessage(hwndList, LB_SETCURSEL, nIndex, 0L); SendMessage(hwndList, LB_SETTOPINDEX, nTopIndex,0L); SendMessage(hwndList, WM_SETREDRAW, TRUE,0L); } // end if bDragSuccess
} // end if bDrag
bDrag = FALSE; ReleaseDC(hwndList, hdc); KillTimer(hwndList, idTimer1); } break; default: return CallWindowProc(lpfnOldListProc, hwndList, message, wParam, lParam); } return 0; }
INT_PTR CALLBACK AboutDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) { case WM_INITDIALOG: return (TRUE); case WM_COMMAND: if (wParam == IDOK) { EndDialog(hDlg, TRUE); return (TRUE); } break; } return (FALSE);
}
void DrawIndicator(HDC hDC, int nYpos, int nWidth, WORD wFlags) {
// draw a horizontal line
int nTop, nHeight; HICON hIcon; HRGN hClipRgn; // the clipping region
RECT rect;
// we don't want the clip anything when we are drawing
// the icon outside the list box
SelectClipRgn(hDC, NULL); if (wFlags & DI_ERASEICON) { rect.left = -33; rect.right = -1; rect.top = nYpos -16; rect.bottom = nYpos + 16; // ghBrush is created in WM_INITDIALOG
FillRect(hDC, &rect, ghBrush); } else { hIcon = LoadIcon(hInst, _TEXT("IDI_ARROW")); if (hIcon) { DrawIcon(hDC,-33,nYpos - 16,hIcon); DestroyIcon(hIcon); } } // create a clipping region for drawing the lines in the list box
GetWindowRect(ghList, &rect); hClipRgn = CreateRectRgn(0,0, rect.right - rect.left, rect.bottom - rect.top); if ( hClipRgn ) { SelectClipRgn(hDC, hClipRgn); // we can delete it emmdiately because SelectClipRgn makes a COPY of the region
DeleteObject(hClipRgn); } /****************************************************
erasing something drawn on top the top is drawn like ______ |_____| | | instead of | | so we want to NOT draw the two vertical lines above the horzontal
*****************************************************/ // if (nYpos = 0) wFlags |= DI_TOPERASED;
if (wFlags & DI_TOPERASED) { nTop = nYpos; nHeight = nHtItem / 4; } /****************************************************
erasing something originally drawn on the bottom if the list box is NOT LBS_NOINTEGRALHEIGHT, then the botton line will be on the border of the list box, so we don't want to draw the horizontal line at all, ie we draw | | |_____| instead of | |
*****************************************************/ else if (wFlags & DI_BOTTOMERASED && !bNoIntegralHeight) { nTop = nYpos - nHtItem / 4; nHeight = nHtItem / 4; } else { nTop = nYpos - nHtItem / 4; nHeight = nHtItem / 2; } if (!(wFlags & DI_BOTTOMERASED && !bNoIntegralHeight)) // see above comment
{ PatBlt(hDC, LINE_WIDTH, nYpos, nWidth - 2 * LINE_WIDTH, LINE_WIDTH, PATINVERT); } PatBlt(hDC, 0, nTop, LINE_WIDTH, nHeight , PATINVERT); PatBlt(hDC, nWidth - LINE_WIDTH, nTop, LINE_WIDTH, nHeight, PATINVERT); }
|