windows-nt/Source/XPSP1/NT/windows/feime/cht/lctool/movelst.c
2020-09-26 16:20:57 +08:00

707 lines
26 KiB
C

/*************************************************
* 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,
(DLGPROC)ActualDlgProc);
if (is_WORD)
SetFocus(hwndWord[iCurrentAddr]);
else
SetFocus(hwndPhrase[iCurrentAddr]);
if (is_OK) {
bSaveFile = TRUE;
lcSaveEditText(iDisp_Top, 0);
lcOrgEditWindow();
}
}
LRESULT CALLBACK ClassDlgProc(HWND hDlg, UINT message, WPARAM wParam , LPARAM lParam)
{
return DefDlgProc(hDlg, message, wParam, lParam);
}
LRESULT 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
}
LRESULT 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 idTimer; // 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;
idTimer = 0;
idTimer = (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 pt;
GetCursorPos(&pt);
nTopIndex = (int)SendMessage(hwndList, LB_GETTOPINDEX,0,0L);;
if (pt.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 (pt.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, idTimer);
}
break;
default:
return CallWindowProc(lpfnOldListProc, hwndList, message, wParam, lParam);
}
return 0;
}
LRESULT 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);
}