2 * wengineoutput.c - split-off front-end of Engine output (PV) by HGM
\r
4 * Author: Alessandro Scotti (Dec 2005)
\r
6 * Copyright 2005 Alessandro Scotti
\r
8 * ------------------------------------------------------------------------
\r
10 * GNU XBoard is free software: you can redistribute it and/or modify
\r
11 * it under the terms of the GNU General Public License as published by
\r
12 * the Free Software Foundation, either version 3 of the License, or (at
\r
13 * your option) any later version.
\r
15 * GNU XBoard is distributed in the hope that it will be useful, but
\r
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
18 * General Public License for more details.
\r
20 * You should have received a copy of the GNU General Public License
\r
21 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
23 *------------------------------------------------------------------------
\r
24 ** See the file ChangeLog for a revision history. */
\r
28 #include <windows.h> /* required for all Windows applications */
\r
29 #include <richedit.h>
\r
33 #include <commdlg.h>
\r
37 #include "frontend.h"
\r
38 #include "backend.h"
\r
39 #include "winboard.h"
\r
42 #include "engineoutput.h"
\r
44 /* Module variables */
\r
46 static BOOLEAN engineOutputDialogUp = FALSE;
\r
47 HICON icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle
\r
48 HWND outputField[2][7]; // [HGM] front-end array to translate output field to window handle
\r
51 static HICON LoadIconEx( int id )
\r
53 return LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON, ICON_SIZE, ICON_SIZE, 0 );
\r
56 // [HGM] the platform-dependent way of indicating where output should go is now all
\r
57 // concentrated here, where a table of platform-dependent handles are initialized.
\r
58 // This cleanses most other routines of front-end stuff, so they can go into the back end.
\r
59 static void InitializeEngineOutput()
\r
61 // [HGM] made this into a table, rather than separate global variables
\r
62 icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 );
\r
63 icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 );
\r
64 icons[nColorUnknown] = LoadIconEx( IDI_UNKNOWN_14 );
\r
65 icons[nClear] = LoadIconEx( IDI_TRANS_14 );
\r
66 icons[nPondering] = LoadIconEx( IDI_PONDER_14 );
\r
67 icons[nThinking] = LoadIconEx( IDI_CLOCK_14 );
\r
68 icons[nAnalyzing] = LoadIconEx( IDI_ANALYZE2_14 );
\r
70 // [HGM] also make a table of handles to output controls
\r
71 // Note that engineOutputDialog must be defined first!
\r
72 outputField[0][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color1 );
\r
73 outputField[0][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel1 );
\r
74 outputField[0][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon1 );
\r
75 outputField[0][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData1 );
\r
76 outputField[0][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine1_NPS );
\r
77 outputField[0][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo1 );
\r
79 outputField[1][nColorIcon] = GetDlgItem( engineOutputDialog, IDC_Color2 );
\r
80 outputField[1][nLabel] = GetDlgItem( engineOutputDialog, IDC_EngineLabel2 );
\r
81 outputField[1][nStateIcon] = GetDlgItem( engineOutputDialog, IDC_StateIcon2 );
\r
82 outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 );
\r
83 outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS );
\r
84 outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 );
\r
88 static void SetControlPos( HWND hDlg, int id, int x, int y, int width, int height )
\r
90 HWND hControl = GetDlgItem( hDlg, id );
\r
92 SetWindowPos( hControl, HWND_TOP, x, y, width, height, SWP_NOZORDER );
\r
95 #define HIDDEN_X 20000
\r
96 #define HIDDEN_Y 20000
\r
99 static void HideControl( HWND hDlg, int id )
\r
101 HWND hControl = GetDlgItem( hDlg, id );
\r
104 GetWindowRect( hControl, &rc );
\r
107 Avoid hiding an already hidden control, because that causes many
\r
108 unnecessary WM_ERASEBKGND messages!
\r
110 if( rc.left != HIDDEN_X || rc.top != HIDDEN_Y ) {
\r
111 SetControlPos( hDlg, id, 20000, 20000, 100, 100 );
\r
115 // front end, although we might make GetWindowRect front end instead
\r
116 static int GetControlWidth( HWND hDlg, int id )
\r
120 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
122 return rc.right - rc.left;
\r
126 static int GetControlHeight( HWND hDlg, int id )
\r
130 GetWindowRect( GetDlgItem( hDlg, id ), &rc );
\r
132 return rc.bottom - rc.top;
\r
135 static int GetHeaderHeight()
\r
137 int result = GetControlHeight( engineOutputDialog, IDC_EngineLabel1 );
\r
139 if( result < ICON_SIZE ) result = ICON_SIZE;
\r
144 // The size calculations should be backend? If setControlPos is a platform-dependent way of doing things,
\r
145 // a platform-independent wrapper for it should be supplied.
\r
146 static void PositionControlSet( HWND hDlg, int x, int y, int clientWidth, int memoHeight, int idColor, int idEngineLabel, int idNPS, int idMemo, int idStateIcon, int idStateData )
\r
148 int label_x = x + ICON_SIZE + H_MARGIN;
\r
149 int label_h = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
150 int label_y = y + ICON_SIZE - label_h;
\r
151 int nps_w = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
152 int nps_x = clientWidth - H_MARGIN - nps_w;
\r
153 int state_data_w = GetControlWidth( hDlg, IDC_StateData1 );
\r
154 int state_data_x = nps_x - H_MARGIN - state_data_w;
\r
155 int state_icon_x = state_data_x - ICON_SIZE - 2;
\r
156 int max_w = clientWidth - 2*H_MARGIN;
\r
157 int memo_y = y + ICON_SIZE + LABEL_V_DISTANCE;
\r
159 SetControlPos( hDlg, idColor, x, y, ICON_SIZE, ICON_SIZE );
\r
160 SetControlPos( hDlg, idEngineLabel, label_x, label_y, state_icon_x - label_x, label_h );
\r
161 SetControlPos( hDlg, idStateIcon, state_icon_x, y, ICON_SIZE, ICON_SIZE );
\r
162 SetControlPos( hDlg, idStateData, state_data_x, label_y, state_data_w, label_h );
\r
163 SetControlPos( hDlg, idNPS, nps_x, label_y, nps_w, label_h );
\r
164 SetControlPos( hDlg, idMemo, x, memo_y, max_w, memoHeight );
\r
167 // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine
\r
168 void ResizeWindowControls( int mode )
\r
170 HWND hDlg = engineOutputDialog; // [HGM] used to be parameter, but routine is called from back-end
\r
172 int headerHeight = GetHeaderHeight();
\r
173 // int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 );
\r
174 // int labelOffset = H_MARGIN + ICON_SIZE + H_MARGIN;
\r
175 // int labelDeltaY = ICON_SIZE - labelHeight;
\r
178 int maxControlWidth;
\r
181 /* Initialize variables */
\r
182 GetClientRect( hDlg, &rc );
\r
184 clientWidth = rc.right - rc.left;
\r
185 clientHeight = rc.bottom - rc.top;
\r
187 maxControlWidth = clientWidth - 2*H_MARGIN;
\r
189 npsWidth = GetControlWidth( hDlg, IDC_Engine1_NPS );
\r
191 /* Resize controls */
\r
194 PositionControlSet( hDlg, H_MARGIN, V_MARGIN,
\r
196 clientHeight - V_MARGIN - LABEL_V_DISTANCE - headerHeight- V_MARGIN,
\r
197 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
199 /* Hide controls for the second engine */
\r
200 HideControl( hDlg, IDC_Color2 );
\r
201 HideControl( hDlg, IDC_EngineLabel2 );
\r
202 HideControl( hDlg, IDC_StateIcon2 );
\r
203 HideControl( hDlg, IDC_StateData2 );
\r
204 HideControl( hDlg, IDC_Engine2_NPS );
\r
205 HideControl( hDlg, IDC_EngineMemo2 );
\r
206 SendDlgItemMessage( hDlg, IDC_EngineMemo2, WM_SETTEXT, 0, (LPARAM) "" );
\r
207 /* TODO: we should also hide/disable them!!! what about tab stops?!?! */
\r
211 int memo_h = (clientHeight - headerHeight*2 - V_MARGIN*2 - LABEL_V_DISTANCE*2 - SPLITTER_SIZE) / 2;
\r
212 int header1_y = V_MARGIN;
\r
213 int header2_y = V_MARGIN + headerHeight + LABEL_V_DISTANCE + memo_h + SPLITTER_SIZE;
\r
215 PositionControlSet( hDlg, H_MARGIN, header1_y, clientWidth, memo_h,
\r
216 IDC_Color1, IDC_EngineLabel1, IDC_Engine1_NPS, IDC_EngineMemo1, IDC_StateIcon1, IDC_StateData1 );
\r
218 PositionControlSet( hDlg, H_MARGIN, header2_y, clientWidth, memo_h,
\r
219 IDC_Color2, IDC_EngineLabel2, IDC_Engine2_NPS, IDC_EngineMemo2, IDC_StateIcon2, IDC_StateData2 );
\r
222 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo1), NULL, FALSE );
\r
223 InvalidateRect( GetDlgItem(hDlg,IDC_EngineMemo2), NULL, FALSE );
\r
226 // front end. Actual printing of PV lines into the output field
\r
227 void InsertIntoMemo( int which, char * text, int where )
\r
229 SendMessage( outputField[which][nMemo], EM_SETSEL, where, where ); // [HGM] multivar: choose insertion point
\r
231 SendMessage( outputField[which][nMemo], EM_REPLACESEL, (WPARAM) FALSE, (LPARAM) text );
\r
234 // front end. Associates an icon with an output field ("control" in Windows jargon).
\r
235 // [HGM] let it find out the output field from the 'which' number by itself
\r
236 void SetIcon( int which, int field, int nIcon )
\r
240 SendMessage( outputField[which][field], STM_SETICON, (WPARAM) icons[nIcon], 0 );
\r
244 // front end wrapper for SetWindowText, taking control number in stead of handle
\r
245 void DoSetWindowText(int which, int field, char *s_label)
\r
247 SetWindowText( outputField[which][field], s_label );
\r
250 // This seems pure front end
\r
251 LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
\r
253 static SnapData sd;
\r
256 case WM_INITDIALOG:
\r
257 if( engineOutputDialog == NULL ) {
\r
258 engineOutputDialog = hDlg;
\r
260 RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */
\r
262 ResizeWindowControls( windowMode );
\r
265 SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo1, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));
\r
266 SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo2, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 ));
\r
268 SetEngineState( 0, STATE_IDLE, "" );
\r
269 SetEngineState( 1, STATE_IDLE, "" );
\r
275 switch (LOWORD(wParam)) {
\r
277 EndDialog(hDlg, TRUE);
\r
281 EndDialog(hDlg, FALSE);
\r
290 case WM_GETMINMAXINFO:
\r
292 MINMAXINFO * mmi = (MINMAXINFO *) lParam;
\r
294 mmi->ptMinTrackSize.x = 100;
\r
295 mmi->ptMinTrackSize.y = 160;
\r
300 EngineOutputPopDown();
\r
304 ResizeWindowControls( windowMode );
\r
307 case WM_ENTERSIZEMOVE:
\r
308 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
311 return OnSizing( &sd, hDlg, wParam, lParam );
\r
314 return OnMoving( &sd, hDlg, wParam, lParam );
\r
316 case WM_EXITSIZEMOVE:
\r
317 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
324 void EngineOutputPopUp()
\r
327 static int needInit = TRUE;
\r
329 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED);
\r
331 if( engineOutputDialog ) {
\r
332 SendMessage( engineOutputDialog, WM_INITDIALOG, 0, 0 );
\r
334 if( ! engineOutputDialogUp ) {
\r
335 ShowWindow(engineOutputDialog, SW_SHOW);
\r
339 lpProc = MakeProcInstance( (FARPROC) EngineOutputProc, hInst );
\r
341 /* Note to self: dialog must have the WS_VISIBLE style set, otherwise it's not shown! */
\r
342 CreateDialog( hInst, MAKEINTRESOURCE(DLG_EngineOutput), hwndMain, (DLGPROC)lpProc );
\r
344 FreeProcInstance(lpProc);
\r
347 // [HGM] displaced to after creation of dialog, to allow initialization of output fields
\r
349 InitializeEngineOutput();
\r
353 engineOutputDialogUp = TRUE;
\r
357 void EngineOutputPopDown()
\r
359 CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_UNCHECKED);
\r
361 if( engineOutputDialog ) {
\r
362 ShowWindow(engineOutputDialog, SW_HIDE);
\r
365 engineOutputDialogUp = FALSE;
\r
368 // front end. [HGM] Takes handle of output control from table, so only number is passed
\r
369 void DoClearMemo(int which)
\r
371 SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" );
\r
374 // front end (because only other front-end wants to know)
\r
375 int EngineOutputIsUp()
\r
377 return engineOutputDialogUp;
\r
380 // front end, to give back-end access to engineOutputDialog
\r
381 int EngineOutputDialogExists()
\r
383 return engineOutputDialog != NULL;
\r