1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/nativdlg.cpp
3 // Purpose:     Native dialog loading code (part of wxWindow)
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     04/01/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14 
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 
23 #ifndef WX_PRECOMP
24     #include <stdio.h>
25 
26     #include "wx/wx.h"
27 #endif
28 
29 #include "wx/spinbutt.h"
30 #include "wx/msw/private.h"
31 
32 // ---------------------------------------------------------------------------
33 // global functions
34 // ---------------------------------------------------------------------------
35 
36 extern INT_PTR APIENTRY
37 wxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
38 
39 // ===========================================================================
40 // implementation
41 // ===========================================================================
42 
LoadNativeDialog(wxWindow * parent,wxWindowID id)43 bool wxWindow::LoadNativeDialog(wxWindow* parent, wxWindowID id)
44 {
45     m_windowId = id;
46 
47     wxWindowCreationHook hook(this);
48     m_hWnd = (WXHWND)::CreateDialog((HINSTANCE)wxGetInstance(),
49                                     MAKEINTRESOURCE(id),
50                                     parent ? (HWND)parent->GetHWND() : 0,
51                                     (DLGPROC) wxDlgProc);
52 
53     if ( !m_hWnd )
54         return false;
55 
56     SubclassWin(GetHWND());
57 
58     if ( parent )
59         parent->AddChild(this);
60     else
61         wxTopLevelWindows.Append(this);
62 
63     // Enumerate all children
64     HWND hWndNext;
65     hWndNext = ::GetWindow((HWND) m_hWnd, GW_CHILD);
66 
67     if (hWndNext)
68         CreateWindowFromHWND(this, (WXHWND) hWndNext);
69 
70     while (hWndNext != (HWND) NULL)
71     {
72         hWndNext = ::GetWindow(hWndNext, GW_HWNDNEXT);
73         if (hWndNext)
74             CreateWindowFromHWND(this, (WXHWND) hWndNext);
75     }
76 
77     return true;
78 }
79 
LoadNativeDialog(wxWindow * parent,const wxString & name)80 bool wxWindow::LoadNativeDialog(wxWindow* parent, const wxString& name)
81 {
82     SetName(name);
83 
84     wxWindowCreationHook hook(this);
85     m_hWnd = (WXHWND)::CreateDialog((HINSTANCE) wxGetInstance(),
86                                     name.c_str(),
87                                     parent ? (HWND)parent->GetHWND() : 0,
88                                     (DLGPROC)wxDlgProc);
89 
90     if ( !m_hWnd )
91         return false;
92 
93     SubclassWin(GetHWND());
94 
95     if ( parent )
96         parent->AddChild(this);
97     else
98         wxTopLevelWindows.Append(this);
99 
100     // Enumerate all children
101     HWND hWndNext;
102     hWndNext = ::GetWindow((HWND) m_hWnd, GW_CHILD);
103 
104     if (hWndNext)
105         CreateWindowFromHWND(this, (WXHWND) hWndNext);
106 
107     while (hWndNext != (HWND) NULL)
108     {
109         hWndNext = ::GetWindow(hWndNext, GW_HWNDNEXT);
110         if (hWndNext)
111             CreateWindowFromHWND(this, (WXHWND) hWndNext);
112     }
113 
114     return true;
115 }
116 
117 // ---------------------------------------------------------------------------
118 // look for child by id
119 // ---------------------------------------------------------------------------
120 
GetWindowChild1(wxWindowID id)121 wxWindow* wxWindow::GetWindowChild1(wxWindowID id)
122 {
123     if ( m_windowId == id )
124         return this;
125 
126     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
127     while ( node )
128     {
129         wxWindow* child = node->GetData();
130         wxWindow* win = child->GetWindowChild1(id);
131         if ( win )
132             return win;
133 
134         node = node->GetNext();
135     }
136 
137     return NULL;
138 }
139 
GetWindowChild(wxWindowID id)140 wxWindow* wxWindow::GetWindowChild(wxWindowID id)
141 {
142     wxWindow* win = GetWindowChild1(id);
143     if ( !win )
144     {
145         HWND hwnd = ::GetDlgItem(GetHwnd(), id);
146         if ( hwnd )
147         {
148             win = CreateWindowFromHWND(this, (WXHWND) hwnd);
149         }
150     }
151 
152     return win;
153 }
154 
155 // ---------------------------------------------------------------------------
156 // create wxWin window from a native HWND
157 // ---------------------------------------------------------------------------
158 
CreateWindowFromHWND(wxWindow * parent,WXHWND hWnd)159 wxWindow* wxWindow::CreateWindowFromHWND(wxWindow* parent, WXHWND hWnd)
160 {
161     wxCHECK_MSG( parent, NULL, wxT("must have valid parent for a control") );
162 
163     wxString str(wxGetWindowClass(hWnd));
164     str.UpperCase();
165 
166     long id = wxGetWindowId(hWnd);
167     long style = GetWindowLong((HWND) hWnd, GWL_STYLE);
168 
169     wxWindow* win = NULL;
170 
171     if (str == wxT("BUTTON"))
172     {
173         int style1 = (style & 0xFF);
174 #if wxUSE_CHECKBOX
175         if ((style1 == BS_3STATE) || (style1 == BS_AUTO3STATE) || (style1 == BS_AUTOCHECKBOX) ||
176             (style1 == BS_CHECKBOX))
177         {
178             win = new wxCheckBox;
179         }
180         else
181 #endif
182 #if wxUSE_RADIOBTN
183         if ((style1 == BS_AUTORADIOBUTTON) || (style1 == BS_RADIOBUTTON))
184         {
185             win = new wxRadioButton;
186         }
187         else
188 #endif
189 #if wxUSE_BMPBUTTON
190         if (style & BS_BITMAP)
191         {
192             // TODO: how to find the bitmap?
193             win = new wxBitmapButton;
194             wxLogError(wxT("Have not yet implemented bitmap button as BS_BITMAP button."));
195         }
196         else
197         if (style1 == BS_OWNERDRAW)
198         {
199             // TODO: how to find the bitmap?
200             // TODO: can't distinguish between bitmap button and bitmap static.
201             // Change implementation of wxStaticBitmap to SS_BITMAP.
202             // PROBLEM: this assumes that we're using resource-based bitmaps.
203             // So maybe need 2 implementations of bitmap buttons/static controls,
204             // with a switch in the drawing code. Call default proc if BS_BITMAP.
205             win = new wxBitmapButton;
206         }
207         else
208 #endif
209 #if wxUSE_BUTTON
210         if ((style1 == BS_PUSHBUTTON) || (style1 == BS_DEFPUSHBUTTON))
211         {
212             win = new wxButton;
213         }
214         else
215 #endif
216 #if wxUSE_STATBOX
217         if (style1 == BS_GROUPBOX)
218         {
219             win = new wxStaticBox;
220         }
221         else
222 #endif
223         {
224             wxLogError(wxT("Don't know what kind of button this is: id = %ld"),
225                        id);
226         }
227     }
228 #if wxUSE_COMBOBOX
229     else if (str == wxT("COMBOBOX"))
230     {
231         win = new wxComboBox;
232     }
233 #endif
234 #if wxUSE_TEXTCTRL
235     // TODO: Problem if the user creates a multiline - but not rich text - text control,
236     // since wxWin assumes RichEdit control for this. Should have m_isRichText in
237     // wxTextCtrl. Also, convert as much of the window style as is necessary
238     // for correct functioning.
239     // Could have wxWindow::AdoptAttributesFromHWND(WXHWND)
240     // to be overridden by each control class.
241     else if (str == wxT("EDIT"))
242     {
243         win = new wxTextCtrl;
244     }
245 #endif
246 #if wxUSE_LISTBOX
247     else if (str == wxT("LISTBOX"))
248     {
249         win = new wxListBox;
250     }
251 #endif
252 #if wxUSE_SCROLLBAR
253     else if (str == wxT("SCROLLBAR"))
254     {
255         win = new wxScrollBar;
256     }
257 #endif
258 #if wxUSE_SPINBTN
259     else if (str == wxT("MSCTLS_UPDOWN32"))
260     {
261         win = new wxSpinButton;
262     }
263 #endif
264 #if wxUSE_SLIDER
265     else if (str == wxT("MSCTLS_TRACKBAR32"))
266     {
267         // Need to ascertain if it's horiz or vert
268         win = new wxSlider;
269     }
270 #endif // wxUSE_SLIDER
271 #if wxUSE_STATTEXT
272     else if (str == wxT("STATIC"))
273     {
274         int style1 = (style & 0xFF);
275 
276         if ((style1 == SS_LEFT) || (style1 == SS_RIGHT)
277             || (style1 == SS_SIMPLE)
278             )
279             win = new wxStaticText;
280 #if wxUSE_STATBMP
281         else if (style1 == SS_BITMAP)
282         {
283             win = new wxStaticBitmap;
284 
285             // Help! this doesn't correspond with the wxWin implementation.
286             wxLogError(wxT("Please make SS_BITMAP statics into owner-draw buttons."));
287         }
288 #endif /* wxUSE_STATBMP */
289     }
290 #endif
291     else
292     {
293         wxString msg(wxT("Don't know how to convert from Windows class "));
294         msg += str;
295         wxLogError(msg);
296     }
297 
298     if (win)
299     {
300         parent->AddChild(win);
301         win->SubclassWin(hWnd);
302         win->AdoptAttributesFromHWND();
303     }
304 
305     return win;
306 }
307 
308 // Make sure the window style (etc.) reflects the HWND style (roughly)
AdoptAttributesFromHWND()309 void wxWindow::AdoptAttributesFromHWND()
310 {
311     SetId(wxGetWindowId(m_hWnd));
312 
313     long style = GetWindowLong(GetHwnd(), GWL_STYLE);
314 
315     if (style & WS_VSCROLL)
316         m_windowStyle |= wxVSCROLL;
317     if (style & WS_HSCROLL)
318         m_windowStyle |= wxHSCROLL;
319 }
320