96a08e2dfee4c71ba614dcb7e09fef6fd38c6473
[xboard.git] / winboard / whistory.c
1 /*\r
2  * Move history for WinBoard\r
3  *\r
4  * Author: Alessandro Scotti (Dec 2005)\r
5  * front-end code split off by HGM\r
6  *\r
7  * Copyright 2005 Alessandro Scotti\r
8  *\r
9  * ------------------------------------------------------------------------\r
10  *\r
11  * GNU XBoard is free software: you can redistribute it and/or modify\r
12  * it under the terms of the GNU General Public License as published by\r
13  * the Free Software Foundation, either version 3 of the License, or (at\r
14  * your option) any later version.\r
15  *\r
16  * GNU XBoard is distributed in the hope that it will be useful, but\r
17  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
19  * General Public License for more details.\r
20  *\r
21  * You should have received a copy of the GNU General Public License\r
22  * along with this program. If not, see http://www.gnu.org/licenses/. \r
23  *\r
24  * ------------------------------------------------------------------------\r
25  ** See the file ChangeLog for a revision history.  */\r
26 \r
27 #include "config.h"\r
28 \r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 #include <malloc.h>\r
32 #include <windows.h> /* required for all Windows applications */\r
33 #include <richedit.h>\r
34 #include <commdlg.h>\r
35 #include <dlgs.h>\r
36 \r
37 #include "common.h"\r
38 #include "frontend.h"\r
39 #include "backend.h"\r
40 #include "winboard.h"\r
41 #include "wsnap.h"\r
42 \r
43 // templates for calls into back-end\r
44 void RefreshMemoContent P((void));\r
45 void MemoContentUpdated P((void));\r
46 void FindMoveByCharIndex P(( int char_index ));\r
47 \r
48 #define DEFAULT_COLOR       0xFFFFFFFF\r
49 \r
50 #define H_MARGIN            2\r
51 #define V_MARGIN            2\r
52 \r
53 static BOOLEAN moveHistoryDialogUp = FALSE;\r
54 \r
55 // ------------- low-level front-end actions called by MoveHistory back-end -----------------\r
56 \r
57 // low-level front-end, after calculating from & to is left to caller\r
58 // it task is to highlight the indicated characters. (In WinBoard it makes them bold and blue.)\r
59 void HighlightMove( int from, int to, Boolean highlight )\r
60 {\r
61         CHARFORMAT cf;\r
62         HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );\r
63 \r
64         SendMessage( hMemo, EM_SETSEL, from, to);\r
65 \r
66 \r
67         /* Set style */\r
68         ZeroMemory( &cf, sizeof(cf) );\r
69 \r
70         cf.cbSize = sizeof(cf);\r
71         cf.dwMask = CFM_BOLD | CFM_COLOR;\r
72 \r
73         if( highlight ) {\r
74             cf.dwEffects |= CFE_BOLD;\r
75             cf.crTextColor = RGB( 0x00, 0x00, 0xFF );\r
76         }\r
77         else {\r
78             cf.dwEffects |= CFE_AUTOCOLOR;\r
79         }\r
80 \r
81         SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );\r
82 }\r
83 \r
84 // low-level front-end, but replace Windows data types to make it callable from back-end\r
85 // its task is to clear the contents of the move-history text edit\r
86 void ClearHistoryMemo()\r
87 {\r
88     SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_SETTEXT, 0, (LPARAM) "" );\r
89 }\r
90 \r
91 // low-level front-end, made callable from back-end by passing flags and color numbers\r
92 // its task is to append the given text to the text edit\r
93 // the bold argument says 0 = normal, 1 = bold typeface\r
94 // the colorNr argument says 0 = font-default, 1 = gray\r
95 int AppendToHistoryMemo( char * text, int bold, int colorNr )\r
96 {\r
97     CHARFORMAT cf;\r
98     DWORD flags = bold ? CFE_BOLD :0;\r
99     DWORD color = colorNr ? GetSysColor(COLOR_GRAYTEXT) : DEFAULT_COLOR;\r
100 \r
101     HWND hMemo = GetDlgItem( moveHistoryDialog, IDC_MoveHistory );\r
102 \r
103     /* Select end of text */\r
104     int cbTextLen = (int) SendMessage( hMemo, WM_GETTEXTLENGTH, 0, 0 );\r
105 \r
106     SendMessage( hMemo, EM_SETSEL, cbTextLen, cbTextLen );\r
107 \r
108     /* Set style */\r
109     ZeroMemory( &cf, sizeof(cf) );\r
110 \r
111     cf.cbSize = sizeof(cf);\r
112     cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_COLOR | CFM_UNDERLINE;\r
113     cf.dwEffects = flags;\r
114 \r
115     if( color != DEFAULT_COLOR ) {\r
116         cf.crTextColor = color;\r
117     }\r
118     else {\r
119         cf.dwEffects |= CFE_AUTOCOLOR;\r
120     }\r
121 \r
122     SendMessage( hMemo, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf );\r
123 \r
124     /* Append text */\r
125     SendMessage( hMemo, EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );\r
126 \r
127     /* Return offset of appended text */\r
128     return cbTextLen;\r
129 }\r
130 \r
131 // low-level front-end; wrapper for the code to scroll the mentioned character in view (-1 = end)\r
132 void ScrollToCurrent(int caretPos)\r
133 {\r
134     if(caretPos < 0)\r
135         caretPos = (int) SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_GETTEXTLENGTH, 0, 0 );\r
136     SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETSEL, caretPos, caretPos );\r
137 \r
138     SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SCROLLCARET, 0, 0 );\r
139 }\r
140 \r
141 \r
142 // ------------------------------ call backs --------------------------\r
143 \r
144 // front-end. Universal call-back for any event. Recognized vents are dialog creation, OK and cancel button-press\r
145 // (dead code, as these buttons do not exist?), mouse clicks on the text edit, and moving / sizing\r
146 LRESULT CALLBACK HistoryDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
147 {\r
148     static SnapData sd;\r
149 \r
150     switch (message) {\r
151     case WM_INITDIALOG:\r
152         if( moveHistoryDialog == NULL ) {\r
153             moveHistoryDialog = hDlg;\r
154             Translate(hDlg, DLG_MoveHistory);\r
155 \r
156             /* Enable word wrapping and notifications */\r
157             SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETTARGETDEVICE, 0, 0 );\r
158 \r
159             SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS );\r
160 \r
161             /* Set font */\r
162             SendDlgItemMessage( moveHistoryDialog, IDC_MoveHistory, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));\r
163 \r
164             /* Restore window placement */\r
165             RestoreWindowPlacement( hDlg, &wpMoveHistory );\r
166         }\r
167 \r
168         /* Update memo */\r
169         RefreshMemoContent();\r
170 \r
171         MemoContentUpdated();\r
172 \r
173         return FALSE;\r
174 \r
175     case WM_COMMAND:\r
176         switch (LOWORD(wParam)) {\r
177         case IDOK:\r
178           EndDialog(hDlg, TRUE);\r
179           return TRUE;\r
180 \r
181         case IDCANCEL:\r
182           EndDialog(hDlg, FALSE);\r
183           return TRUE;\r
184 \r
185         default:\r
186           break;\r
187         }\r
188 \r
189         break;\r
190 \r
191     case WM_NOTIFY:\r
192         if( wParam == IDC_MoveHistory ) {\r
193             MSGFILTER * lpMF = (MSGFILTER *) lParam;\r
194 \r
195             if( lpMF->msg == WM_LBUTTONDBLCLK && (lpMF->wParam & (MK_CONTROL | MK_SHIFT)) == 0 ) {\r
196                 POINTL pt;\r
197                 LRESULT index;\r
198 \r
199                 pt.x = LOWORD( lpMF->lParam );\r
200                 pt.y = HIWORD( lpMF->lParam );\r
201 \r
202                 index = SendDlgItemMessage( hDlg, IDC_MoveHistory, EM_CHARFROMPOS, 0, (LPARAM) &pt );\r
203 \r
204                 FindMoveByCharIndex( index ); // [HGM] also does the actual moving to it, now\r
205 \r
206                 /* Zap the message for good: apparently, returning non-zero is not enough */\r
207                 lpMF->msg = WM_USER;\r
208 \r
209                 return TRUE;\r
210             }\r
211         }\r
212         break;\r
213 \r
214     case WM_SIZE:\r
215         SetWindowPos( GetDlgItem( moveHistoryDialog, IDC_MoveHistory ),\r
216             HWND_TOP,\r
217             H_MARGIN, V_MARGIN,\r
218             LOWORD(lParam) - 2*H_MARGIN,\r
219             HIWORD(lParam) - 2*V_MARGIN,\r
220             SWP_NOZORDER );\r
221         break;\r
222 \r
223     case WM_GETMINMAXINFO:\r
224         {\r
225             MINMAXINFO * mmi = (MINMAXINFO *) lParam;\r
226         \r
227             mmi->ptMinTrackSize.x = 100;\r
228             mmi->ptMinTrackSize.y = 100;\r
229         }\r
230         break;\r
231 \r
232     case WM_CLOSE:\r
233         MoveHistoryPopDown();\r
234         break;\r
235 \r
236     case WM_ENTERSIZEMOVE:\r
237         return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
238 \r
239     case WM_SIZING:\r
240         return OnSizing( &sd, hDlg, wParam, lParam );\r
241 \r
242     case WM_MOVING:\r
243         return OnMoving( &sd, hDlg, wParam, lParam );\r
244 \r
245     case WM_EXITSIZEMOVE:\r
246         return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
247     }\r
248 \r
249     return FALSE;\r
250 }\r
251 \r
252 // ------------ standard entry points into MoveHistory code -----------\r
253 \r
254 // front-end\r
255 VOID MoveHistoryPopUp()\r
256 {\r
257   FARPROC lpProc;\r
258   \r
259   CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_CHECKED);\r
260 \r
261   if( moveHistoryDialog ) {\r
262     SendMessage( moveHistoryDialog, WM_INITDIALOG, 0, 0 );\r
263 \r
264     if( ! moveHistoryDialogUp ) {\r
265         ShowWindow(moveHistoryDialog, SW_SHOW);\r
266     }\r
267   }\r
268   else {\r
269     lpProc = MakeProcInstance( (FARPROC) HistoryDialogProc, hInst );\r
270 \r
271     /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */\r
272     CreateDialog( hInst, MAKEINTRESOURCE(DLG_MoveHistory), hwndMain, (DLGPROC)lpProc );\r
273 \r
274     FreeProcInstance(lpProc);\r
275   }\r
276 \r
277   moveHistoryDialogUp = TRUE;\r
278 \r
279 // Note that in WIndows creating the dialog causes its call-back to perform\r
280 // RefreshMemoContent() and MemoContentUpdated() immediately after it is realized.\r
281 // To port this to X we might have to do that from here.\r
282 }\r
283 \r
284 // front-end\r
285 VOID MoveHistoryPopDown()\r
286 {\r
287   CheckMenuItem(GetMenu(hwndMain), IDM_ShowMoveHistory, MF_UNCHECKED);\r
288 \r
289   if( moveHistoryDialog ) {\r
290       ShowWindow(moveHistoryDialog, SW_HIDE);\r
291   }\r
292 \r
293   moveHistoryDialogUp = FALSE;\r
294 }\r
295 \r
296 // front-end\r
297 Boolean MoveHistoryIsUp()\r
298 {\r
299     return moveHistoryDialogUp;\r
300 }\r
301 \r
302 // front-end\r
303 Boolean MoveHistoryDialogExists()\r
304 {\r
305     return moveHistoryDialog != NULL;\r
306 }\r