]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxlwindow.cpp
Win compilation fixes
[wxWidgets.git] / user / wxLayout / wxlwindow.cpp
1 /*-*- c++ -*-********************************************************
2 * wxLwindow.h : a scrolled Window for displaying/entering rich text*
3 * *
4 * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net) *
5 * *
6 * $Id$
7 *******************************************************************/
8
9 #ifdef __GNUG__
10 # pragma implementation "wxlwindow.h"
11 #endif
12
13 //#include "Mpch.h"
14
15 #ifdef M_BASEDIR
16 # ifndef USE_PCH
17 # include "Mcommon.h"
18 # include "gui/wxMenuDefs.h"
19 # include "gui/wxMApp.h"
20 # endif // USE_PCH
21 # include "gui/wxlwindow.h"
22 #else
23 # ifdef __WXMSW__
24 # include <windows.h>
25 # undef FindWindow
26 # undef GetCharWidth
27 # undef StartDoc
28 # endif
29 # include "wxlwindow.h"
30 #endif
31
32 BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
33 EVT_PAINT (wxLayoutWindow::OnPaint)
34 EVT_CHAR (wxLayoutWindow::OnChar)
35 EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
36 EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
37 EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
38 EVT_MENU_RANGE(WXLOWIN_MENU_FIRST, WXLOWIN_MENU_LAST, wxLayoutWindow::OnMenu)
39 EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
40 EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
41 END_EVENT_TABLE()
42 /*
43
44 EVT_MENU(WXLOWIN_MENU_LARGER, wxLayoutWindow::OnMenu)
45 EVT_MENU(WXLOWIN_MENU_SMALLER, wxLayoutWindow::OnMenu)
46 EVT_MENU(WXLOWIN_MENU_UNDERLINE_ON, wxLayoutWindow::OnMenu)
47 EVT_MENU(WXLOWIN_MENU_UNDERLINE_OFF, wxLayoutWindow::OnMenu)
48 EVT_MENU(WXLOWIN_MENU_BOLD_ON, wxLayoutWindow::OnMenu)
49 EVT_MENU(WXLOWIN_MENU_BOLD_OFF, wxLayoutWindow::OnMenu)
50 EVT_MENU(WXLOWIN_MENU_ITALICS_ON, wxLayoutWindow::OnMenu)
51 EVT_MENU(WXLOWIN_MENU_ITALICS_OFF, wxLayoutWindow::OnMenu)
52 EVT_MENU(WXLOWIN_MENU_ROMAN, wxLayoutWindow::OnMenu)
53 EVT_MENU(WXLOWIN_MENU_TYPEWRITER, wxLayoutWindow::OnMenu)
54 EVT_MENU(WXLOWIN_MENU_SANSSERIF, wxLayoutWindow::OnMenu)
55 */
56
57 wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
58 : wxScrolledWindow(parent, -1, wxDefaultPosition, wxDefaultSize,
59 wxHSCROLL | wxVSCROLL | wxBORDER)
60
61 {
62 m_Editable = false;
63 m_doSendEvents = false;
64 m_ViewStartX = 0; m_ViewStartY = 0;
65 m_DoPopupMenu = true;
66 m_PopupMenu = MakeFormatMenu();
67 m_memDC = new wxMemoryDC;
68 m_bitmap = new wxBitmap(4,4);
69 m_bitmapSize = wxPoint(4,4);
70 m_llist = new wxLayoutList();
71 wxPoint max = m_llist->GetSize();
72 SetScrollbars(10, 20 /*lineHeight*/, max.x/10+1, max.y/20+1);
73 EnableScrolling(true,true);
74 m_maxx = max.x; m_maxy = max.y;
75 SetDirty();
76 }
77
78 wxLayoutWindow::~wxLayoutWindow()
79 {
80 delete m_memDC; // deletes bitmap automatically (?)
81 delete m_bitmap;
82 delete m_llist;
83 delete m_PopupMenu;
84 }
85
86 #ifdef __WXMSW__
87 long
88 wxLayoutWindow::MSWGetDlgCode()
89 {
90 // if we don't return this, we won't get OnChar() events for TABs and ENTER
91 return DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_WANTMESSAGE;
92 }
93 #endif //MSW
94
95 void
96 wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
97 {
98 if(!m_doSendEvents) // nothing to do
99 return;
100
101 wxPaintDC dc( this );
102 PrepareDC( dc );
103 SetFocus();
104
105 wxPoint findPos;
106 findPos.x = dc.DeviceToLogicalX(event.GetX());
107 findPos.y = dc.DeviceToLogicalY(event.GetY());
108
109 #ifdef WXLAYOUT_DEBUG
110 wxLogDebug("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)",
111 event.GetX(), event.GetY(), findPos.x, findPos.y);
112 #endif
113
114 m_ClickPosition = findPos;
115 wxLayoutObject *obj = m_llist->FindObject(findPos);
116
117 #ifdef WXLAYOUT_DEBUG
118 if(obj)
119 wxLogDebug("wxLayoutWindow::OnMouse: Found object of type %d.",
120 obj->GetType());
121 else
122 wxLogDebug("wxLayoutWindow::OnMouse: Found no object.");
123 #endif
124
125 // only do the menu if activated, editable and not on a clickable object
126 if(eventId == WXLOWIN_MENU_RCLICK
127 && IsEditable()
128 && (! obj || (obj && obj->GetUserData() == NULL))
129 )
130 {
131 PopupMenu(m_PopupMenu, event.GetX(), event.GetY());
132 return;
133 }
134 // find the object at this position
135 if(obj)
136 {
137 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, eventId);
138 commandEvent.SetEventObject( this );
139 commandEvent.SetClientData((char *)obj);
140 GetEventHandler()->ProcessEvent(commandEvent);
141 }
142 }
143
144 /*
145 * Some simple keyboard handling.
146 */
147 void
148 wxLayoutWindow::OnChar(wxKeyEvent& event)
149 {
150 if(!IsEditable()) // do nothing
151 {
152 event.Skip();
153 return;
154 }
155
156 long keyCode = event.KeyCode();
157
158 /* First, handle control keys */
159 if(event.ControlDown() && ! event.AltDown())
160 {
161 switch(event.KeyCode())
162 {
163 case WXK_DELETE :
164 case 'd':
165 m_llist->Delete(1);
166 break;
167 case 'y':
168 m_llist->DeleteLines(1);
169 break;
170 case 'h': // like backspace
171 if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
172 break;
173 case 'u':
174 m_llist->DeleteToBeginOfLine();
175 break;
176 case 'k':
177 m_llist->DeleteToEndOfLine();
178 break;
179 default:
180 ;
181 }
182 }
183 // ALT only:
184 else if( event.AltDown() && ! event.ControlDown() )
185 {
186 switch(event.KeyCode())
187 {
188 case WXK_DELETE:
189 case 'd':
190 m_llist->DeleteWord();
191 break;
192 default:
193 ;
194 }
195 }
196 // no control keys:
197 else if ( ! event.AltDown() && ! event.ControlDown())
198 {
199 switch(event.KeyCode())
200 {
201 case WXK_RIGHT:
202 m_llist->MoveCursorHorizontally(1);
203 break;
204 case WXK_LEFT:
205 m_llist->MoveCursorHorizontally(-1);
206 break;
207 case WXK_UP:
208 m_llist->MoveCursorVertically(-1);
209 break;
210 case WXK_DOWN:
211 m_llist->MoveCursorVertically(1);
212 break;
213 case WXK_PRIOR:
214 m_llist->MoveCursorVertically(-20);
215 break;
216 case WXK_NEXT:
217 m_llist->MoveCursorVertically(20);
218 break;
219 case WXK_HOME:
220 m_llist->MoveCursorToBeginOfLine();
221 break;
222 case WXK_END:
223 m_llist->MoveCursorToEndOfLine();
224 break;
225 case WXK_DELETE :
226 m_llist->Delete(1);
227 break;
228 case WXK_BACK: // backspace
229 if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
230 break;
231 case WXK_RETURN:
232 m_llist->LineBreak();
233 break;
234 default:
235 if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
236 && (keyCode < 256 && keyCode >= 32)
237 )
238 {
239 wxString tmp;
240 tmp += keyCode;
241 m_llist->Insert(tmp);
242 //// m_llist->WrapLine();
243 }
244 break;
245 }
246 }
247 SetDirty();
248 DoPaint(true); // paint and scroll to cursor
249 }
250
251 void
252 wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
253 {
254 DoPaint();
255 }
256
257 void
258 wxLayoutWindow::DoPaint(bool scrollToCursor)
259 {
260 wxPaintDC dc( this );
261 PrepareDC( dc );
262
263 int x0,y0,x1,y1, dx, dy;
264
265 // Calculate where the top of the visible area is:
266 ViewStart(&x0,&y0);
267 GetScrollPixelsPerUnit(&dx, &dy);
268 x0 *= dx; y0 *= dy;
269
270 // Get the size of the visible window:
271 GetClientSize(&x1,&y1);
272 wxASSERT(x1 > 0);
273
274 wxASSERT(y1 > 0);
275
276 // Maybe we need to change the scrollbar sizes or positions,
277 // so layout the list and check:
278 if(IsDirty() || scrollToCursor)
279 m_llist->Layout(dc);
280 if(IsDirty())
281 ResizeScrollbars();
282
283 /* Make sure that the scrollbars are at a position so that the
284 cursor is visible if we are editing. */
285 /** Scroll so that cursor is visible! */
286 if(IsEditable() && scrollToCursor)
287 {
288 wxPoint cc = m_llist->GetCursorScreenPos();
289 if(cc.x < x0 || cc.y < y0
290 || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10)) // (9*x)/10 == 90%
291 {
292 int nx, ny;
293 nx = cc.x - x1/2; if(nx < 0) nx = 0;
294 ny = cc.y - y1/2; if(ny < 0) ny = 0;
295 Scroll(nx/dx,ny/dy); // new view start
296 x0 = nx; y0 = ny;
297 }
298 }
299
300 /* Check whether the window has grown, if so, we need to reallocate
301 the bitmap to be larger. */
302 if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
303 {
304 wxASSERT(m_bitmapSize.x > 0);
305 wxASSERT(m_bitmapSize.y > 0);
306
307 m_memDC->SelectObject(wxNullBitmap);
308 delete m_bitmap;
309 m_bitmapSize = wxPoint(x1,y1);
310 m_bitmap = new wxBitmap(x1,y1);
311 m_memDC->SelectObject(*m_bitmap);
312 }
313 // Device origins on the memDC are suspect, we translate manually
314 // with the translate parameter of Draw().
315 m_memDC->SetDeviceOrigin(0,0);
316 m_memDC->Clear();
317
318 // The +4 give the window a tiny border on the left and top, looks nice.
319 wxPoint offset(-x0+4,-y0+4);
320 m_llist->Draw(*m_memDC,offset);
321 if(IsEditable())
322 m_llist->DrawCursor(*m_memDC,m_HaveFocus,offset);
323 // Now copy everything to the screen:
324 dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
325
326
327 ResetDirty();
328 }
329
330 // change the range and position of scroll bars
331 void
332 wxLayoutWindow::ResizeScrollbars(bool exact)
333 {
334 wxPoint max = m_llist->GetSize();
335
336 if(max.x > m_maxx || max.y > m_maxy
337 || max.x < (7*m_maxx)/10 || max.y << (7*m_maxy)/10
338 || exact)
339 {
340 if(! exact) // add an extra 20% to the sizes to avoid future updates
341 {
342 max.x = (12*max.x)/10; // 12/20 = 120%
343 max.y = (12*max.y)/10;
344 }
345 ViewStart(&m_ViewStartX, &m_ViewStartY);
346 SetScrollbars(10, 20, max.x/10+1,max.y/20+1,m_ViewStartX,m_ViewStartY,true);
347 m_maxx = max.x; m_maxy = max.y;
348 }
349 }
350
351
352 wxMenu *
353 wxLayoutWindow::MakeFormatMenu()
354 {
355 wxMenu *m = new wxMenu(_("Layout Menu"));
356
357 m->Append(WXLOWIN_MENU_LARGER ,_("&Larger"),_("Switch to larger font."), false);
358 m->Append(WXLOWIN_MENU_SMALLER ,_("&Smaller"),_("Switch to smaller font."), false);
359 m->AppendSeparator();
360 m->Append(WXLOWIN_MENU_UNDERLINE_ON, _("&Underline on"),_("Activate underline mode."), false);
361 m->Append(WXLOWIN_MENU_UNDERLINE_OFF,_("&Underline off"),_("Deactivate underline mode."), false);
362 m->Append(WXLOWIN_MENU_BOLD_ON ,_("&Bold on"),_("Activate bold mode."), false);
363 m->Append(WXLOWIN_MENU_BOLD_OFF ,_("&Bold off"),_("Deactivate bold mode."), false);
364 m->Append(WXLOWIN_MENU_ITALICS_ON ,_("&Italics on"),_("Activate italics mode."), false);
365 m->Append(WXLOWIN_MENU_ITALICS_OFF ,_("&Italics off"),_("Deactivate italics mode."), false);
366 m->AppendSeparator();
367 m->Append(WXLOWIN_MENU_ROMAN ,_("&Roman"),_("Switch to roman font."), false);
368 m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Switch to typewriter font."), false);
369 m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Switch to sans serif font."), false);
370 return m;
371 }
372
373 void wxLayoutWindow::OnMenu(wxCommandEvent& event)
374 {
375 switch (event.GetId())
376 {
377 case WXLOWIN_MENU_LARGER:
378 m_llist->SetFontLarger(); break;
379 case WXLOWIN_MENU_SMALLER:
380 m_llist->SetFontSmaller(); break;
381 case WXLOWIN_MENU_UNDERLINE_ON:
382 m_llist->SetFontUnderline(true); break;
383 case WXLOWIN_MENU_UNDERLINE_OFF:
384 m_llist->SetFontUnderline(false); break;
385 case WXLOWIN_MENU_BOLD_ON:
386 m_llist->SetFontWeight(wxBOLD); break;
387 case WXLOWIN_MENU_BOLD_OFF:
388 m_llist->SetFontWeight(wxNORMAL); break;
389 case WXLOWIN_MENU_ITALICS_ON:
390 m_llist->SetFontStyle(wxITALIC); break;
391 case WXLOWIN_MENU_ITALICS_OFF:
392 m_llist->SetFontStyle(wxNORMAL); break;
393 case WXLOWIN_MENU_ROMAN:
394 m_llist->SetFontFamily(wxROMAN); break;
395 case WXLOWIN_MENU_TYPEWRITER:
396 m_llist->SetFontFamily(wxFIXED); break;
397 case WXLOWIN_MENU_SANSSERIF:
398 m_llist->SetFontFamily(wxSWISS); break;
399 }
400 }
401
402 void
403 wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
404 {
405 m_HaveFocus = true;
406 DoPaint(); // to repaint the cursor
407 }
408
409 void
410 wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
411 {
412 m_HaveFocus = true;
413 DoPaint(); // to repaint the cursor
414 }