1 /* AbiWord
2  * Copyright (C) 1998,1999 AbiSource, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA.
18  */
19 
20 #include <windows.h>
21 #include <commctrl.h>
22 
23 #include "ut_string.h"
24 #include "ut_assert.h"
25 #include "ut_debugmsg.h"
26 #include "ut_Win32OS.h"
27 
28 #include "xap_App.h"
29 #include "xap_Win32App.h"
30 #include "xap_Win32FrameImpl.h"
31 
32 #include "ap_Dialog_Id.h"
33 #include "ap_Strings.h"
34 #include "ap_Preview_Paragraph.h"
35 #include "ap_Win32Dialog_Paragraph.h"
36 #include "xap_Win32PreviewWidget.h"
37 #include "xap_Win32LabelledSeparator.h"
38 
39 #include "gr_Win32Graphics.h"
40 #include "xap_Win32DialogHelper.h"
41 #include "ap_Win32Resources.rc2"
42 
43 /*****************************************************************/
44 
45 #define GWL(hwnd)              (AP_Win32Dialog_Paragraph*)GetWindowLongPtrW((hwnd), DWLP_USER)
46 #define SWL(hwnd, d)   SetWindowLongPtrW((hwnd), DWLP_USER,(LONG_PTR)(d))
47 
48 /*****************************************************************/
49 
static_constructor(XAP_DialogFactory * pFactory,XAP_Dialog_Id id)50 XAP_Dialog * AP_Win32Dialog_Paragraph::static_constructor(XAP_DialogFactory * pFactory,
51 														 XAP_Dialog_Id id)
52 {
53 	AP_Win32Dialog_Paragraph * p = new AP_Win32Dialog_Paragraph(pFactory,id);
54 	return p;
55 }
56 
AP_Win32Dialog_Paragraph(XAP_DialogFactory * pDlgFactory,XAP_Dialog_Id id)57 AP_Win32Dialog_Paragraph::AP_Win32Dialog_Paragraph(XAP_DialogFactory * pDlgFactory,
58 												 XAP_Dialog_Id id)
59 	: AP_Dialog_Paragraph(pDlgFactory,id)
60 {
61 	m_pPreviewWidget = NULL;
62 	m_bEditChanged = false;
63 }
64 
~AP_Win32Dialog_Paragraph(void)65 AP_Win32Dialog_Paragraph::~AP_Win32Dialog_Paragraph(void)
66 {
67 	DELETEP(m_pPreviewWidget);
68 }
69 
70 /*****************************************************************/
71 
runModal(XAP_Frame * pFrame)72 void AP_Win32Dialog_Paragraph::runModal(XAP_Frame * pFrame)
73 {
74 	/*
75 	  This dialog is non-persistent.
76 
77 	  This dialog should do the following:
78 
79 	  - Construct itself to represent the paragraph properties
80 	    in the base class (AP_Dialog_Paragraph).
81 
82 		The Unix one looks just like Microsoft Word 97's Paragraph
83 		dialog.
84 
85 	  - The base class stores all the paragraph parameters in
86 	    m_paragraphData.
87 
88 	  On "OK" (or during user-interaction) the dialog should:
89 
90 	  - Save all the data to the m_paragraphData struct so it
91 	    can be queried by the caller (edit methods routines).
92 
93 	  On "Cancel" the dialog should:
94 
95 	  - Just quit, the data items will be ignored by the caller.
96 
97 	  On "Tabs..." the dialog should (?):
98 
99 	  - Just quit, discarding changed data, and let the caller (edit methods)
100 	    invoke the Tabs dialog.
101 
102 	*/
103 
104 	// store frame for later use
105 	m_pFrame = pFrame;
106 
107 	// raise the dialog
108 	XAP_Win32App * pWin32App = static_cast<XAP_Win32App *>(m_pApp);
109 
110 	XAP_Win32LabelledSeparator_RegisterClass(pWin32App);
111 
112 //	createModal(pFrame, MAKEINTRESOURCEW(AP_RID_DIALOG_PARAGRAPH));
113 
114 	LPCWSTR lpTemplate = NULL;
115 
116 	UT_ASSERT(m_id == AP_DIALOG_ID_PARAGRAPH);
117 
118 	lpTemplate = MAKEINTRESOURCEW(AP_RID_DIALOG_PARAGRAPH);
119 
120 	XAP_Win32FrameImpl* pWin32FrameImpl = static_cast<XAP_Win32FrameImpl*>(pFrame->getFrameImpl());
121 
122 	HWND hFrameWnd = pWin32FrameImpl->getTopLevelWindow();
123 
124 	UT_DebugOnly<int> result = DialogBoxParamW(pWin32App->getInstance(),lpTemplate,
125 								hFrameWnd,
126 								(DLGPROC)s_dlgProc,(LPARAM)this);
127 	UT_ASSERT((result != -1));
128 }
129 
130 /**/ //was commented out from here
s_dlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)131 BOOL CALLBACK AP_Win32Dialog_Paragraph::s_dlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
132 {
133 	// This is a static function.
134 
135 	AP_Win32Dialog_Paragraph * pThis;
136 
137 	switch (msg)
138 	{
139 	case WM_INITDIALOG:
140 		pThis = (AP_Win32Dialog_Paragraph *)lParam;
141 		SWL(hWnd,lParam);
142 		pThis->setHandle(hWnd);
143 		return pThis->_onInitDialog(hWnd,wParam,lParam);
144 
145 	case WM_COMMAND:
146 		pThis = GWL(hWnd);
147 		return pThis->_onCommand(hWnd,wParam,lParam);
148 
149 	case WM_NOTIFY:
150 		{
151 			pThis = GWL(hWnd);
152 
153 			switch (((LPNMHDR) lParam)->code)
154 			{
155 			case TCN_SELCHANGING:
156 				{
157 					// TODO: validate data before leaving page
158 				}
159 				break;
160 
161 			case TCN_SELCHANGE:
162 				{
163 					int iTo = TabCtrl_GetCurSel(pThis->m_hwndTab);
164 
165 					// a more general solution would be better here
166 					ShowWindow(pThis->m_hwndSpacing, (iTo ? SW_HIDE : SW_SHOW));
167 					ShowWindow(pThis->m_hwndBreaks, (!iTo ? SW_HIDE : SW_SHOW));
168 				}
169 				break;
170 
171 			// Process other notifications here
172 			default:
173 				break;
174 			}
175 		}
176 		return 0;
177 
178 	default:
179 		return 0;
180 	}
181 }
182 /**/ // and to here
183 // this little struct gets passed into s_tabProc
184 typedef struct _tabParam
185 {
186 	AP_Win32Dialog_Paragraph *	pThis;
187 	WORD which;
188 } TabParam;
189 
s_tabProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)190 BOOL CALLBACK AP_Win32Dialog_Paragraph::s_tabProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
191 {
192 	// This is a static function.
193 
194 	AP_Win32Dialog_Paragraph * pThis;
195 
196 	switch (msg)
197 	{
198 	case WM_INITDIALOG:
199 		{
200 			TabParam * pTP = (TabParam *) lParam;
201 
202 			// from now on, we can just remember pThis
203 			pThis = pTP->pThis;
204 			SWL(hWnd,pThis);
205 			return pThis->_onInitTab(hWnd,wParam,lParam);
206 		}
207 
208 	case WM_COMMAND:
209 		pThis = GWL(hWnd);
210 		return pThis->_onCommand(hWnd,wParam,lParam);
211 
212 	case WM_NOTIFY:
213 		pThis = GWL(hWnd);
214 		switch (((LPNMHDR)lParam)->code)
215 		{
216 		case UDN_DELTAPOS:		return pThis->_onDeltaPos((NM_UPDOWN *)lParam);
217 		default:				return 0;
218 		}
219 
220 	default:
221 		return 0;
222 	}
223 }
224 
225 /*****************************************************************/
226 
227 #define _DS(c,s)	setDlgItemText(hWnd, AP_RID_DIALOG_##c,pSS->getValue(AP_STRING_ID_##s))
228 #define _DSX(c,s)	setDlgItemText(hWnd, AP_RID_DIALOG_##c,pSS->getValue(XAP_STRING_ID_##s))
229 #define _GV(s)		(pSS->getValue(AP_STRING_ID_##s))
230 
_onInitDialog(HWND hWnd,WPARAM,LPARAM)231 BOOL AP_Win32Dialog_Paragraph::_onInitDialog(HWND hWnd, WPARAM /*wParam*/, LPARAM /*lParam*/)
232 {
233 	const XAP_StringSet * pSS = m_pApp->getStringSet();
234 
235 	setDialogTitle (pSS->getValue(AP_STRING_ID_DLG_Para_ParaTitle));
236 
237 	// localize controls
238 	_DSX(PARA_BTN_OK,			DLG_OK);
239 	_DSX(PARA_BTN_CANCEL,		DLG_Cancel);
240 
241 	_DS(PARA_BTN_TABS,			DLG_Para_ButtonTabs);
242 
243 	// setup the tabs
244 	{
245 		TabParam tp;
246 		TCITEMW tie;
247 
248 		XAP_Win32App * pWin32App = static_cast<XAP_Win32App *>(m_pApp);
249 		HINSTANCE hinst = pWin32App->getInstance();
250 		DLGTEMPLATE * pTemplate = NULL;
251 		UT_DebugOnly<HWND> w;
252 
253 		tp.pThis = this;
254 
255 		// remember the windows we're using
256 
257 		m_hwndDlg = hWnd;
258 		m_hwndTab = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_TAB);
259 
260 		// add a tab for each of the child dialog boxes
261 
262 		UT_Win32LocaleString str;
263 
264 		tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
265 		tie.iImage = -1;
266 		str.fromUTF8(_GV(DLG_Para_TabLabelIndentsAndSpacing));
267 		tie.pszText = (LPWSTR)str.c_str();
268 		tie.lParam = AP_RID_DIALOG_PARA_TAB1;
269 		SendMessageW(m_hwndTab, TCM_INSERTITEMW, 0, (LPARAM)&tie);
270 		str.fromUTF8(_GV(DLG_Para_TabLabelLineAndPageBreaks));
271 		tie.pszText = (LPWSTR)str.c_str();
272 		tie.lParam = AP_RID_DIALOG_PARA_TAB2;
273 		SendMessageW(m_hwndTab, TCM_INSERTITEMW, 1, (LPARAM)&tie);
274 
275 		// finally, create the (modeless) child dialogs
276 
277 		tp.which = AP_RID_DIALOG_PARA_TAB1;
278 		pTemplate = UT_LockDlgRes(hinst, MAKEINTRESOURCEW(tp.which));
279 		w = CreateDialogIndirectParamW(hinst, pTemplate, m_hwndTab,
280 										(DLGPROC)s_tabProc, (LPARAM)&tp);
281 		UT_ASSERT_HARMLESS((w && (w == m_hwndSpacing)));
282 
283 		tp.which = AP_RID_DIALOG_PARA_TAB2;
284 		pTemplate = UT_LockDlgRes(hinst, MAKEINTRESOURCEW(tp.which));
285 		w = CreateDialogIndirectParamW(hinst, pTemplate, m_hwndTab,
286 										(DLGPROC)s_tabProc, (LPARAM)&tp);
287 		UT_ASSERT_HARMLESS((w && (w == m_hwndBreaks)));
288 	}
289 
290 	// HACK: make sure the first tab is visible
291 	// TODO: trigger selchange logic instead
292 	ShowWindow(m_hwndSpacing, SW_SHOW);
293 
294 	// sync all controls once to get started
295 	// HACK: the first arg gets ignored
296 	_syncControls(id_MENU_ALIGNMENT, true);
297 	centerDialog();
298 	return 1;							// 1 == we did not call SetFocus()
299 }
300 
301 /*****************************************************************/
302 
303 #define _CAS(w,s)	str.fromUTF8(_GV(s));\
304 	SendMessageW(w, CB_ADDSTRING, 0, (LPARAM)str.c_str())
305 #define _SST(c,i)	setDlgItemText(hWnd,AP_RID_DIALOG_##c,_getSpinItemValue(i))
306 #define _CDB(c,i)	CheckDlgButton(hWnd,AP_RID_DIALOG_##c,_getCheckItemValue(i))
307 
_onInitTab(HWND hWnd,WPARAM,LPARAM lParam)308 BOOL AP_Win32Dialog_Paragraph::_onInitTab(HWND hWnd, WPARAM /*wParam*/, LPARAM lParam)
309 {
310 	const XAP_StringSet * pSS = m_pApp->getStringSet();
311 
312 	UT_Win32LocaleString str;
313 
314 	// position ourselves w.r.t. containing tab
315 
316 	RECT r;
317 	GetClientRect(m_hwndTab, &r);
318 	TabCtrl_AdjustRect(m_hwndTab, FALSE, &r);
319 	SetWindowPos(hWnd, HWND_TOP, r.left, r.top, 0, 0, SWP_NOSIZE);
320 
321 	// remember which window is which tab
322 
323 	TabParam * pTP = (TabParam *) lParam;
324 	switch (pTP->which)
325 	{
326 	case AP_RID_DIALOG_PARA_TAB1:		// first tab
327 		{
328 			m_hwndSpacing = hWnd;
329 
330 			// Hide Bidi Check Box unless required
331 			{
332 				HWND hwndBidi = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_CHECK_BIDI);
333 				ShowWindow(hwndBidi,SW_HIDE);
334 				ShowWindow(hwndBidi,SW_SHOW);
335 			}
336 
337 			// localize controls
338 			_DS(PARA_TEXT_ALIGN,		DLG_Para_LabelAlignment);
339 			_DS(PARA_TEXT_INDENT,		DLG_Para_LabelIndentation);
340 			_DS(PARA_TEXT_LEFT,			DLG_Para_LabelLeft);
341 			_DS(PARA_TEXT_RIGHT,		DLG_Para_LabelRight);
342 			_DS(PARA_TEXT_HANG,			DLG_Para_LabelSpecial);
343 			_DS(PARA_TEXT_BY,			DLG_Para_LabelBy);
344 			_DS(PARA_TEXT_SPACING,		DLG_Para_LabelSpacing);
345 			_DS(PARA_TEXT_BEFORE,		DLG_Para_LabelBefore);
346 			_DS(PARA_TEXT_AFTER,		DLG_Para_LabelAfter);
347 			_DS(PARA_TEXT_LEAD,			DLG_Para_LabelLineSpacing);
348 			_DS(PARA_TEXT_AT,			DLG_Para_LabelAt);
349 			_DS(PARA_CHECK_BIDI,		DLG_Para_DomDirection);
350 
351 			// populate fixed choices
352 			{
353 				HWND hwndAlign = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_COMBO_ALIGN);
354 				// insert the empty value (for multi-para selections with different state)
355 				SendMessageW(hwndAlign, CB_ADDSTRING, 0, (LPARAM) L"");
356 				_CAS(hwndAlign, DLG_Para_AlignLeft);
357 				_CAS(hwndAlign, DLG_Para_AlignCentered);
358 				_CAS(hwndAlign, DLG_Para_AlignRight);
359 				_CAS(hwndAlign, DLG_Para_AlignJustified);
360 				SendMessageW(hwndAlign, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_ALIGNMENT), 0);
361 
362 				HWND hwndHang = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_COMBO_HANG);
363 				SendMessageW(hwndHang, CB_ADDSTRING, 0, (LPARAM) L"");
364 				_CAS(hwndHang, DLG_Para_SpecialNone);
365 				_CAS(hwndHang, DLG_Para_SpecialFirstLine);
366 				_CAS(hwndHang, DLG_Para_SpecialHanging);
367 				SendMessageW(hwndHang, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_SPECIAL_INDENT), 0);
368 
369 				HWND hwndLead = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_COMBO_LEAD);
370 				SendMessageW(hwndLead, CB_ADDSTRING, 0, (LPARAM) L"");
371 				_CAS(hwndLead, DLG_Para_SpacingSingle);
372 				_CAS(hwndLead, DLG_Para_SpacingHalf);
373 				_CAS(hwndLead, DLG_Para_SpacingDouble);
374 				_CAS(hwndLead, DLG_Para_SpacingAtLeast);
375 				_CAS(hwndLead, DLG_Para_SpacingExactly);
376 				_CAS(hwndLead, DLG_Para_SpacingMultiple);
377 				SendMessageW(hwndLead, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_SPECIAL_SPACING), 0);
378 			}
379 
380 			// set initial state
381 			_SST(PARA_EDIT_LEFT,	id_SPIN_LEFT_INDENT);
382 			_SST(PARA_EDIT_RIGHT,	id_SPIN_RIGHT_INDENT);
383 			_SST(PARA_EDIT_BY,		id_SPIN_SPECIAL_INDENT);
384 			_SST(PARA_EDIT_BEFORE,	id_SPIN_BEFORE_SPACING);
385 			_SST(PARA_EDIT_AFTER,	id_SPIN_AFTER_SPACING);
386 			_SST(PARA_EDIT_AT,		id_SPIN_SPECIAL_SPACING);
387 			_CDB(PARA_CHECK_BIDI,	id_CHECK_DOMDIRECTION);
388 		}
389 		break;
390 
391 	case AP_RID_DIALOG_PARA_TAB2:		// second tab
392 		{
393 			m_hwndBreaks = hWnd;
394 
395 			// localize controls
396 			_DS(PARA_TEXT_PAGE,			DLG_Para_LabelPagination);
397 			_DS(PARA_CHECK_WIDOW,		DLG_Para_PushWidowOrphanControl);
398 			_DS(PARA_CHECK_NEXT,		DLG_Para_PushKeepWithNext);
399 			_DS(PARA_CHECK_TOGETHER,	DLG_Para_PushKeepLinesTogether);
400 			_DS(PARA_CHECK_BREAK,		DLG_Para_PushPageBreakBefore);
401 			_DS(PARA_CHECK_SUPPRESS,	DLG_Para_PushSuppressLineNumbers);
402 			_DS(PARA_CHECK_NOHYPHEN,	DLG_Para_PushNoHyphenate);
403 
404 			// set initial state
405 			_CDB(PARA_CHECK_WIDOW,		id_CHECK_WIDOW_ORPHAN);
406 			_CDB(PARA_CHECK_NEXT,		id_CHECK_KEEP_NEXT);
407 			_CDB(PARA_CHECK_TOGETHER,	id_CHECK_KEEP_LINES);
408 			_CDB(PARA_CHECK_BREAK,		id_CHECK_PAGE_BREAK);
409 			_CDB(PARA_CHECK_SUPPRESS,	id_CHECK_SUPPRESS);
410 			_CDB(PARA_CHECK_NOHYPHEN,	id_CHECK_NO_HYPHENATE);
411 		}
412 		break;
413 
414 	default:
415 		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
416 		break;
417 	}
418 
419 	// the following are common to each tab
420 
421 	_DS(PARA_TEXT_PREVIEW,		DLG_Para_LabelPreview);
422 
423 	if (!m_pPreviewWidget)
424 	{
425 		// for XP purposes, life is simplest if we only have one preview
426 		// widget which "floats" above both tabs.  to get the window
427 		// parentage right, we use the dimensions and location of the
428 		// owner-draw control on the tab to position *another* dummy
429 		// window which is parented by the main dialog instead.
430 
431 		HWND hwndChild = GetDlgItem(hWnd, AP_RID_DIALOG_PARA_PREVIEW);
432 		HWND hwndFloater = GetDlgItem(m_hwndDlg, AP_RID_DIALOG_PARA_PREVIEW);
433 
434 		RECT r2;
435 		GetWindowRect(hwndChild, &r2);
436 
437 		POINT pt;
438 		pt.x = r2.left;
439 		pt.y = r2.top;
440 		ScreenToClient(m_hwndDlg, &pt);
441 
442 		SetWindowPos(hwndFloater, HWND_TOP, pt.x, pt.y,
443 					 r2.right - r2.left, r2.bottom - r2.top, SWP_NOREDRAW);
444 
445 		// use this floater window as a parent to the widget that we create
446 		// here and thus have complete control of.
447 
448 		m_pPreviewWidget = new XAP_Win32PreviewWidget(static_cast<XAP_Win32App *>(m_pApp),
449 													  hwndFloater,
450 													  0);
451 
452 		// instantiate the XP preview object using the win32 preview widget (window)
453 		// we just created.  we seem to have a mish-mash of terms here, sorry.
454 
455 		UT_uint32 w,h;
456 		m_pPreviewWidget->getWindowSize(&w,&h);
457 
458 		_createPreviewFromGC(m_pPreviewWidget->getGraphics(),w,h);
459 		m_pPreviewWidget->setPreview(m_paragraphPreview); // we need this to call draw() on WM_PAINTs
460 //		_updatePreview();
461 	}
462 
463 	return 1;							// 1 == we did not call SetFocus()
464 }
465 
466 /*****************************************************************/
467 
468 #define _COMBO(c,i)				\
469 	case AP_RID_DIALOG_##c:		\
470 		switch (HIWORD(wParam))	\
471 		{						\
472 			case CBN_SELCHANGE:	\
473 				_setMenuItemValue(i,SendMessageW(hWndCtrl,CB_GETCURSEL,0,0));	\
474 				return 1;	\
475 							\
476 			default:		\
477 				return 0;	\
478 		}					\
479 		break;				\
480 
481 // to ensure the accurate value is displayed to the user
482 // we call "_syncControls(i)" after we set the variable, to
483 // catch any changes the _setSpinItemValue() call might
484 // have done to validate data
485 #define _EDIT(c,i)				\
486 	case AP_RID_DIALOG_##c:		\
487 		switch (wNotifyCode)	\
488 		{						\
489 			case EN_CHANGE:		\
490 				m_bEditChanged = true;		\
491 				return 1;		\
492 								\
493 			case EN_KILLFOCUS:	\
494 				char buf[SPIN_BUF_TEXT_SIZE];	\
495 				GetWindowText(hWndCtrl,buf,SPIN_BUF_TEXT_SIZE);		\
496 				_setSpinItemValue(i,buf);		\
497 				_syncControls(i);				\
498 				m_bEditChanged = false;		\
499 				return 1;	\
500 							\
501 			default:		\
502 				return 0;	\
503 		}					\
504 		break;				\
505 
506 #define _CHECK(c,i)				\
507 	case AP_RID_DIALOG_##c:		\
508 		_setCheckItemValue(i,(tCheckState) IsDlgButtonChecked(hWnd,AP_RID_DIALOG_##c));	\
509 		return 1;			\
510 
511 /*****************************************************************/
512 
_onCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)513 BOOL AP_Win32Dialog_Paragraph::_onCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
514 {
515 	WORD wNotifyCode = HIWORD(wParam);
516 	WORD wId = LOWORD(wParam);
517 	HWND hWndCtrl = (HWND)lParam;
518 
519 	switch (wId)
520 	{
521 	_COMBO(PARA_COMBO_ALIGN,	id_MENU_ALIGNMENT);
522 	_COMBO(PARA_COMBO_HANG,		id_MENU_SPECIAL_INDENT);
523 	_COMBO(PARA_COMBO_LEAD,		id_MENU_SPECIAL_SPACING);
524 
525 	_EDIT(PARA_EDIT_LEFT,		id_SPIN_LEFT_INDENT);
526 	_EDIT(PARA_EDIT_RIGHT,		id_SPIN_RIGHT_INDENT);
527 	_EDIT(PARA_EDIT_BY,			id_SPIN_SPECIAL_INDENT);
528 	_EDIT(PARA_EDIT_BEFORE,		id_SPIN_BEFORE_SPACING);
529 	_EDIT(PARA_EDIT_AFTER,		id_SPIN_AFTER_SPACING);
530 	_EDIT(PARA_EDIT_AT,			id_SPIN_SPECIAL_SPACING);
531 
532 	_CHECK(PARA_CHECK_WIDOW,	id_CHECK_WIDOW_ORPHAN);
533 	_CHECK(PARA_CHECK_NEXT,		id_CHECK_KEEP_NEXT);
534 	_CHECK(PARA_CHECK_TOGETHER,	id_CHECK_KEEP_LINES);
535 	_CHECK(PARA_CHECK_BREAK,	id_CHECK_PAGE_BREAK);
536 	_CHECK(PARA_CHECK_SUPPRESS,	id_CHECK_SUPPRESS);
537 	_CHECK(PARA_CHECK_NOHYPHEN,	id_CHECK_NO_HYPHENATE);
538 	_CHECK(PARA_CHECK_BIDI,		id_CHECK_DOMDIRECTION);
539 
540 	case IDCANCEL:						// also AP_RID_DIALOG_PARA_BTN_CANCEL
541 		m_answer = a_CANCEL;
542 		EndDialog(hWnd,0);
543 		return 1;
544 
545 	case IDOK:							// also AP_RID_DIALOG_PARA_BTN_OK
546 		m_answer = a_OK;
547 		EndDialog(hWnd,0);
548 		return 1;
549 
550 	case AP_RID_DIALOG_PARA_BTN_TABS:
551 		m_answer = a_TABS;
552 		EndDialog(hWnd,0);
553 		return 1;
554 
555 	default:							// we did not handle this notification
556 		UT_DEBUGMSG(("WM_Command for id %ld\n",wId));
557 		return 0;						// return zero to let windows take care of it.
558 	}
559 }
560 
561 /*****************************************************************/
562 
563 #define _SPIN(w,c,i)					\
564 	case AP_RID_DIALOG_PARA_SPIN_##c:	\
565 		if (m_bEditChanged)				\
566 		{								\
567 			GetDlgItemText(w,AP_RID_DIALOG_PARA_EDIT_##c,buf,SPIN_BUF_TEXT_SIZE);	\
568 			_setSpinItemValue(i,buf);	\
569 			m_bEditChanged = false;	\
570 		}								\
571 		_doSpin(i, (0 - (UT_sint32) pnmud->iDelta));	\
572 		break;							\
573 
_onDeltaPos(NM_UPDOWN * pnmud)574 BOOL AP_Win32Dialog_Paragraph::_onDeltaPos(NM_UPDOWN * pnmud)
575 {
576 	// respond to WM_NOTIFY/UDN_DELTAPOS message
577 	// return TRUE to prevent the change from happening
578 	// return FALSE to allow it to occur
579 	// we may alter the change by changing the fields in pnmud.
580 
581 	UT_DEBUGMSG(("onDeltaPos: [idFrom %d][iPos %d][iDelta %d]\n",
582 				 pnmud->hdr.idFrom,pnmud->iPos,pnmud->iDelta));
583 
584 	char buf[SPIN_BUF_TEXT_SIZE];
585 
586 	switch(pnmud->hdr.idFrom)
587 	{
588 	_SPIN(m_hwndSpacing, LEFT,		id_SPIN_LEFT_INDENT);
589 	_SPIN(m_hwndSpacing, RIGHT,		id_SPIN_RIGHT_INDENT);
590 	_SPIN(m_hwndSpacing, BY,		id_SPIN_SPECIAL_INDENT);
591 	_SPIN(m_hwndSpacing, BEFORE,	id_SPIN_BEFORE_SPACING);
592 	_SPIN(m_hwndSpacing, AFTER,		id_SPIN_AFTER_SPACING);
593 	_SPIN(m_hwndSpacing, AT,		id_SPIN_SPECIAL_SPACING);
594 
595 	default:
596 		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
597 		break;
598 	}
599 
600 	return FALSE;
601 }
602 
603 /*****************************************************************/
604 
605 #define _syncSPIN(w,c,i)	\
606 		case i:				\
607 			SetDlgItemText(w,AP_RID_DIALOG_##c,_getSpinItemValue(i));	\
608 			break;			\
609 
_syncControls(tControl changed,bool bAll)610 void AP_Win32Dialog_Paragraph::_syncControls(tControl changed, bool bAll /* = false */)
611 {
612 	// let parent sync any member variables first
613 
614 	AP_Dialog_Paragraph::_syncControls(changed, bAll);
615 
616 	// sync the display
617 
618 	// 1.  link the "hanging indent by" combo and spinner
619 
620 	if (bAll || (changed == id_SPIN_SPECIAL_INDENT))
621 	{
622 		// typing in the control can change the associated combo
623 		if (_getMenuItemValue(id_MENU_SPECIAL_INDENT) == indent_FIRSTLINE)
624 		{
625 			HWND h = GetDlgItem(m_hwndSpacing, AP_RID_DIALOG_PARA_COMBO_HANG);
626 			SendMessageW(h, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_SPECIAL_INDENT), 0);
627 		}
628 	}
629 	if (bAll || (changed == id_MENU_SPECIAL_INDENT))
630 	{
631 		switch(_getMenuItemValue(id_MENU_SPECIAL_INDENT))
632 		{
633 		case indent_NONE:
634 			// clear the spin control
635 			SetDlgItemText(m_hwndSpacing, AP_RID_DIALOG_PARA_EDIT_BY, NULL);
636 			break;
637 
638 		default:
639 			// set the spin control
640 			SetDlgItemText(m_hwndSpacing, AP_RID_DIALOG_PARA_EDIT_BY, _getSpinItemValue(id_SPIN_SPECIAL_INDENT));
641 			break;
642 		}
643 	}
644 
645 	// 2.  link the "line spacing at" combo and spinner
646 
647 	if (bAll || (changed == id_SPIN_SPECIAL_SPACING))
648 	{
649 		// typing in the control can change the associated combo
650 		if (_getMenuItemValue(id_MENU_SPECIAL_SPACING) == spacing_MULTIPLE)
651 		{
652 			HWND h = GetDlgItem(m_hwndSpacing, AP_RID_DIALOG_PARA_COMBO_LEAD);
653 			SendMessageW(h, CB_SETCURSEL, (WPARAM) _getMenuItemValue(id_MENU_SPECIAL_SPACING), 0);
654 		}
655 	}
656 	if (bAll || (changed == id_MENU_SPECIAL_SPACING))
657 	{
658 		switch(_getMenuItemValue(id_MENU_SPECIAL_SPACING))
659 		{
660 		case spacing_SINGLE:
661 		case spacing_ONEANDHALF:
662 		case spacing_DOUBLE:
663 			// clear the spin control
664 			SetDlgItemText(m_hwndSpacing, AP_RID_DIALOG_PARA_EDIT_AT, NULL);
665 			break;
666 
667 		default:
668 			// set the spin control
669 			SetDlgItemText(m_hwndSpacing, AP_RID_DIALOG_PARA_EDIT_AT, _getSpinItemValue(id_SPIN_SPECIAL_SPACING));
670 			break;
671 		}
672 	}
673 
674 	// 3.  move results of _doSpin() back to screen
675 
676 	if (!bAll)
677 	{
678 		// spin controls only sync when spun
679 		switch (changed)
680 		{
681 		_syncSPIN(m_hwndSpacing, PARA_EDIT_LEFT,	id_SPIN_LEFT_INDENT)
682 		_syncSPIN(m_hwndSpacing, PARA_EDIT_RIGHT,	id_SPIN_RIGHT_INDENT)
683 		_syncSPIN(m_hwndSpacing, PARA_EDIT_BY,		id_SPIN_SPECIAL_INDENT)
684 		_syncSPIN(m_hwndSpacing, PARA_EDIT_BEFORE,	id_SPIN_BEFORE_SPACING)
685 		_syncSPIN(m_hwndSpacing, PARA_EDIT_AFTER,	id_SPIN_AFTER_SPACING)
686 		_syncSPIN(m_hwndSpacing, PARA_EDIT_AT,		id_SPIN_SPECIAL_SPACING)
687 		default:
688 			break;
689 		}
690 	}
691 }
692