1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiSource Program Utilities
4  * Copyright (C) 1998 AbiSource, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 #define WIN32_LEAN_AND_MEAN
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <windows.h>
29 #include <commctrl.h>   // includes the common control header
30 
31 #include "ut_assert.h"
32 #include "ut_debugmsg.h"
33 #include "ut_vector.h"
34 #include "ut_Win32OS.h"
35 #include "ev_Win32Toolbar.h"
36 #include "xap_Win32App.h"
37 #include "xap_Frame.h"
38 #include "xap_Win32FrameImpl.h"
39 #include "ev_Toolbar_Actions.h"
40 #include "ev_Toolbar_Layouts.h"
41 #include "ev_Toolbar_Labels.h"
42 #include "ev_Toolbar_Control.h"
43 #include "ev_EditEventMapper.h"
44 #include "xap_Win32Toolbar_Icons.h"
45 #include "xap_EncodingManager.h"
46 #include "ev_Win32Toolbar_ViewListener.h"
47 #include "xav_View.h"
48 #include "ut_xml.h"
49 #include "xap_Prefs.h"
50 // The following are for the windows font colour dialog hack
51 #include "ap_Dialog_Id.h"
52 #include "ap_Dialog_Background.h"
53 #include "fv_View.h"
54 #include "pt_PieceTable.h"
55 #include "ap_Win32Toolbar_FontCombo.h"
56 #include "ap_Win32App.h"
57 #include "ut_Win32LocaleString.h"
58 
59 
60 #ifndef TBSTYLE_EX_DRAWDDARROWS
61 #define TBSTYLE_EX_DRAWDDARROWS 0x00000001
62 #endif
63 
64 #ifndef TB_SETEXTENDEDSTYLE
65 #define TB_SETEXTENDEDSTYLE     (WM_USER + 84)  // For TBSTYLE_EX_*
66 #endif
67 
68 #ifndef TB_GETEXTENDEDSTYLE
69 #define TB_GETEXTENDEDSTYLE     (WM_USER + 85)  // For TBSTYLE_EX_*
70 #endif
71 
72 #ifndef TBSTYLE_AUTOSIZE
73 #define TBSTYLE_AUTOSIZE  0x10
74 #endif
75 
76 /*****************************************************************/
77 
78 //
79 // Janitor class to cleanup bitmap handles at program termination.
80 // This one should really be in the anonymous namespace in this translation
81 // unit, but since we don't use namespaces...
82 //
83 class ABI_EXPORT foo_Bitmap_container
84 {
85 public:	// d'tor needs to be public due to buggy MSVC compilers
86 	~foo_Bitmap_container();
87 
88 	static foo_Bitmap_container& instance();	// singleton
addBitmap(HBITMAP hBm)89 	void addBitmap(HBITMAP hBm)
90 	{
91 		UT_ASSERT(hBm);
92 		m_bitmaps_vector.addItem(reinterpret_cast<void*>(hBm));
93 	}
94 
95 private:
foo_Bitmap_container()96 	foo_Bitmap_container() : m_bitmaps_vector(50) {}
97 	foo_Bitmap_container(const foo_Bitmap_container&);	// no impl
98 	void operator=(const foo_Bitmap_container&);		// no impl
99 	UT_Vector m_bitmaps_vector;
100 };
101 
instance()102 foo_Bitmap_container& foo_Bitmap_container::instance()
103 {
104 	static foo_Bitmap_container container;
105 	return container;
106 }
107 
~foo_Bitmap_container()108 foo_Bitmap_container::~foo_Bitmap_container()
109 {
110 	const UT_uint32 nItems = m_bitmaps_vector.getItemCount();
111 	for (UT_uint32 iItem = nItems; iItem; --iItem)
112 	{
113 		void* p = (void*)m_bitmaps_vector.getNthItem(iItem - 1);
114 		// This is really, *REALLY* bad! The same entity that created this
115 		// bitmap should also be responsible to destroy it. Time permitting,
116 		// refactor all this code to make it correct.
117 		::DeleteObject((HGDIOBJ)p);
118 	}
119 }
120 
121 
122 /*****************************************************************/
123 
124 
EV_Win32Toolbar(XAP_Win32App * pWin32App,XAP_Frame * pFrame,const char * szToolbarLayoutName,const char * szToolbarLabelSetName)125 EV_Win32Toolbar::EV_Win32Toolbar(XAP_Win32App * pWin32App, XAP_Frame * pFrame,
126 								 const char * szToolbarLayoutName,
127 								 const char * szToolbarLabelSetName)
128 :	EV_Toolbar(pWin32App->getEditMethodContainer(),
129 				szToolbarLayoutName,
130 				szToolbarLabelSetName),
131 	m_pWin32App(pWin32App),
132 	m_pWin32Frame(pFrame),
133 	m_pViewListener(NULL),
134 	m_lid(0),				// view listener id
135 	m_hwnd(0),
136 	m_pFontCtrl(NULL)
137 {
138 }
139 
~EV_Win32Toolbar(void)140 EV_Win32Toolbar::~EV_Win32Toolbar(void)
141 {
142 	_releaseListener();
143 
144 	if (m_pFontCtrl)
145 		delete m_pFontCtrl;
146 
147 	for (UT_sint32 c=0; c < m_vecOrgStylesNames.getItemCount(); c++)
148 		delete m_vecOrgStylesNames.getNthItem(c);
149 
150 }
151 
toolbarEvent(XAP_Toolbar_Id id,UT_UCSChar * pData,UT_uint32 dataLength)152 bool EV_Win32Toolbar::toolbarEvent(XAP_Toolbar_Id id,
153 									  UT_UCSChar * pData,
154 									  UT_uint32 dataLength)
155 {
156 	// user selected something from this toolbar.
157 	// invoke the appropriate function.
158 	// return true iff handled.
159 
160 	// we use this for the color dialog hack
161 
162 
163 	const EV_Toolbar_ActionSet * pToolbarActionSet = m_pWin32App->getToolbarActionSet();
164 	UT_return_val_if_fail(pToolbarActionSet,false);
165 
166 	const EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
167 	if (!pAction)
168 		return false;
169 
170 	AV_View * pView = m_pWin32Frame->getCurrentView();
171 
172 #if 0
173 	// make sure we ignore presses on "down" group buttons
174 	if (pAction->getItemType() == EV_TBIT_GroupButton)
175 	{
176 		const char * szState = 0;
177 		EV_Toolbar_ItemState tis = pAction->getToolbarItemState(pView,&szState);
178 
179 		if (EV_TIS_ShouldBeToggled(tis))
180 		{
181 			// if this assert fires, you got a click while the button is down
182 			// if your widget set won't let you prevent this, handle it here
183 			UT_ASSERT_HARMLESS(UT_TODO);
184 
185 			// can safely ignore this event
186 			return true;
187 		}
188 	}
189 #endif
190 
191 	// TODO this windows font color dialog is a hack
192 	// TODO true implementation requires a custom widget on the toolbar
193 	if (pAction->getItemType() == EV_TBIT_ColorFore || pAction->getItemType() == EV_TBIT_ColorBack)
194 	{
195 		UT_UCS4String ucs4color;
196 		UT_uint32 dataLength;
197 		XAP_Win32FrameImpl* fimpl = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl());
198 		//int id = ItemIdFromWmCommand(cmd);
199 
200 		UT_ASSERT(id== AP_TOOLBAR_ID_COLOR_BACK || id== AP_TOOLBAR_ID_COLOR_FORE);
201 
202 		const EV_Toolbar_ActionSet * pToolbarActionSet = m_pWin32App->getToolbarActionSet();
203 		UT_return_val_if_fail(pToolbarActionSet,false);
204 
205 		const EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
206 
207 		if (!pAction)
208             return true;
209 
210 		AV_View * pView = m_pWin32Frame->getCurrentView();
211 
212 		const char * szMethodName = pAction->getMethodName();
213 		if (!szMethodName)
214             return true;
215 
216 		const EV_EditMethodContainer * pEMC = m_pWin32App->getEditMethodContainer();
217 		EV_EditMethod * pEM = pEMC->findEditMethodByName(szMethodName);
218 
219 		if (id==AP_TOOLBAR_ID_COLOR_BACK)
220 		{
221 			ucs4color = fimpl->m_sColorBack.ucs4_str();
222 			dataLength =  fimpl->m_sColorBack.size();
223 		}
224 		else
225 		{
226 			ucs4color = fimpl->m_sColorFore.ucs4_str();
227 			dataLength =  fimpl->m_sColorFore.size();
228 		}
229 
230 		invokeToolbarMethod(pView,pEM, ucs4color.ucs4_str(),dataLength);
231 	}
232 
233 	const char * szMethodName = pAction->getMethodName();
234 	if (!szMethodName)
235 		return false;
236 
237 	const EV_EditMethodContainer * pEMC = m_pWin32App->getEditMethodContainer();
238 	UT_return_val_if_fail(pEMC,false);
239 
240 	EV_EditMethod * pEM = pEMC->findEditMethodByName(szMethodName);
241 	UT_ASSERT(pEM);						// make sure it's bound to something
242 
243 	invokeToolbarMethod(pView,pEM,pData,dataLength);
244 	return true;
245 }
246 
247 /*****************************************************************/
248 
249 // HACK: forward declarations for subclassed controls
250 #ifdef STRICT
251 #define WHICHPROC	WNDPROC
252 #else
253 #define WHICHPROC	FARPROC
254 #endif
255 
256 WHICHPROC s_lpfnDefCombo;
257 WHICHPROC s_lpfnDefToolBar;
258 
259 
260 #define COMBO_BUF_LEN 256
261 
262 
263 
_ToolBarWndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam)264 LRESULT CALLBACK EV_Win32Toolbar::_ToolBarWndProc (HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
265 {
266 	if (uMessage == WM_CTLCOLORSTATIC) {
267 		if(SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW)) == CLR_INVALID)
268 		{
269 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
270 		}
271 		if(SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT)) == CLR_INVALID)
272 		{
273 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
274 		}
275 		return (LRESULT) GetSysColorBrush (COLOR_WINDOW);
276 	}
277 
278 	return (CallWindowProcW(s_lpfnDefToolBar, hWnd, uMessage, wParam, lParam));
279 }
280 
_ComboWndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam)281 LRESULT CALLBACK EV_Win32Toolbar::_ComboWndProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
282 {
283 	switch (uMessage)
284 	{
285 		/* Draws the font preview in the font selection combobox*/
286 		case WM_DRAWITEM:
287 		{
288 			EV_Win32Toolbar * t = (EV_Win32Toolbar *) GetWindowLongPtrW(hWnd, GWLP_USERDATA);
289 			UINT u = GetDlgCtrlID(hWnd);
290 			XAP_Toolbar_Id id = t->ItemIdFromWmCommand(u);
291 
292 			if (id!=AP_TOOLBAR_ID_FMT_FONT)	/* Only owner draw the font selection*/
293 			{
294 				UT_ASSERT_HARMLESS(0);
295 				break;
296 			}
297 
298 			DRAWITEMSTRUCT* dis = (DRAWITEMSTRUCT*)lParam;
299 			if((UT_sint32)dis->itemData < 0)
300 			{
301 				return TRUE;
302 			}
303 
304 			XAP_Toolbar_ControlFactory * pFactory = t->m_pWin32App->getControlFactory();
305 
306 			if (!t->m_pFontCtrl)
307 			{
308 				EV_Toolbar_Control * pControl = pFactory->getControl(t, AP_TOOLBAR_ID_FMT_FONT);
309 				t->m_pFontCtrl = static_cast<AP_Win32Toolbar_FontCombo *>(pControl);
310 				t->m_pFontCtrl->populate();
311 			}
312 
313 			HFONT hFont, hUIFont;
314 			LOGFONTW logfont;
315 			SIZE size;
316 			HFONT hfontSave;
317             UT_Win32LocaleString str;
318 			const UT_GenericVector<const char*> * v = t->m_pFontCtrl->getContents();
319 			str.fromUTF8 (v->getNthItem(dis->itemData));
320 
321 			if(dis->itemState & ODS_COMBOBOXEDIT)
322 			{
323 				HFONT hUIFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
324 				hfontSave = (HFONT) SelectObject (dis->hDC, hUIFont);
325 				ExtTextOutW(dis->hDC, dis->rcItem.left, dis->rcItem.top, ETO_OPAQUE | ETO_CLIPPED, 0, str.c_str(), str.size(), 0);
326 				SelectObject (dis->hDC, hfontSave);
327 			}
328 			else
329 			{
330 				memset (&logfont, 0, sizeof (logfont));
331 
332 				/* Create current font */
333 				logfont.lfHeight = 18;
334 				logfont.lfWidth = 0;
335 				logfont.lfEscapement = 0;
336 				logfont.lfOrientation = 0;
337 				logfont.lfWeight = FW_BOLD;
338 				logfont.lfItalic = FALSE;
339 				logfont.lfUnderline = FALSE;
340 				logfont.lfStrikeOut = FALSE;
341 				logfont.lfCharSet = DEFAULT_CHARSET;
342 				logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
343 				logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
344 				logfont.lfQuality = DEFAULT_QUALITY;
345 				logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
346 				lstrcpynW(logfont.lfFaceName, str.c_str(), LF_FACESIZE);
347 				hFont = CreateFontIndirectW (&logfont);
348 
349 				if(dis->itemState & ODS_SELECTED) /* HighLight the selected text*/
350 				{
351 					SetTextColor(dis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
352 					SetBkColor(dis->hDC, GetSysColor(COLOR_HIGHLIGHT));
353 					FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
354 				}
355 				else
356 				{
357 					SetTextColor(dis->hDC, GetSysColor(COLOR_WINDOWTEXT));
358 					SetBkColor(dis->hDC, GetSysColor(COLOR_WINDOW));
359 					FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_WINDOW) );
360 				}
361 
362 				hUIFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
363 
364 				/*Fontname in regular font*/
365 				hfontSave = (HFONT) SelectObject (dis->hDC, hUIFont);
366                 ExtTextOutW(dis->hDC, dis->rcItem.left, dis->rcItem.top, ETO_OPAQUE | ETO_CLIPPED, 0, str.c_str(), str.size(), 0);
367 
368 				/*Font example after the name*/
369 				const wchar_t* szSample = L"AbCdEfGhIj";
370                 GetTextExtentPoint32W(dis->hDC, str.c_str(), str.size(), &size);
371 				SelectObject (dis->hDC, hFont);
372 				ExtTextOutW(dis->hDC, dis->rcItem.left+size.cx+5, dis->rcItem.top, ETO_OPAQUE | ETO_CLIPPED, 0, szSample, wcslen(szSample), 0);
373 				SelectObject (dis->hDC, hfontSave);
374 				DeleteObject(hFont);
375 			}
376 
377 			return TRUE;
378 		}
379 
380 		case WM_MOUSEMOVE:
381 		case WM_LBUTTONDOWN:
382 		case WM_LBUTTONUP:
383 		{
384 			// relay mouse messages from the combo box to get tool tips to work
385 			// TODO: similar relay needed from edit control, too??
386 			// ALT:  tell tooltip control to subclass for these events
387 			MSG msg;
388 			HWND hWndTT;
389 			msg.lParam = lParam;
390 			msg.wParam = wParam;
391 			msg.message = uMessage;
392 			msg.hwnd = hWnd;
393 
394 			HWND hwndToolbar = GetParent(hWnd);
395 
396 			hWndTT = (HWND)SendMessageW(hwndToolbar, TB_GETTOOLTIPS, 0,0);
397 			SendMessageW(hWndTT, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg);
398 			break;
399 		}
400 
401 		case WM_COMMAND:
402 		{
403 			switch (HIWORD(wParam))
404 			{
405 				case CBN_SELCHANGE:
406 				{
407 					UT_sint32 iSelected = SendMessageW(hWnd, CB_GETCURSEL, 0, 0);
408 
409 					if(iSelected != -1)
410 					{
411 						static UT_UCSChar ucs_buf[COMBO_BUF_LEN];
412                         UT_Win32LocaleString str;
413 						UT_uint32 bufLength = SendMessageW(hWnd, CB_GETLBTEXTLEN, iSelected, (LPARAM)0) + 1;
414 						wchar_t* buf = (wchar_t*)g_try_malloc(bufLength * sizeof (wchar_t));
415 						UT_uint32 dataLength = SendMessageW(hWnd, CB_GETLBTEXT, iSelected, (LPARAM)buf);
416                         str.fromLocale (buf);
417 
418                         UT_UCS4_strcpy_utf8_char(ucs_buf, str.utf8_str().utf8_str());
419 						UT_UCSChar * pData = (UT_UCSChar *) ucs_buf;	// HACK: should be void *
420 
421 						EV_Win32Toolbar * t = (EV_Win32Toolbar *) GetWindowLongPtrW(hWnd, GWLP_USERDATA);
422 						UT_ASSERT(t);
423 
424 						if(dataLength)
425 						{
426 							UINT u = GetDlgCtrlID(hWnd);
427 							XAP_Toolbar_Id id = t->ItemIdFromWmCommand(u);
428 
429 							// If is a STYLE_NAME we should pass the internal one, not the localised
430 							if (id==AP_TOOLBAR_ID_FMT_STYLE)
431 							{
432 								UT_sint32 iSelected;
433 								int nData;
434 
435 								iSelected = SendMessageW(hWnd, CB_GETCURSEL, 0, 0);
436 
437 								// Find the proper non-localised text
438 								XAP_Toolbar_ControlFactory * pFactory = t->m_pWin32App->getControlFactory();
439 								EV_Toolbar_Control * pControl = pFactory->getControl(t, AP_TOOLBAR_ID_FMT_STYLE);
440 								AP_Win32Toolbar_StyleCombo * pStyleC = static_cast<AP_Win32Toolbar_StyleCombo *>(pControl);
441 								pStyleC->repopulate();
442 
443 								nData  = SendMessageW(hWnd, CB_GETITEMDATA, iSelected, 0);
444 
445 								UT_UTF8String *utf = t->m_vecOrgStylesNames.getNthItem(nData);
446 								UT_ASSERT((utf && (utf->length() < (COMBO_BUF_LEN-1))));
447 								UT_UCS4_strcpy_utf8_char(ucs_buf, utf->utf8_str());
448 								dataLength = UT_UCS4_strlen (ucs_buf);
449 
450 								DELETEP(pControl);
451 							}
452 
453 							t->toolbarEvent(id, pData, dataLength);
454 						}
455 
456 						SetFocus(static_cast<XAP_Win32FrameImpl*>(t->m_pWin32Frame->getFrameImpl())->getTopLevelWindow());
457 					}
458 					else
459 					{
460 						PostMessageW(hWnd, WM_KEYDOWN, VK_ESCAPE, 0);
461 					}
462 
463 					break;
464 				}
465 
466 
467 				break;
468 
469 			} // swich
470 		} // case command
471 
472 		case WM_KEYDOWN:
473 		{
474 			EV_Win32Toolbar * t = (EV_Win32Toolbar *) GetWindowLongPtrW(hWnd, GWLP_USERDATA);
475 			UT_ASSERT(t);
476 
477 			switch (wParam)
478 			{
479 				case VK_ESCAPE:
480 				{
481 					// restore combo state
482 					UINT u = GetDlgCtrlID(hWnd);
483 					XAP_Toolbar_Id id = t->ItemIdFromWmCommand(u);
484 
485 					t->_refreshID(id);
486 				}
487 				// fall through
488 
489 				case VK_TAB:
490 				case VK_RETURN:
491 				{
492 					SetFocus(static_cast<XAP_Win32FrameImpl*>(t->m_pWin32Frame->getFrameImpl())->getTopLevelWindow());
493 					return 0;
494 				}
495 			}
496 		}
497 	}
498 	return (CallWindowProcW(s_lpfnDefCombo, hWnd, uMessage, wParam, lParam));
499 }
500 
501 
502 /*****************************************************************/
503 
synthesize(void)504 bool EV_Win32Toolbar::synthesize(void)
505 {
506 	// create a toolbar from the info provided.
507 
508 	////////////////////////////////////////////////////////////////
509 	// get toolbar button appearance from the preferences
510 	////////////////////////////////////////////////////////////////
511 
512 	bool bIcons = true;
513 	bool bText = false;
514 	const gchar * szValue = NULL;
515 	m_pWin32App->getPrefsValue(XAP_PREF_KEY_ToolbarAppearance,&szValue);
516 	UT_return_val_if_fail((szValue) && (*szValue),false);
517 
518 	if (g_ascii_strcasecmp(szValue,"icon") == 0)
519 	{
520 		bIcons = true;
521 		bText = false;
522 	}
523 	else if (g_ascii_strcasecmp(szValue,"text") == 0)
524 	{
525 		bIcons = false;
526 		bText = true;
527 	}
528 	else if (g_ascii_strcasecmp(szValue,"both") == 0)
529 	{
530 		bIcons = true;
531 		bText = true;
532 	}
533 
534 	const EV_Toolbar_ActionSet * pToolbarActionSet = m_pWin32App->getToolbarActionSet();
535 	UT_ASSERT(pToolbarActionSet);
536 
537 	UT_uint32 nrLabelItemsInLayout = m_pToolbarLayout->getLayoutItemCount();
538 	UT_ASSERT(nrLabelItemsInLayout > 0);
539 
540 	XAP_Toolbar_ControlFactory * pFactory = m_pWin32App->getControlFactory();
541 	UT_ASSERT(pFactory);
542 
543 	HWND hwndParent = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl())->getToolbarWindow();
544 	if(hwndParent == NULL)
545 		return false;
546 
547 	// NOTE: this toolbar will get placed later, by frame or rebar
548 
549 	m_hwnd = UT_CreateWindowEx(0,
550 							   TOOLBARCLASSNAMEW, // window class name
551 							   NULL,			// window caption
552 							   WS_CHILD | WS_VISIBLE
553 							   | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
554 							   | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT
555 							   | ( bText && !bIcons ? TBSTYLE_LIST : 0 )
556 							   | TBSTYLE_CUSTOMERASE
557 							   | CCS_NOPARENTALIGN | CCS_NODIVIDER
558 							   | CCS_NORESIZE
559 							   ,						// window style
560 							   0,						// initial x position
561 							   0,						// initial y position
562 							   0,						// initial x size
563 							   0,						// initial y size
564 							   hwndParent,				// parent window handle
565 							   NULL,					// window menu handle
566 							   m_pWin32App->getInstance(),		// program instance handle
567 							   NULL);  // creation parameters
568 
569 
570 	UT_ASSERT(m_hwnd);
571 
572 	// override the window procedure
573 	s_lpfnDefToolBar = (WHICHPROC)GetWindowLongPtrW(m_hwnd, GWLP_WNDPROC);
574 	SetWindowLongPtrW(m_hwnd, GWLP_WNDPROC, (LONG_PTR)_ToolBarWndProc);
575 	SetWindowLongPtrW(m_hwnd, GWLP_USERDATA, (LONG_PTR)this);
576 
577 
578 	SendMessageW(m_hwnd, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
579 
580 	// the Windows Common Control Toolbar requires that we set
581 	// a bitmap size in the toolbar window **before** we actually
582 	// add any of them.  at this point in the code, we haven't
583 	// loaded any of the bitmaps yet and thus don't know the maximum
584 	// size.  we could go thru the layout twice and compute the
585 	// maxium before calling this, but this seems overkill since
586 	// we know at compile time what all of the bitmaps are....
587 	//
588 	// Now bitmaps are cut down to requested size if too large - HB
589 
590 	const WORD MY_MAXIMUM_BITMAP_X = 24;
591 	const WORD MY_MAXIMUM_BITMAP_Y = 24;
592 
593 	if( bIcons )
594 		SendMessageW(m_hwnd, TB_SETBITMAPSIZE, 0,
595 					(LPARAM) MAKELONG(MY_MAXIMUM_BITMAP_X,MY_MAXIMUM_BITMAP_Y));
596 	else
597 		SendMessageW(m_hwnd, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG(0,0));
598 
599 	DWORD dwColor = GetSysColor(COLOR_BTNFACE);
600 	UT_RGBColor backgroundColor(GetRValue(dwColor),GetGValue(dwColor),GetBValue(dwColor));
601 
602 	// TODO: is there any advantage to building up all the TBBUTTONs at once
603 	//		 and then adding them en masse, instead of one at a time?
604 	UINT last_id=0;
605 	bool bControls = false;
606 
607 	for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
608 	{
609 		EV_Toolbar_LayoutItem * pLayoutItem = m_pToolbarLayout->getLayoutItem(k);
610 		UT_continue_if_fail(pLayoutItem);
611 
612 		XAP_Toolbar_Id id = pLayoutItem->getToolbarId();
613 		EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
614 		UT_ASSERT(pAction);
615 		EV_Toolbar_Label * pLabel = m_pToolbarLabelSet->getLabel(id);
616 		UT_ASSERT(pLabel);
617 
618 		UINT u = WmCommandFromItemId(id);
619 
620 		TBBUTTON tbb;
621 		memset(&tbb, 0, sizeof(tbb));
622 
623 		switch (pLayoutItem->getToolbarLayoutFlags())
624 		{
625 		case EV_TLF_Normal:
626 			{
627 				tbb.idCommand = u;
628 				tbb.dwData = 0;
629 
630 				last_id = u;
631 
632 				bool bButton = false;
633 
634 				switch (pAction->getItemType())
635 				{
636 					//TODO: For now these are buttons which bring up a dialog, as some point,
637            		 	//make them be able to bring up some sort of additional selector.
638 				case EV_TBIT_ColorFore:
639 				case EV_TBIT_ColorBack:
640 					UT_DEBUGMSG(("TODO: Hey Windows needs some tender love and care and a colour selector! \n"));
641 					// UT_ASSERT(UT_NOT_IMPLEMENTED);
642 					UT_DEBUGMSG(("TODO: Handle the colour selector case \n"));
643 					/* Fall through and make a push button */
644 
645 				case EV_TBIT_PushButton:
646 					bButton = true;
647 					tbb.fsState = TBSTATE_ENABLED;
648 					tbb.fsStyle = TBSTYLE_BUTTON;
649 					break;
650 
651 				case EV_TBIT_ToggleButton:
652 					bButton = true;
653 					tbb.fsState = TBSTATE_ENABLED;
654 					tbb.fsStyle = TBSTYLE_CHECK;
655 					break;
656 
657 				case EV_TBIT_GroupButton:
658 					bButton = true;
659 					tbb.fsState = TBSTATE_ENABLED;
660 					tbb.fsStyle = TBSTYLE_CHECKGROUP;
661 					break;
662 
663 				case EV_TBIT_ComboBox:
664 					{
665 						EV_Toolbar_Control * pControl = pFactory->getControl(this, id);
666 						UT_ASSERT_HARMLESS(pControl);
667 
668 						int iWidth = 100;
669 
670 						if (pControl)
671 						{
672 							iWidth = pControl->getPixelWidth();
673 						}
674 
675 						bControls = true;
676 						tbb.fsStyle = TBSTYLE_SEP;
677 						tbb.iBitmap = iWidth;
678 
679 						// create a matching child control
680 						DWORD dwStyle = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL |
681 								CBS_HASSTRINGS | CBS_DROPDOWN;
682 
683 						if ((pControl) && (pControl->shouldSort()))
684 						{
685 							dwStyle |= CBS_SORT;
686 						}
687 
688 						if (id==AP_TOOLBAR_ID_FMT_FONT)
689 							dwStyle |= CBS_OWNERDRAWFIXED;
690 
691 						HWND hwndCombo = UT_CreateWindowEx ( 0L,   // No extended styles.
692 							L"COMBOBOX",						// Class name.
693 							L"",								// Default text.
694 							dwStyle,						// Styles and defaults.
695 							0, 2, iWidth, 250,				// Size and position.
696 							m_hwnd,							// Parent window.
697 							(HMENU) u,						// ID.
698 							m_pWin32App->getInstance(),		// Current instance.
699 							NULL );							// No class data.
700 
701 						UT_ASSERT(hwndCombo);
702 
703 						/*
704 						 * Hack to create a combobox that is readonly, but which is capable of displaying text in
705 						 * the edit control which differs from that in the drop-down list like GTK combos.
706 						 */
707 						HWND hwndEdit = FindWindowExW(hwndCombo, 0, NULL, NULL);
708 						if (!hwndEdit)
709 							UT_DEBUGMSG(("Toolbar: Failed to get handle of combos edit controls. Not setting read-only.\n"));
710 						else
711 							SendMessageW(hwndEdit, EM_SETREADONLY, (WPARAM)TRUE, (LPARAM)0);
712 						SendMessageW(hwndCombo, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
713 						SendMessageW(hwndCombo, CB_SETDROPPEDWIDTH,(WPARAM)pControl->getDroppedWidth(), 0);
714 
715 						// populate it
716 						if (pControl)
717 						{
718 							pControl->populate();
719 
720 							const UT_GenericVector<const char*> * v = pControl->getContents();
721 							UT_ASSERT_HARMLESS(v);
722 
723 							SendMessageW(hwndCombo, WM_SETREDRAW, FALSE,0);
724 
725 							if (v)
726 							{
727 								UT_uint32 items = v->getItemCount();
728 								int nIndex;
729                                 UT_Win32LocaleString localised;
730 								for (UT_uint32 k=0; k < items; k++)
731 								{
732 									localised.fromUTF8(v->getNthItem(k));
733     								nIndex = SendMessageW(hwndCombo, CB_ADDSTRING,(WPARAM)0, (LPARAM)localised.c_str());
734  	     							SendMessageW(hwndCombo,CB_SETITEMDATA, nIndex, k);
735 								}
736 							}
737 
738 							SendMessageW(hwndCombo, WM_SETREDRAW, TRUE,0);
739 						}
740 
741 						// override the window procedure for the combo box
742 						s_lpfnDefCombo = (WHICHPROC)GetWindowLongPtrW(hwndCombo, GWLP_WNDPROC);
743 						SetWindowLongPtrW(hwndCombo, GWLP_WNDPROC, (LONG_PTR)_ComboWndProc);
744 						SetWindowLongPtrW(hwndCombo, GWLP_USERDATA, (LONG_PTR)this);
745 
746 						// Get the handle to the tooltip window.
747 						HWND hwndTT = (HWND)SendMessageW(m_hwnd, TB_GETTOOLTIPS, 0, 0);
748 
749 						if (hwndTT)
750 						{
751                             UT_Win32LocaleString str;
752 							const char * szToolTip = pLabel->getToolTip();
753 							if (!szToolTip || !*szToolTip)
754 							{
755 								szToolTip = pLabel->getStatusMsg();
756 							}
757 
758                             str.fromUTF8 (szToolTip);
759 
760 							// Fill in the TOOLINFO structure.
761 							TOOLINFOW ti;
762 							ti.cbSize = sizeof(ti);
763 							ti.uFlags = TTF_IDISHWND | TTF_CENTERTIP;
764 							ti.lpszText = (wchar_t *) str.c_str();
765 							ti.hwnd = m_hwnd;		// TODO: should this be the frame?
766 							ti.uId = (UINT_PTR)hwndCombo;
767 							// Set up tooltips for the combo box.
768 							SendMessageW(hwndTT, TTM_ADDTOOLW, 0, (LPARAM)(LPTOOLINFOW)&ti);
769 						}
770 
771 						// bind this separator to its control
772 						tbb.dwData = (DWORD_PTR) hwndCombo;
773 
774 						// for now, we never repopulate, so can just toss it
775 						DELETEP(pControl);
776 					}
777 					break;
778 
779 				case EV_TBIT_EditText:
780 				case EV_TBIT_DropDown:
781 				case EV_TBIT_StaticLabel:
782 					// TODO do these...
783 					break;
784 
785 				case EV_TBIT_Spacer:
786 				case EV_TBIT_BOGUS:
787 				default:
788 					UT_ASSERT_HARMLESS(0);
789 					break;
790 				}
791 
792 				if (bButton)
793 				{
794 					// TODO figure out who destroys hBitmap...
795 					//
796 					// TMN: 20 Nov 2000 - Tests display that we must hang on to the
797 					// bitmap handle for this to work.
798 					// Had we been allowed to use C++ I'd say
799 					//		std::map<std::string, HBITMAP> icons;
800 					// but currently I don't know how to handle this in a clean way.
801 					// Would UT_Array help?
802 
803 					// TODO add code to create these once per application
804 					// TODO and reference them in each toolbar instance
805 					// TODO rather than create them once for each window....
806 
807 					if (bIcons)
808 					{
809 						HBITMAP hBitmap;
810 						UT_DebugOnly<bool> bFoundIcon =
811 							XAP_Win32Toolbar_Icons::getBitmapForIcon(m_hwnd,
812 																	MY_MAXIMUM_BITMAP_X,
813 																	MY_MAXIMUM_BITMAP_Y,
814 																	&backgroundColor,
815 																	pLabel->getIconName(),
816 																	&hBitmap);
817 						UT_ASSERT(bFoundIcon);
818 
819 						// TMN: I know, this is really, really bad, but it's
820 						// currently the only thing we have at our disposal to
821 						// release these bitmaps at program termination.
822 						foo_Bitmap_container::instance().addBitmap(hBitmap);
823 
824 						TBADDBITMAP ab;
825 						ab.hInst = 0;
826 						ab.nID = (LPARAM)hBitmap;
827 
828 						LRESULT iAddedAt = SendMessageW(m_hwnd,TB_ADDBITMAP,1,(LPARAM)&ab);
829 						UT_ASSERT(iAddedAt != -1);
830 
831 						tbb.iBitmap = iAddedAt;
832 					}
833 
834 					if (bText)
835 					{
836 						const char * szLabel = pLabel->getToolbarLabel();
837 						// As long as translators don't cut the text short,
838 						// we need to autosize just to squize anything insize 1280 :)
839 						tbb.fsStyle |= TBSTYLE_AUTOSIZE;
840 						tbb.iString = SendMessageW(m_hwnd, TB_ADDSTRING, (WPARAM) 0, (LPARAM) (LPSTR) szLabel);
841 					}
842 
843 					if (pAction->getItemType() == EV_TBIT_ColorFore || pAction->getItemType() == EV_TBIT_ColorBack)
844 					{
845 						tbb.fsStyle |=TBSTYLE_DROPDOWN;
846 
847 						//tbb.fsStyle |=BTNS_WHOLEDROPDOWN;
848 
849 						DWORD dwStyle = SendMessageW(m_hwnd, TB_GETEXTENDEDSTYLE, (WPARAM) 0, (LPARAM) 0);
850 						dwStyle |= TBSTYLE_EX_DRAWDDARROWS;
851 						SendMessageW(m_hwnd, TB_SETEXTENDEDSTYLE, (WPARAM) 0, (LPARAM) dwStyle);
852 					}
853 
854 				}
855 			}
856 			break;
857 
858 		case EV_TLF_Spacer:
859 			tbb.fsState = TBSTATE_ENABLED;
860 			tbb.fsStyle = TBSTYLE_SEP;
861 			break;
862 
863 		default:
864 			UT_ASSERT_HARMLESS(0);
865 		}
866 
867 		// add this button to the bar
868 		SendMessageW(m_hwnd, TB_ADDBUTTONS, (WPARAM) 1, (LPARAM) (LPTBBUTTON) &tbb);
869 	}
870 
871 	// figure out bar dimensions now that buttons are all there
872 	SendMessageW(m_hwnd, TB_AUTOSIZE, 0, 0);
873 
874 	if (bControls)
875 	{
876 		// move each control on top of its associated separator
877 		for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
878 		{
879 			EV_Toolbar_LayoutItem * pLayoutItem = m_pToolbarLayout->getLayoutItem(k);
880 			UT_continue_if_fail(pLayoutItem);
881 
882 			XAP_Toolbar_Id id = pLayoutItem->getToolbarId();
883 			EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
884 			UT_continue_if_fail(pAction);
885 
886 			RECT r;
887 			HWND hwndCtrl;
888 			int nHeight, nSep;
889 
890 			switch (pAction->getItemType())
891 			{
892 				case EV_TBIT_ComboBox:
893 					hwndCtrl = _getControlWindow(id);
894 					UT_ASSERT(hwndCtrl);
895 					GetWindowRect(hwndCtrl, &r);
896 					nHeight = r.bottom - r.top;
897 
898 					SendMessageW(m_hwnd, TB_GETITEMRECT, (WPARAM) k, (LPARAM)(LPRECT) &r);
899 
900 					nSep = (r.bottom - r.top - nHeight)/2;
901 					if (nSep < 0)
902 						nSep = 0;
903 
904 					MoveWindow(hwndCtrl, r.left, r.top + nSep, r.right - r.left, nHeight, TRUE);
905 
906 					break;
907 
908 				case EV_TBIT_EditText:
909 				case EV_TBIT_DropDown:
910 				case EV_TBIT_StaticLabel:
911 					// TODO do these...
912 					break;
913 
914 				default:
915 					break;
916 			}
917 		}
918 	}
919 
920 	UT_ASSERT(last_id > 0);
921 
922 	_addToRebar();	// add this bar to the rebar
923 
924 	// I think that this is true due to the WS_VISIBLE flag
925 	// sent to CreateWindowEx
926 	m_bVisible = true;
927 
928 	return true;
929 }
930 
getWindow(void) const931 HWND EV_Win32Toolbar::getWindow(void) const
932 {
933 	return m_hwnd;
934 }
935 
_getControlWindow(XAP_Toolbar_Id id)936 HWND EV_Win32Toolbar::_getControlWindow(XAP_Toolbar_Id id)
937 {
938 	TBBUTTON tbb;
939 	HWND hwndCtrl;
940 	UINT u = WmCommandFromItemId(id);
941 
942 	UT_uint32 k = SendMessageW(m_hwnd, TB_COMMANDTOINDEX, (WPARAM) u, 0);
943 	SendMessageW(m_hwnd, TB_GETBUTTON, (WPARAM) k, (LPARAM)(LPTBBUTTON) &tbb);
944 	UT_ASSERT(tbb.idCommand == (int) u);
945 	UT_ASSERT(tbb.fsStyle & TBSTYLE_SEP);
946 
947 	hwndCtrl = (HWND) tbb.dwData;
948 
949 	return hwndCtrl;
950 }
951 
_releaseListener(void)952 void EV_Win32Toolbar::_releaseListener(void)
953 {
954 	if (!m_pViewListener)
955 		return;
956 	DELETEP(m_pViewListener);
957 	m_pViewListener = 0;
958 	m_lid = 0;
959 }
960 
bindListenerToView(AV_View * pView)961 bool EV_Win32Toolbar::bindListenerToView(AV_View * pView)
962 {
963 	if(m_hwnd == NULL)
964 		return false;
965 
966 	_releaseListener();
967 
968 	m_pViewListener = new EV_Win32Toolbar_ViewListener(this,pView);
969 	UT_ASSERT(m_pViewListener);
970 
971 	UT_DebugOnly<bool> bResult = pView->addListener(static_cast<AV_Listener *>(m_pViewListener),&m_lid);
972 	UT_ASSERT(bResult);
973 
974 	if(pView->isDocumentPresent())
975 	{
976 		refreshToolbar(pView, AV_CHG_ALL);
977 	}
978 
979 	return true;
980 }
981 
refreshToolbar(AV_View * pView,AV_ChangeMask mask)982 bool EV_Win32Toolbar::refreshToolbar(AV_View * pView, AV_ChangeMask mask)
983 {
984 	if(m_hwnd == NULL)
985 		return false;
986 
987 	// make the toolbar reflect the current state of the document
988 	// at the current insertion point or selection.
989 
990 	const EV_Toolbar_ActionSet * pToolbarActionSet = m_pWin32App->getToolbarActionSet();
991 	UT_ASSERT(pToolbarActionSet);
992 
993 	UT_uint32 nrLabelItemsInLayout = m_pToolbarLayout->getLayoutItemCount();
994 	for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
995 	{
996 		EV_Toolbar_LayoutItem * pLayoutItem = m_pToolbarLayout->getLayoutItem(k);
997 		UT_continue_if_fail(pLayoutItem);
998 
999 		XAP_Toolbar_Id id = pLayoutItem->getToolbarId();
1000 		EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
1001 		UT_continue_if_fail(pAction);
1002 
1003 		AV_ChangeMask maskOfInterest = pAction->getChangeMaskOfInterest();
1004 		if ((maskOfInterest & mask) == 0)					// if this item doesn't care about
1005 			continue;										// changes of this type, skip it...
1006 
1007 		switch (pLayoutItem->getToolbarLayoutFlags())
1008 		{
1009 		case EV_TLF_Normal:
1010 			_refreshItem(pView, pAction, id);
1011 			break;
1012 
1013 		case EV_TLF_Spacer:
1014 			break;
1015 
1016 		default:
1017 			UT_ASSERT_HARMLESS(0);
1018 			break;
1019 		}
1020 	}
1021 
1022 	return true;
1023 }
1024 
_refreshID(XAP_Toolbar_Id id)1025 bool EV_Win32Toolbar::_refreshID(XAP_Toolbar_Id id)
1026 {
1027 	const EV_Toolbar_ActionSet * pToolbarActionSet = m_pWin32App->getToolbarActionSet();
1028 	UT_return_val_if_fail(pToolbarActionSet,false);
1029 
1030 	EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
1031 	UT_ASSERT(pAction);
1032 
1033 	AV_View * pView = m_pWin32Frame->getCurrentView();
1034 	UT_ASSERT(pView);
1035 
1036 	return _refreshItem(pView, pAction, id);
1037 }
1038 
_refreshItem(AV_View * pView,const EV_Toolbar_Action * pAction,XAP_Toolbar_Id id)1039 bool EV_Win32Toolbar::_refreshItem(AV_View * pView, const EV_Toolbar_Action * pAction, XAP_Toolbar_Id id)
1040 {
1041 	const char * szState = 0;
1042 	EV_Toolbar_ItemState tis = pAction->getToolbarItemState(pView,&szState);
1043 
1044 	UINT u = WmCommandFromItemId(id);
1045 
1046 	switch (pAction->getItemType())
1047 	{
1048 		// These two are unhandled and for the moment drop down to PushButton
1049 		case EV_TBIT_ColorFore:
1050 		case EV_TBIT_ColorBack:
1051 
1052 		case EV_TBIT_PushButton:
1053 			{
1054 				bool bGrayed = EV_TIS_ShouldBeGray(tis);
1055 
1056 				SendMessageW(m_hwnd, TB_ENABLEBUTTON, u, (!bGrayed ? 1 : 0)) ;
1057 
1058 				//UT_DEBUGMSG(("refreshToolbar: PushButton [%s] is %s\n",
1059 				//			m_pToolbarLabelSet->getLabel(id)->getToolbarLabel(),
1060 				//			((bGrayed) ? "disabled" : "enabled")));
1061 			}
1062 			break;
1063 
1064 		case EV_TBIT_ToggleButton:
1065 		case EV_TBIT_GroupButton:
1066 			{
1067 				bool bGrayed = EV_TIS_ShouldBeGray(tis);
1068 				bool bToggled = EV_TIS_ShouldBeToggled(tis);
1069 
1070 				SendMessageW(m_hwnd, TB_ENABLEBUTTON, u, (!bGrayed ? 1 : 0));
1071 				SendMessageW(m_hwnd, TB_CHECKBUTTON, u, (bToggled ? 1 : 0));
1072 
1073 				//UT_DEBUGMSG(("refreshToolbar: ToggleButton [%s] is %s and %s\n",
1074 				//			 m_pToolbarLabelSet->getLabel(id)->getToolbarLabel(),
1075 				//			 ((bGrayed) ? "disabled" : "enabled"),
1076 				//			 ((bToggled) ? "pressed" : "not pressed")));
1077 			}
1078 			break;
1079 
1080 		case EV_TBIT_ComboBox:
1081 			{
1082 				//bool bGrayed = EV_TIS_ShouldBeGray(tis);
1083 				//bool bString = EV_TIS_ShouldUseString(tis);
1084 				HWND hwndCombo = _getControlWindow(id);
1085 				UT_return_val_if_fail(hwndCombo, true);
1086 				std::string utf8;
1087 				UT_String str;
1088 
1089 				// NOTE: we always update the control even if !szState
1090 				if (!szState)
1091 				{
1092 					int idx = SendMessageW(hwndCombo, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)szState);
1093 					if (idx==CB_ERR)
1094 						SetWindowTextW(hwndCombo, L"");
1095 					break;
1096 				}
1097 
1098 				// Find the proper non-localised text
1099                 UT_Win32LocaleString localised;
1100 				if (id==AP_TOOLBAR_ID_FMT_STYLE)
1101 				{
1102                         pt_PieceTable::s_getLocalisedStyleName(szState, utf8);
1103 						localised.fromUTF8 (utf8.c_str());
1104                 }
1105                  else
1106     					localised.fromUTF8 (szState);
1107 
1108                 int idx = SendMessageW(hwndCombo, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)localised.c_str());
1109 				if (idx!=CB_ERR)
1110 					SendMessageW(hwndCombo, CB_SETCURSEL, idx, 0);
1111 				/*
1112 				 * If the string didn't exist within the combos list, we handle things differently for
1113 				 * different combos.
1114 				 */
1115 				if (idx==CB_ERR)
1116 				{
1117 					const XAP_StringSet * pSS;
1118 
1119 					switch (id)
1120 					{
1121 					/*
1122 					 * In the case of the font and font size combo, this means that the document contains a font not
1123 					 * installed on the system. Add it to the edit control, as is the case with the unix version.
1124 					 */
1125 					case AP_TOOLBAR_ID_FMT_SIZE:
1126 					case AP_TOOLBAR_ID_FMT_FONT:
1127 						idx = SendMessageW(hwndCombo, WM_SETTEXT, (WPARAM)-1, (LPARAM)localised.c_str());
1128 						if (idx == CB_ERR)
1129 						{
1130 							UT_DEBUGMSG(("refreshToolbar: Failed to set text for font combo.\n"));
1131 						}
1132 						break;
1133 					/*
1134 					 * If this is the zoom combo, select the "Other..." string.
1135 					 */
1136 					case AP_TOOLBAR_ID_ZOOM:
1137 						pSS = XAP_App::getApp()->getStringSet();
1138                         localised.fromUTF8 (pSS->getValue(XAP_STRING_ID_TB_Zoom_Percent));
1139 						idx = SendMessageW(hwndCombo, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)localised.c_str());
1140 						break;
1141 
1142 					case AP_TOOLBAR_ID_FMT_STYLE:
1143 						UT_DEBUGMSG(("refreshToolbar: Unknown string selected in style combo.\n"));
1144 						break;
1145 					default:
1146 						UT_DEBUGMSG(("refreshToolbar: Unknown string selected in unknown combo.\n"));
1147 						break;
1148 					}
1149 				}
1150 
1151 				//UT_DEBUGMSG(("refreshToolbar: ComboBox [%s] is %s and %s\n",
1152 				//			 m_pToolbarLabelSet->getLabel(id)->getToolbarLabel(),
1153 				//			 ((bGrayed) ? "disabled" : "enabled"),
1154 				//			 ((bString) ? szState : "no state")));
1155 			}
1156 			break;
1157 
1158 		case EV_TBIT_EditText:
1159 		case EV_TBIT_DropDown:
1160 		case EV_TBIT_StaticLabel:
1161 		case EV_TBIT_Spacer:
1162 			// TODO do these later...
1163 			break;
1164 
1165 
1166 		case EV_TBIT_BOGUS:
1167 		default:
1168 			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1169 			break;
1170 	}
1171 
1172 	return true;
1173 }
1174 
getToolTip(LPARAM lParam)1175 bool EV_Win32Toolbar::getToolTip(LPARAM lParam)
1176 {
1177 	UT_ASSERT(lParam);
1178 	LPTOOLTIPTEXTW lpttt = (LPTOOLTIPTEXTW) lParam;
1179 
1180 	// who's asking?
1181 	UINT idButton = lpttt->hdr.idFrom;
1182 	XAP_Toolbar_Id id = ItemIdFromWmCommand(idButton);
1183 
1184 	EV_Toolbar_Label * pLabel = m_pToolbarLabelSet->getLabel(id);
1185 	if (!pLabel)
1186 		return false;
1187 
1188 	// ok, gotcha
1189 	const char * szToolTip = pLabel->getToolTip();
1190 	if (!szToolTip || !*szToolTip)
1191 	{
1192 		szToolTip = pLabel->getStatusMsg();
1193 	}
1194 
1195 	if (!szToolTip || !*szToolTip)
1196 	{
1197 		szToolTip = pLabel->getToolbarLabel();
1198 	}
1199 
1200 	if (szToolTip && *szToolTip)
1201 	{
1202 		UT_Win32LocaleString str;
1203 		str.fromUTF8 (szToolTip);
1204 		wcsncpy(lpttt->lpszText, str.c_str(),80);
1205 	}
1206 	else
1207 	{
1208 		lpttt->lpszText[0] = '\0';
1209 	}
1210 	lpttt->hinst=NULL;
1211 
1212 	return true;
1213 }
1214 
1215 
show(void)1216 void EV_Win32Toolbar::show(void)
1217 {
1218 	UT_return_if_fail(m_pWin32Frame);
1219 	UT_DebugOnly<HWND> hRebar = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl())->getToolbarWindow();
1220 	UT_ASSERT(hRebar);
1221 	UT_DebugOnly<int> iBand = _getBandForHwnd(m_hwnd);
1222 	UT_ASSERT(iBand < 0);	// It can't already be displayed!
1223 	_addToRebar();
1224 
1225 	m_bVisible = true;
1226 }
1227 
hide(void)1228 void EV_Win32Toolbar::hide(void)
1229 {
1230 	UT_return_if_fail(m_pWin32Frame);
1231 	HWND hRebar = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl())->getToolbarWindow();
1232 	UT_ASSERT(hRebar);
1233 	const int iBand = _getBandForHwnd(m_hwnd);
1234 	if (iBand >= 0)
1235 	{
1236 		SendMessageW(hRebar, RB_DELETEBAND, (WPARAM)iBand, 0);
1237 		m_bVisible = false;
1238 	}
1239 }
1240 
1241 //
1242 // Returns the index of hToolbar in the rebar hRebar.
1243 // Returns -1 on error or if the toolbar wasn't recognized as a
1244 // child of the specified rebar control.
1245 //
_getBandForHwnd(HWND hToolbar) const1246 int EV_Win32Toolbar::_getBandForHwnd(HWND hToolbar) const
1247 {
1248 	HWND hRebar = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl())->getToolbarWindow();
1249 
1250 	// If we ever get more than 20 toolbars I don't wanna be around.
1251 	REBARBANDINFOW rbi;
1252 	memset(&rbi, 0, sizeof(rbi));
1253 	rbi.cbSize = sizeof(rbi);
1254 	rbi.fMask  = RBBIM_CHILD;
1255 	for (int i = 0; i < 20; ++i)
1256 	{
1257 		if (!SendMessageW(hRebar, RB_GETBANDINFO, (WPARAM)i, (LPARAM)&rbi))
1258 		{
1259 			continue;
1260 		}
1261 		if (hToolbar == rbi.hwndChild)
1262 		{
1263 			return i;
1264 		}
1265 	}
1266 	return -1;
1267 }
1268 
_addToRebar()1269 void EV_Win32Toolbar::_addToRebar()
1270 {
1271 	// Get the height of the toolbar.
1272 	DWORD dwBtnSize = SendMessageW(m_hwnd, TB_GETBUTTONSIZE, 0,0);
1273 
1274 	RECT rc;
1275 	GetWindowRect(m_hwnd, &rc);
1276 //	UINT iWidth = rc.right + 13;
1277 	UINT iWidth = rc.right - rc.left + 13;
1278 
1279 	// add this bar to the rebar
1280 	REBARBANDINFOW rbbi;
1281 	memset(&rbbi, 0, sizeof(rbbi));
1282 	// Initialize REBARBANDINFO
1283 	rbbi.cbSize = sizeof(REBARBANDINFOW);
1284 	rbbi.fMask =	RBBIM_COLORS	|	// clrFore and clrBack are valid
1285 					RBBIM_CHILD		|	// hwndChild is valid
1286 					RBBIM_CHILDSIZE	|	// cxMinChild and cyMinChild are valid
1287 					RBBIM_SIZE		|	// cx is valid
1288 					RBBIM_STYLE;		// fStyle is valid
1289 	rbbi.clrFore = GetSysColor(COLOR_BTNTEXT);
1290 	rbbi.clrBack = GetSysColor(COLOR_BTNFACE);
1291 	// NOT using RBBS_CHILDEDGE for fStyle gives us a slimmer look,
1292 	// better with the flat button style.
1293 	rbbi.fStyle =	RBBS_NOVERT			|	// do not display in vertical orientation
1294 					RBBS_BREAK;
1295 	rbbi.hwndChild = m_hwnd;
1296 	rbbi.cxMinChild = LOWORD(dwBtnSize);
1297 	rbbi.cyMinChild = HIWORD(dwBtnSize);
1298 	rbbi.cx = iWidth;
1299 
1300 	HWND hRebar = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl())->getToolbarWindow();
1301 	// Add it at the the end
1302 	SendMessageW(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbbi);
1303 }
1304 
1305 
getFrame(void)1306 XAP_Frame * EV_Win32Toolbar::getFrame(void)
1307 {
1308 	return m_pWin32Frame;
1309 }
1310 
1311 
1312 /*!
1313  * This method examines the current document and repopulates the Styles
1314  * Combo box with what is in the document. It returns false if no styles
1315  * combo box was found. True if it all worked.
1316  */
repopulateStyles(void)1317 bool EV_Win32Toolbar::repopulateStyles(void)
1318 {
1319 //
1320 // First off find the Styles combobox in a toolbar somewhere
1321 //
1322 	UT_uint32 count = m_pToolbarLayout->getLayoutItemCount();
1323 	UT_uint32 i =0;
1324 	EV_Toolbar_LayoutItem * pLayoutItem = NULL;
1325 	XAP_Toolbar_Id id;
1326 	for(i=0; i < count; i++)
1327 	{
1328 		pLayoutItem = m_pToolbarLayout->getLayoutItem(i);
1329 		id = pLayoutItem->getToolbarId();
1330 	//	wd = (_wd *) getNthItem(i);
1331 		if(id == AP_TOOLBAR_ID_FMT_STYLE)
1332 			break;
1333 	}
1334 	if(i>=count)
1335 		return false;
1336 
1337 
1338 
1339 //
1340 // GOT IT!
1341 //
1342   //	UT_ASSERT(wd->m_id == AP_TOOLBAR_ID_FMT_STYLE);
1343 	XAP_Toolbar_ControlFactory * pFactory = m_pWin32App->getControlFactory();
1344 	UT_return_val_if_fail(pFactory,false);
1345 	EV_Toolbar_Control * pControl = pFactory->getControl(this, id);
1346 	AP_Win32Toolbar_StyleCombo * pStyleC = static_cast<AP_Win32Toolbar_StyleCombo *>(pControl);
1347 	pStyleC->repopulate();
1348 
1349 
1350 	HWND hwndCombo = _getControlWindow(id);
1351 	UT_ASSERT(hwndCombo);
1352 	// GtkCombo * item = GTK_COMBO(wd->m_widget);
1353 //
1354 // Now the combo box has to be refilled from this
1355 //
1356 	const UT_GenericVector<const char*> * v = pControl->getContents();
1357 	UT_return_val_if_fail(v,false);
1358 
1359 //
1360 // Now  we must remove and delete the old data so we add the new
1361 // list of styles to the combo box.
1362 //
1363 // Try this....
1364 	SendMessageW(hwndCombo, WM_SETREDRAW, FALSE, 0);
1365 	SendMessageW(hwndCombo, CB_RESETCONTENT, 0 , 0);
1366 
1367 	SendMessageW(hwndCombo, CB_SETDROPPEDWIDTH,
1368 				(WPARAM)pStyleC->getDroppedWidth(), 0);
1369 
1370 //
1371 //	GtkList * oldlist = GTK_LIST(item->list);
1372 //	gtk_list_clear_items(oldlist,0,-1);
1373 //
1374 // Now make a new one.
1375 //
1376 	int	nItem;
1377 	std::string utf8;
1378 	UT_String str;
1379 
1380 	for (UT_sint32 c=0; c < m_vecOrgStylesNames.getItemCount(); c++)
1381 		delete m_vecOrgStylesNames.getNthItem(c);
1382 
1383 	m_vecOrgStylesNames.clear();
1384 
1385 
1386 	for (UT_sint32 k=0; k < v->getItemCount(); k++)
1387 	{
1388 		const char*	sz = (char *)v->getNthItem(k);
1389 		UT_Win32LocaleString localised;
1390 
1391 		pt_PieceTable::s_getLocalisedStyleName(sz, utf8);
1392 		localised.fromUTF8 (utf8.c_str());
1393 
1394 		nItem = SendMessageW(hwndCombo, CB_ADDSTRING,(WPARAM)0, (LPARAM)localised.c_str());
1395 		m_vecOrgStylesNames.addItem (new UT_UTF8String ((char *)v->getNthItem(k)));
1396 		SendMessageW(hwndCombo, CB_SETITEMDATA,(WPARAM)nItem, (LPARAM)m_vecOrgStylesNames.getItemCount()-1);
1397 	}
1398 //
1399 // Don't need this anymore and we don't like memory leaks in abi
1400 //
1401 	SendMessageW(hwndCombo, WM_SETREDRAW, TRUE, 0);
1402 	InvalidateRect (hwndCombo, NULL, true);
1403 	delete pStyleC;
1404 //
1405 // I think we've finished!
1406 //
1407 	return true;
1408 }
1409 
1410 /*
1411 	This method is called when the user clicks on the arrow next to the
1412 	foreground and background colour seletion buttons on the toolbar
1413 */
onDropArrow(UINT cmd)1414 void	EV_Win32Toolbar::onDropArrow(UINT cmd)
1415 {
1416 	AV_View * pView = m_pWin32Frame->getCurrentView();
1417 	XAP_Frame * pFrame = (XAP_Frame *) pView->getParentData();
1418 	UT_return_if_fail(pFrame);
1419 
1420 	UT_UCS4String ucs4color;
1421 	int id = ItemIdFromWmCommand(cmd);
1422 
1423 	pFrame->raise();
1424 
1425 	XAP_DialogFactory * pDialogFactory
1426 		= (XAP_DialogFactory *)(pFrame->getDialogFactory());
1427 
1428 	AP_Dialog_Background * pDialog
1429 		= (AP_Dialog_Background *)(pDialogFactory->requestDialog(AP_DIALOG_ID_BACKGROUND));
1430 	UT_ASSERT_HARMLESS(pDialog);
1431 	if (pDialog)
1432 	{
1433 		//
1434 		// Get Current color
1435 		//
1436 
1437 		const EV_Toolbar_ActionSet * pToolbarActionSet = m_pWin32App->getToolbarActionSet();
1438 		UT_return_if_fail(pToolbarActionSet);
1439 
1440 		const EV_Toolbar_Action * pAction = pToolbarActionSet->getAction(id);
1441 		if (!pAction)	return;
1442 
1443 
1444 		XAP_Win32FrameImpl* fimpl = static_cast<XAP_Win32FrameImpl*>(m_pWin32Frame->getFrameImpl());
1445 
1446 		if (!fimpl->m_sColorBack.empty() && pAction->getItemType() == EV_TBIT_ColorBack)
1447 			pDialog->setColor(fimpl->m_sColorBack.utf8_str());
1448 
1449 		if (!fimpl->m_sColorFore.empty() && pAction->getItemType() == EV_TBIT_ColorFore)
1450 			pDialog->setColor(fimpl->m_sColorFore.utf8_str());
1451 
1452 		pDialog->runModal (pFrame);
1453 
1454 		AP_Dialog_Background::tAnswer ans = pDialog->getAnswer();
1455 		bool bOK = (ans == AP_Dialog_Background::a_OK);
1456 
1457 		if (bOK)
1458 		{
1459 			UT_UTF8String strColor;
1460 			strColor = (reinterpret_cast<const char *>(pDialog->getColor()));
1461 
1462 			if (pAction->getItemType() == EV_TBIT_ColorBack)
1463 				fimpl->m_sColorBack = strColor;
1464 
1465 			if (pAction->getItemType() == EV_TBIT_ColorFore)
1466 				fimpl->m_sColorFore = strColor;
1467 
1468 			toolbarEvent(id, NULL, 0);
1469 		}
1470 
1471 		pDialogFactory->releaseDialog(pDialog);
1472 	}
1473 }
1474 
1475