[ 1420190 ] Enable backspace key on smartphone
[wxWidgets.git] / src / msw / wince / menuce.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/wince/menuce.cpp
3 // Purpose: Smartphone menus implementation
4 // Author: Wlodzimierz ABX Skiba
5 // Modified by:
6 // Created: 28.05.2004
7 // RCS-ID: $Id$
8 // Copyright: (c) Wlodzimierz Skiba
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if defined(__SMARTPHONE__) && defined(__WXWINCE__)
28
29 #ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/toplevel.h"
32 #include "wx/menu.h"
33 #endif //WX_PRECOMP
34
35 #include <windows.h>
36 #include <ole2.h>
37 #include <shellapi.h>
38 #include <aygshell.h>
39 #include <tpcshell.h>
40 #include "wx/msw/wince/missing.h"
41
42 #include "wx/msw/wince/resources.h"
43
44 #include "wx/stockitem.h"
45
46 wxTopLevelWindowMSW::ButtonMenu::ButtonMenu()
47 {
48 m_id = wxID_ANY;
49 m_label = wxEmptyString;
50 m_menu = NULL;
51 m_assigned = false;
52 }
53
54 wxTopLevelWindowMSW::ButtonMenu::~ButtonMenu()
55 {
56 if(m_menu)
57 {
58 delete m_menu;
59 m_menu = NULL;
60 };
61 }
62
63 void wxTopLevelWindowMSW::SetLeftMenu(int id, const wxString& label, wxMenu *subMenu)
64 {
65 m_LeftButton.SetButton(id, label, subMenu);
66 ReloadAllButtons();
67 }
68
69 void wxTopLevelWindowMSW::SetRightMenu(int id, const wxString& label, wxMenu *subMenu)
70 {
71 m_RightButton.SetButton(id, label, subMenu);
72 ReloadAllButtons();
73 }
74
75 void wxTopLevelWindowMSW::ButtonMenu::SetButton(int id, const wxString& label, wxMenu *subMenu)
76 {
77 m_assigned = true;
78 m_id = id;
79 if(label.empty() && wxIsStockID(id))
80 m_label = wxGetStockLabel(id, false);
81 else
82 m_label = label;
83 m_menu = subMenu;
84 }
85
86 wxMenu *wxTopLevelWindowMSW::ButtonMenu::DuplicateMenu(wxMenu *menu)
87 {
88 // This is required in case of converting wxMenuBar to wxMenu in wxFrame::SetMenuBar.
89 // All submenus has to be recreated because of new owner.
90
91 wxMenu *duplication = new wxMenu;
92
93 if (menu)
94 {
95 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
96 while (node)
97 {
98 wxMenuItem *item = node->GetData();
99 if (item)
100 {
101 wxMenu *submenu = NULL;
102
103 if(item->IsSubMenu())
104 submenu = DuplicateMenu( item->GetSubMenu() );
105 else
106 submenu = NULL;
107
108 wxMenuItem *new_item = wxMenuItem::New(duplication, item->GetId(), item->GetLabel(), item->GetHelp(), item->GetKind(), submenu);
109
110 if( item->IsCheckable() )
111 new_item->Check(item->IsChecked());
112
113 new_item->Enable( item->IsEnabled() );
114
115 duplication->Append(new_item);
116 }
117 node = node->GetNext();
118 }
119
120 }
121
122 return duplication;
123 }
124
125 void wxMenuToHMenu(wxMenu* in, HMENU hMenu)
126 {
127 if(!in) return;
128
129 wxChar buf[256];
130
131 wxMenuItemList::compatibility_iterator node = in->GetMenuItems().GetFirst();
132 while ( node )
133 {
134 wxMenuItem *item = node->GetData();
135
136 UINT uFlags = 0;
137 UINT uIDNewItem;
138 LPCTSTR lpNewItem;
139
140 if( item->IsSeparator() )
141 {
142 uFlags |= MF_SEPARATOR;
143 uIDNewItem = (unsigned)wxID_ANY;
144 lpNewItem = NULL;
145 }
146 else
147 {
148 // label
149 uFlags |= MF_STRING;
150 wxStrcpy(buf, item->GetLabel().c_str());
151 lpNewItem = buf;
152
153 // state
154 uFlags |= ( item->IsEnabled() ? MF_ENABLED : MF_GRAYED );
155
156 // checked
157 uFlags |= ( item->IsChecked() ? MF_CHECKED : MF_UNCHECKED );
158
159 if( item->IsSubMenu() )
160 {
161 uFlags |= MF_POPUP;
162 HMENU hSubMenu = CreatePopupMenu();
163 wxMenuToHMenu(item->GetSubMenu(), hSubMenu);
164 uIDNewItem = (UINT) hSubMenu;
165 }
166 else
167 {
168 uIDNewItem = item->GetId();
169 }
170 }
171
172 AppendMenu(hMenu, uFlags, uIDNewItem, lpNewItem);
173
174 node = node->GetNext();
175 }
176 }
177
178 void wxTopLevelWindowMSW::ReloadButton(ButtonMenu& button, UINT menuID)
179 {
180 TBBUTTONINFO button_info;
181 wxChar buf[256];
182
183 // set button name
184 memset (&button_info, 0, sizeof (TBBUTTONINFO));
185 button_info.cbSize = sizeof(TBBUTTONINFO);
186 button_info.dwMask = TBIF_TEXT | TBIF_STATE;
187 button_info.fsState = TBSTATE_ENABLED;
188 wxStrcpy(buf, button.GetLabel().c_str());
189 button_info.pszText = buf;
190 ::SendMessage(m_MenuBarHWND, TB_SETBUTTONINFO, menuID, (LPARAM) &button_info);
191
192 if(button.IsMenu())
193 {
194 HMENU hPopupMenu = (HMENU) ::SendMessage(m_MenuBarHWND, SHCMBM_GETSUBMENU, 0, menuID);
195 RemoveMenu(hPopupMenu, 0, MF_BYPOSITION);
196 wxMenuToHMenu(button.GetMenu(), hPopupMenu);
197 }
198 }
199
200 void wxTopLevelWindowMSW::ReloadAllButtons()
201 {
202 // first reaload only after initialization of both buttons
203 // it should is done at the end of Create() of wxTLW
204 if(!m_LeftButton.IsAssigned() || !m_RightButton.IsAssigned())
205 return;
206
207 SHMENUBARINFO menu_bar;
208 wxString label;
209
210 memset (&menu_bar, 0, sizeof (SHMENUBARINFO));
211 menu_bar.cbSize = sizeof (SHMENUBARINFO);
212 menu_bar.hwndParent = (HWND) GetHWND();
213
214 if(m_LeftButton.IsMenu() && m_RightButton.IsMenu())
215 menu_bar.nToolBarId = IDR_MENUBAR_BOTH_MENUS;
216 else if(m_LeftButton.IsMenu())
217 menu_bar.nToolBarId = IDR_MENUBAR_LEFT_MENU;
218 else if(m_RightButton.IsMenu())
219 menu_bar.nToolBarId = IDR_MENUBAR_RIGHT_MENU;
220 else
221 menu_bar.nToolBarId = IDR_MENUBAR_ONE_BUTTON;
222
223 menu_bar.hInstRes = wxGetInstance();
224
225 if (!SHCreateMenuBar(&menu_bar))
226 {
227 wxFAIL_MSG( _T("SHCreateMenuBar failed") );
228 return;
229 }
230
231 HWND prev_MenuBar = m_MenuBarHWND;
232 m_MenuBarHWND = menu_bar.hwndMB;
233
234 ReloadButton(m_LeftButton, IDM_LEFT);
235 ReloadButton(m_RightButton, IDM_RIGHT);
236
237 // hide previous and show new menubar
238 if ( prev_MenuBar )
239 ::ShowWindow( prev_MenuBar, SW_HIDE );
240 ::ShowWindow( m_MenuBarHWND, SW_SHOW );
241
242 // Setup backspace key handling
243 SendMessage(m_MenuBarHWND, SHCMBM_OVERRIDEKEY, VK_TBACK,
244 MAKELPARAM( SHMBOF_NODEFAULT | SHMBOF_NOTIFY,
245 SHMBOF_NODEFAULT | SHMBOF_NOTIFY ));
246 }
247
248 bool wxTopLevelWindowMSW::HandleCommand(WXWORD id, WXWORD WXUNUSED(cmd), WXHWND WXUNUSED(control))
249 {
250 // handle here commands from Smartphone menu bar
251 if ( id == IDM_LEFT || id == IDM_RIGHT )
252 {
253 int menuId = id == IDM_LEFT ? m_LeftButton.GetId() : m_RightButton.GetId() ;
254 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, menuId);
255 commandEvent.SetEventObject(this);
256 GetEventHandler()->ProcessEvent(commandEvent);
257 return true;
258 }
259 return false;
260 }
261
262 bool wxTopLevelWindowMSW::MSWShouldPreProcessMessage(WXMSG* pMsg)
263 {
264 MSG *msg = (MSG *)pMsg;
265
266 // Process back key to be like backspace.
267 if (msg->message == WM_HOTKEY)
268 {
269 if (HIWORD(msg->lParam) == VK_TBACK)
270 SHSendBackToFocusWindow(msg->message, msg->wParam, msg->lParam);
271 }
272
273 return wxTopLevelWindowBase::MSWShouldPreProcessMessage(pMsg);
274 }
275
276 #endif // __SMARTPHONE__ && __WXWINCE__