]> git.saurik.com Git - wxWidgets.git/blob - user/wxLayout/wxlwindow.cpp
Added more makefiles; fixed some samples for Cygwin
[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_PREFIX
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
26 # undef FindWindow
27 # undef GetCharWidth
28 # undef StartDoc
29 # endif
30
31 # include "wxlwindow.h"
32 # define TRACEMESSAGE(x)
33 #endif
34 # define WXL_VAR(x) { wxString s; s << #x " = " << x; wxLogDebug(s); }
35
36 BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
37 EVT_PAINT (wxLayoutWindow::OnPaint)
38 EVT_CHAR (wxLayoutWindow::OnChar)
39
40 EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
41 EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
42 EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
43 EVT_MENU(WXLOWIN_MENU_LARGER, wxLayoutWindow::OnMenu)
44 EVT_MENU(WXLOWIN_MENU_SMALLER, wxLayoutWindow::OnMenu)
45 EVT_MENU(WXLOWIN_MENU_UNDERLINE, wxLayoutWindow::OnMenu)
46 EVT_MENU(WXLOWIN_MENU_BOLD, wxLayoutWindow::OnMenu)
47 EVT_MENU(WXLOWIN_MENU_ITALICS, wxLayoutWindow::OnMenu)
48 EVT_MENU(WXLOWIN_MENU_ROMAN, wxLayoutWindow::OnMenu)
49 EVT_MENU(WXLOWIN_MENU_TYPEWRITER, wxLayoutWindow::OnMenu)
50 EVT_MENU(WXLOWIN_MENU_SANSSERIF, wxLayoutWindow::OnMenu)
51 EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus)
52 EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
53 END_EVENT_TABLE()
54
55 wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
56 : wxScrolledWindow(parent, -1, wxDefaultPosition, wxDefaultSize,
57 wxHSCROLL | wxVSCROLL | wxBORDER)
58
59 {
60 m_doSendEvents = false;
61 m_ViewStartX = 0; m_ViewStartY = 0;
62 m_DoPopupMenu = true;
63 m_PopupMenu = NULL;
64 m_memDC = new wxMemoryDC;
65 m_bitmap = new wxBitmap(4,4);
66 m_bitmapSize = wxPoint(4,4);
67
68 CoordType
69 max_x, max_y, lineHeight;
70 m_llist.GetSize(&max_x, &max_y, &lineHeight);
71 SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1);
72 EnableScrolling(true,true);
73 m_maxx = max_x; m_maxy = max_y; m_lineHeight = lineHeight;
74 }
75
76 wxLayoutWindow::~wxLayoutWindow()
77 {
78 delete m_memDC; // deletes bitmap automatically (?)
79 delete m_bitmap;
80 if(m_PopupMenu) delete m_PopupMenu;
81 }
82
83 #ifdef __WXMSW__
84 long
85 wxLayoutWindow::MSWGetDlgCode()
86 {
87 // if we don't return this, we won't get OnChar() events for TABs and ENTER
88 return DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_WANTMESSAGE;
89 }
90 #endif //MSW
91
92 void
93 wxLayoutWindow::Update(void)
94 {
95 if(IsDirty())
96 {
97 UpdateScrollbars();
98 DoPaint();
99 }
100 else
101 DoPaint(true); // only the cursor
102 return;
103 }
104
105 void
106 wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
107 {
108 if(!m_doSendEvents) // nothing to do
109 return;
110
111 wxPaintDC dc( this );
112 PrepareDC( dc );
113 SetFocus();
114
115 wxPoint findPos;
116 findPos.x = dc.DeviceToLogicalX(event.GetX());
117 findPos.y = dc.DeviceToLogicalY(event.GetY());
118
119 TRACEMESSAGE(("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)",
120 event.GetX(), event.GetY(), findPos.x, findPos.y));
121
122 m_ClickPosition = findPos;
123 wxLayoutObjectBase *obj = m_llist.Find(findPos);
124
125 // only do the menu if activated, editable and not on a clickable object
126 if(eventId == WXLOWIN_MENU_RCLICK
127 && m_DoPopupMenu
128 && m_llist.IsEditable()
129 && obj && obj->GetUserData() == NULL)
130 {
131 // when does this menu get freed?
132 // how do we handle toggling? FIXME
133 PopupMenu(MakeFormatMenu(), event.GetX(), event.GetY());
134 return;
135 }
136 // find the object at this position
137 if(obj)
138 {
139 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, eventId);
140 commandEvent.SetEventObject( this );
141 commandEvent.SetClientData((char *)obj);
142 GetEventHandler()->ProcessEvent(commandEvent);
143 }
144 }
145
146 void
147 wxLayoutWindow::DeleteToEndOfLine(void)
148 {
149 int help = m_llist.GetLineLength(
150 m_llist.GetCurrentObject())
151 - m_llist.GetCursor().x;
152 m_llist.Delete(help>1 ? help-1 : 1);
153 }
154
155 void
156 wxLayoutWindow::GotoEndOfLine(void)
157 {
158 wxPoint p = m_llist.GetCursor();
159 p.x = m_llist.GetLineLength(m_llist.GetCurrentObject());
160 if(p.x > 0) p.x --; // do not count the linebreak
161 m_llist.SetCursor(p);
162 }
163
164 void
165 wxLayoutWindow::GotoBeginOfLine(void)
166 {
167 wxPoint p = m_llist.GetCursor();
168 p.x = 0;
169 m_llist.SetCursor(p);
170 }
171
172 void
173 wxLayoutWindow::DeleteLine(void)
174 {
175 GotoBeginOfLine();
176 DeleteToEndOfLine();
177 m_llist.Delete(1); // newline
178 }
179
180 void
181 wxLayoutWindow::DeleteToBeginOfLine(void)
182 {
183 wxPoint p = m_llist.GetCursor();
184 int count = p.x;
185 if(count > 0)
186 {
187 p.x = 0;
188 m_llist.SetCursor(p);
189 m_llist.Delete(count);
190 }
191 }
192
193
194 void
195 wxLayoutWindow::ScrollToCursor(void)
196 {
197 /** Scroll so that cursor is visible! */
198 int x0,y0,x1,y1,ux,uy;
199 ViewStart(&x0,&y0);
200 GetScrollPixelsPerUnit(&ux,&uy);
201 x0*=ux; y0*=uy;
202 GetClientSize(&x1,&y1);
203
204 wxPoint cc = m_llist.GetCursorCoords();
205
206 if(cc.x < x0 || cc.y < y0
207 || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10)) // (9*x)/10 == 90%
208 {
209 int nx, ny;
210 nx = cc.x - (8*x1)/10; if(nx < 0) nx = 0;
211 ny = cc.y - (8*y1)/10; if(ny < 0) ny = 0;
212 Scroll(nx/ux,ny/uy);
213 }
214 }
215
216 /*
217 * some simple keyboard handling
218 */
219 void
220 wxLayoutWindow::OnChar(wxKeyEvent& event)
221 {
222 if(! m_llist.IsEditable()) // do nothing
223 {
224 event.Skip();
225 return;
226 }
227
228 long keyCode = event.KeyCode();
229
230 /* First, handle control keys */
231 if(event.ControlDown())
232 {
233 switch(event.KeyCode())
234 {
235 case WXK_DELETE :
236 case 'k':
237 DeleteToEndOfLine(); break;
238 case 'd':
239 m_llist.Delete(1); break;
240 case 'y':
241 DeleteLine(); break;
242 case 'h': // like backspace
243 if(m_llist.MoveCursor(-1))
244 m_llist.Delete(1);
245 break;
246 case 'u':
247 DeleteToBeginOfLine(); break;
248 default:
249 ;
250 }
251 }
252 else // no control keys
253 {
254 switch(event.KeyCode())
255 {
256 case WXK_RIGHT:
257 m_llist.MoveCursor(1);
258 break;
259 case WXK_LEFT:
260 m_llist.MoveCursor(-1);
261 break;
262 case WXK_UP:
263 m_llist.MoveCursor(0,-1);
264 break;
265 case WXK_DOWN:
266 m_llist.MoveCursor(0,1);
267 break;
268 case WXK_PRIOR:
269 m_llist.MoveCursor(0,-20);
270 break;
271 case WXK_NEXT:
272 m_llist.MoveCursor(0,20);
273 break;
274 case WXK_HOME:
275 GotoBeginOfLine();
276 break;
277 case WXK_END:
278 GotoEndOfLine();
279 break;
280 case WXK_DELETE :
281 if(event.ControlDown()) // delete to end of line
282 DeleteToEndOfLine();
283 else
284 m_llist.Delete(1);
285 break;
286 case WXK_BACK: // backspace
287 if(m_llist.MoveCursor(-1)) {
288 m_llist.Delete(1);
289 }
290 break;
291 case WXK_RETURN:
292 m_llist.LineBreak();
293 break;
294
295 #ifdef WXLAYOUT_DEBUG
296 case WXK_F1:
297 m_llist.Debug();
298 break;
299 case WXK_F2:
300 m_llist.WrapLine();
301 break;
302 #endif
303
304 default:
305 if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
306 && (keyCode < 256 && keyCode >= 32)
307 )
308 {
309 String tmp;
310 tmp += keyCode;
311 m_llist.Insert(tmp);
312 m_llist.WrapLine();
313 }
314 break;
315 }
316 }
317
318 ScrollToCursor();
319 Update();
320 ScrollToCursor();
321 }
322
323 void
324 wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
325 {
326 DoPaint();
327 }
328
329 void
330 wxLayoutWindow::DoPaint(bool cursorOnly) // or: OnDraw(wxDC& dc)
331 {
332 wxPaintDC dc( this );
333 PrepareDC( dc );
334
335 // wxGTK: wxMemoryDC broken? YES!!
336 int x0,y0,x1,y1, dx, dy;
337 ViewStart(&x0,&y0);
338 GetClientSize(&x1,&y1); // this is the size of the visible window
339 wxASSERT(x1 > 0);
340 wxASSERT(y1 > 0);
341 GetScrollPixelsPerUnit(&dx, &dy);
342 x0 *= dx; y0 *= dy;
343 //FIXME: trying an offset for small border:
344 wxPoint offset(-x0+4,-y0+4);
345
346 //Blit() doesn't work on scrolled window!
347 // So we have to draw the cursor on the memdc.
348 //if(! cursorOnly)
349 {
350 if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
351 {
352 wxASSERT(m_bitmapSize.x > 0);
353 wxASSERT(m_bitmapSize.y > 0);
354
355 m_memDC->SelectObject(wxNullBitmap);
356 delete m_bitmap;
357 m_bitmapSize = wxPoint(x1,y1);
358 m_bitmap = new wxBitmap(x1,y1);
359 m_memDC->SelectObject(*m_bitmap);
360 }
361 m_memDC->SetDeviceOrigin(0,0);
362 m_memDC->Clear();
363 if(IsDirty() || m_llist.CursorMoved())
364 m_llist.Layout(dc);
365
366 m_llist.EraseAndDraw(*m_memDC,
367 wxLayoutObjectList::iterator(NULL),offset);
368 m_llist.DrawCursor(*m_memDC,false,offset);
369 dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
370 }
371
372 //FIXME obsolete? ResetDirty();
373 UpdateScrollbars();
374 }
375
376 // change the range and position of scroll bars
377 void
378 wxLayoutWindow::UpdateScrollbars(bool exact)
379 {
380 CoordType
381 max_x, max_y, lineHeight;
382
383 m_llist.GetSize(&max_x, &max_y, &lineHeight);
384
385 if(max_x > m_maxx || max_y > m_maxy || exact)
386 {
387 if(! exact) // add an extra 50% to the sizes to avoid future updates
388 {
389 max_x = (3*max_x)/2;
390 max_y = (3*max_y)/2;
391 }
392 ViewStart(&m_ViewStartX, &m_ViewStartY);
393 SetScrollbars(10, 20, max_x/10+1,max_y/20+1,m_ViewStartX,m_ViewStartY,true);
394 m_maxx = max_x; m_maxy = max_y;
395 }
396 }
397
398 void
399 wxLayoutWindow::Print(wxDC &dc)
400 {
401 if (dc.Ok() && dc.StartDoc((char *)_("Printing message...")))
402 {
403 //dc.SetUserScale(1.0, 1.0);
404 m_llist.Draw(dc);
405 dc.EndDoc();
406 }
407 }
408
409 wxMenu *
410 wxLayoutWindow::MakeFormatMenu()
411 {
412 if(m_PopupMenu)
413 return m_PopupMenu;
414
415 wxMenu *m = new wxMenu();
416
417 m->Append(WXLOWIN_MENU_LARGER ,_("&Larger"),_("Switch to larger font."), false);
418 m->Append(WXLOWIN_MENU_SMALLER ,_("&Smaller"),_("Switch to smaller font."), false);
419 m->AppendSeparator();
420 m->Append(WXLOWIN_MENU_UNDERLINE,_("&Underline"),_("Toggle underline mode."), true);
421 m->Append(WXLOWIN_MENU_BOLD ,_("&Bold"),_("Toggle bold mode."), true);
422 m->Append(WXLOWIN_MENU_ITALICS ,_("&Italics"),_("Toggle italics mode."), true);
423 m->AppendSeparator();
424 m->Append(WXLOWIN_MENU_ROMAN ,_("&Roman"),_("Toggle underline mode."), false);
425 m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Toggle bold mode."), false);
426 m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Toggle italics mode."), false);
427
428 return m_PopupMenu = m;
429 }
430
431 void wxLayoutWindow::OnMenu(wxCommandEvent& event)
432 {
433 if(! m_llist.IsEditable())
434 return;
435
436 switch (event.GetId())
437 {
438 case WXLOWIN_MENU_LARGER:
439 m_llist.SetFontLarger();
440 break;
441 case WXLOWIN_MENU_SMALLER:
442 m_llist.SetFontSmaller();
443 break;
444 case WXLOWIN_MENU_UNDERLINE:
445 m_llist.SetFontUnderline(
446 m_PopupMenu->IsChecked(WXLOWIN_MENU_UNDERLINE) ? false : true
447 );
448 break;
449 case WXLOWIN_MENU_BOLD:
450 m_llist.SetFontWeight(
451 m_PopupMenu->IsChecked(WXLOWIN_MENU_BOLD) ? wxNORMAL : wxBOLD
452 );
453 case WXLOWIN_MENU_ITALICS:
454 m_llist.SetFontStyle(
455 m_PopupMenu->IsChecked(WXLOWIN_MENU_ITALICS) ? wxNORMAL : wxITALIC
456 );
457 break;
458 case WXLOWIN_MENU_ROMAN:
459 m_llist.SetFontFamily(wxROMAN); break;
460 case WXLOWIN_MENU_TYPEWRITER:
461 m_llist.SetFontFamily(wxFIXED); break;
462 case WXLOWIN_MENU_SANSSERIF:
463 m_llist.SetFontFamily(wxSWISS); break;
464 }
465 }
466
467 void
468 wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
469 {
470 m_llist.SetBoldCursor(true);
471 DoPaint(true);
472 }
473
474 void
475 wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
476 {
477 m_llist.SetBoldCursor(false);
478 Update();
479 }