1 /*-*- c++ -*-********************************************************
2 * wxLwindow.h : a scrolled Window for displaying/entering rich text*
4 * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net) *
7 *******************************************************************/
10 # pragma implementation "wxlwindow.h"
18 # include "gui/wxMenuDefs.h"
19 # include "gui/wxMApp.h"
21 # include "gui/wxlwindow.h"
29 # include "wxlwindow.h"
35 #define WXLO_XOFFSET 4
36 #define WXLO_YOFFSET 4
38 BEGIN_EVENT_TABLE(wxLayoutWindow
,wxScrolledWindow
)
39 EVT_PAINT (wxLayoutWindow::OnPaint
)
40 EVT_CHAR (wxLayoutWindow::OnChar
)
41 EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick
)
42 EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick
)
43 EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick
)
44 EVT_MENU_RANGE(WXLOWIN_MENU_FIRST
, WXLOWIN_MENU_LAST
, wxLayoutWindow::OnMenu
)
45 EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus
)
46 EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus
)
49 wxLayoutWindow::wxLayoutWindow(wxWindow
*parent
)
50 : wxScrolledWindow(parent
, -1, wxDefaultPosition
, wxDefaultSize
,
51 wxHSCROLL
| wxVSCROLL
| wxBORDER
)
55 m_doSendEvents
= false;
56 m_ViewStartX
= 0; m_ViewStartY
= 0;
58 m_PopupMenu
= MakeFormatMenu();
59 m_memDC
= new wxMemoryDC
;
60 m_bitmap
= new wxBitmap(4,4);
61 m_bitmapSize
= wxPoint(4,4);
62 m_llist
= new wxLayoutList();
64 wxPoint max
= m_llist
->GetSize();
65 SetScrollbars(10, 20 /*lineHeight*/, max
.x
/10+1, max
.y
/20+1);
66 EnableScrolling(true,true);
67 m_maxx
= max
.x
; m_maxy
= max
.y
;
68 SetCursor(wxCURSOR_IBEAM
);
72 wxLayoutWindow::~wxLayoutWindow()
74 delete m_memDC
; // deletes bitmap automatically (?)
82 wxLayoutWindow::MSWGetDlgCode()
84 // if we don't return this, we won't get OnChar() events for TABs and ENTER
85 return DLGC_WANTCHARS
| DLGC_WANTARROWS
| DLGC_WANTMESSAGE
;
90 wxLayoutWindow::OnMouse(int eventId
, wxMouseEvent
& event
)
97 findPos
.x
= dc
.DeviceToLogicalX(event
.GetX());
98 findPos
.y
= dc
.DeviceToLogicalY(event
.GetY());
100 findPos
.x
-= WXLO_XOFFSET
;
101 findPos
.y
-= WXLO_YOFFSET
;
103 if(findPos
.x
< 0) findPos
.x
= 0;
104 if(findPos
.y
< 0) findPos
.y
= 0;
106 #ifdef WXLAYOUT_DEBUG
107 wxLogDebug("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)",
108 event
.GetX(), event
.GetY(), findPos
.x
, findPos
.y
);
111 m_ClickPosition
= findPos
;
113 wxLayoutObject
*obj
= m_llist
->FindObjectScreen(dc
, findPos
, &cursorPos
);
115 #ifdef WXLAYOUT_DEBUG
117 wxLogDebug("wxLayoutWindow::OnMouse: Found object of type %d.",
120 wxLogDebug("wxLayoutWindow::OnMouse: Found no object.");
123 // always move cursor to mouse click:
124 if(obj
&& eventId
== WXLOWIN_MENU_LCLICK
)
126 m_llist
->MoveCursorTo(cursorPos
);
129 if(!m_doSendEvents
) // nothing to do
132 // only do the menu if activated, editable and not on a clickable object
133 if(eventId
== WXLOWIN_MENU_RCLICK
135 && (! obj
|| (obj
&& obj
->GetUserData() == NULL
))
138 PopupMenu(m_PopupMenu
, event
.GetX(), event
.GetY());
141 // find the object at this position
144 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, eventId
);
145 commandEvent
.SetEventObject( this );
146 commandEvent
.SetClientData((char *)obj
);
147 GetEventHandler()->ProcessEvent(commandEvent
);
152 * Some simple keyboard handling.
155 wxLayoutWindow::OnChar(wxKeyEvent
& event
)
157 if(!IsEditable()) // do nothing
163 long keyCode
= event
.KeyCode();
165 /* First, handle control keys */
166 if(event
.ControlDown() && ! event
.AltDown())
168 switch(event
.KeyCode())
175 m_llist
->DeleteLines(1);
177 case 'h': // like backspace
178 if(m_llist
->MoveCursorHorizontally(-1)) m_llist
->Delete(1);
181 m_llist
->DeleteToBeginOfLine();
184 m_llist
->DeleteToEndOfLine();
186 #ifdef WXLAYOUT_DEBUG
188 m_llist
->SetFont(-1,-1,-1,-1,true); // underlined
196 else if( event
.AltDown() && ! event
.ControlDown() )
198 switch(event
.KeyCode())
202 m_llist
->DeleteWord();
209 else if ( ! event
.AltDown() && ! event
.ControlDown())
211 switch(event
.KeyCode())
214 m_llist
->MoveCursorHorizontally(1);
217 m_llist
->MoveCursorHorizontally(-1);
220 m_llist
->MoveCursorVertically(-1);
223 m_llist
->MoveCursorVertically(1);
226 m_llist
->MoveCursorVertically(-20);
229 m_llist
->MoveCursorVertically(20);
232 m_llist
->MoveCursorToBeginOfLine();
235 m_llist
->MoveCursorToEndOfLine();
240 case WXK_BACK
: // backspace
241 if(m_llist
->MoveCursorHorizontally(-1)) m_llist
->Delete(1);
245 m_llist
->WrapLine(m_WrapMargin
);
246 m_llist
->LineBreak();
249 if((!(event
.ControlDown() || event
.AltDown() || event
.MetaDown()))
250 && (keyCode
< 256 && keyCode
>= 32)
255 if(m_WrapMargin
> 0 && isspace(keyCode
))
256 m_llist
->WrapLine(m_WrapMargin
);
257 m_llist
->Insert(tmp
);
263 DoPaint(true); // paint and scroll to cursor
267 wxLayoutWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
)) // or: OnDraw(wxDC& dc)
273 wxLayoutWindow::DoPaint(bool scrollToCursor
)
275 wxPaintDC
dc( this );
278 int x0
,y0
,x1
,y1
, dx
, dy
;
280 // Calculate where the top of the visible area is:
282 GetScrollPixelsPerUnit(&dx
, &dy
);
285 // Get the size of the visible window:
286 GetClientSize(&x1
,&y1
);
291 // Maybe we need to change the scrollbar sizes or positions,
292 // so layout the list and check:
295 // this is needed even when only the cursor moved
296 m_llist
->Layout(dc
,y0
+y1
);
301 /* Make sure that the scrollbars are at a position so that the
302 cursor is visible if we are editing. */
303 /** Scroll so that cursor is visible! */
304 if(IsEditable() && scrollToCursor
)
306 wxPoint cc
= m_llist
->GetCursorScreenPos();
307 if(cc
.x
< x0
|| cc
.y
< y0
308 || cc
.x
>= x0
+(9*x1
)/10 || cc
.y
>= y0
+(9*y1
/10)) // (9*x)/10 == 90%
311 nx
= cc
.x
- x1
/2; if(nx
< 0) nx
= 0;
312 ny
= cc
.y
- y1
/2; if(ny
< 0) ny
= 0;
313 Scroll(nx
/dx
,ny
/dy
); // new view start
318 /* Check whether the window has grown, if so, we need to reallocate
319 the bitmap to be larger. */
320 if(x1
> m_bitmapSize
.x
|| y1
> m_bitmapSize
.y
)
322 wxASSERT(m_bitmapSize
.x
> 0);
323 wxASSERT(m_bitmapSize
.y
> 0);
325 m_memDC
->SelectObject(wxNullBitmap
);
327 m_bitmapSize
= wxPoint(x1
,y1
);
328 m_bitmap
= new wxBitmap(x1
,y1
);
329 m_memDC
->SelectObject(*m_bitmap
);
331 // Device origins on the memDC are suspect, we translate manually
332 // with the translate parameter of Draw().
333 m_memDC
->SetDeviceOrigin(0,0);
336 // The offsets give the window a tiny border on the left and top, looks nice.
337 wxPoint
offset(-x0
+WXLO_XOFFSET
,-y0
+WXLO_YOFFSET
);
338 m_llist
->Draw(*m_memDC
,offset
);
340 m_llist
->DrawCursor(*m_memDC
,m_HaveFocus
,offset
);
341 // Now copy everything to the screen:
342 dc
.Blit(x0
,y0
,x1
,y1
,m_memDC
,0,0,wxCOPY
,FALSE
);
348 // change the range and position of scroll bars
350 wxLayoutWindow::ResizeScrollbars(bool exact
)
352 wxPoint max
= m_llist
->GetSize();
354 if(max
.x
> m_maxx
|| max
.y
> m_maxy
355 || max
.x
< (7*m_maxx
)/10 || max
.y
<< (7*m_maxy
)/10
358 if(! exact
) // add an extra 20% to the sizes to avoid future updates
360 max
.x
= (12*max
.x
)/10; // 12/20 = 120%
361 max
.y
= (12*max
.y
)/10;
363 ViewStart(&m_ViewStartX
, &m_ViewStartY
);
364 SetScrollbars(10, 20, max
.x
/10+1,max
.y
/20+1,m_ViewStartX
,m_ViewStartY
,true);
365 m_maxx
= max
.x
; m_maxy
= max
.y
;
371 wxLayoutWindow::MakeFormatMenu()
373 wxMenu
*m
= new wxMenu(_("Layout Menu"));
375 m
->Append(WXLOWIN_MENU_LARGER
,_("&Larger"),_("Switch to larger font."), false);
376 m
->Append(WXLOWIN_MENU_SMALLER
,_("&Smaller"),_("Switch to smaller font."), false);
377 m
->AppendSeparator();
378 m
->Append(WXLOWIN_MENU_UNDERLINE_ON
, _("&Underline on"),_("Activate underline mode."), false);
379 m
->Append(WXLOWIN_MENU_UNDERLINE_OFF
,_("&Underline off"),_("Deactivate underline mode."), false);
380 m
->Append(WXLOWIN_MENU_BOLD_ON
,_("&Bold on"),_("Activate bold mode."), false);
381 m
->Append(WXLOWIN_MENU_BOLD_OFF
,_("&Bold off"),_("Deactivate bold mode."), false);
382 m
->Append(WXLOWIN_MENU_ITALICS_ON
,_("&Italics on"),_("Activate italics mode."), false);
383 m
->Append(WXLOWIN_MENU_ITALICS_OFF
,_("&Italics off"),_("Deactivate italics mode."), false);
384 m
->AppendSeparator();
385 m
->Append(WXLOWIN_MENU_ROMAN
,_("&Roman"),_("Switch to roman font."), false);
386 m
->Append(WXLOWIN_MENU_TYPEWRITER
,_("&Typewriter"),_("Switch to typewriter font."), false);
387 m
->Append(WXLOWIN_MENU_SANSSERIF
,_("&Sans Serif"),_("Switch to sans serif font."), false);
391 void wxLayoutWindow::OnMenu(wxCommandEvent
& event
)
393 switch (event
.GetId())
395 case WXLOWIN_MENU_LARGER
:
396 m_llist
->SetFontLarger(); break;
397 case WXLOWIN_MENU_SMALLER
:
398 m_llist
->SetFontSmaller(); break;
399 case WXLOWIN_MENU_UNDERLINE_ON
:
400 m_llist
->SetFontUnderline(true); break;
401 case WXLOWIN_MENU_UNDERLINE_OFF
:
402 m_llist
->SetFontUnderline(false); break;
403 case WXLOWIN_MENU_BOLD_ON
:
404 m_llist
->SetFontWeight(wxBOLD
); break;
405 case WXLOWIN_MENU_BOLD_OFF
:
406 m_llist
->SetFontWeight(wxNORMAL
); break;
407 case WXLOWIN_MENU_ITALICS_ON
:
408 m_llist
->SetFontStyle(wxITALIC
); break;
409 case WXLOWIN_MENU_ITALICS_OFF
:
410 m_llist
->SetFontStyle(wxNORMAL
); break;
411 case WXLOWIN_MENU_ROMAN
:
412 m_llist
->SetFontFamily(wxROMAN
); break;
413 case WXLOWIN_MENU_TYPEWRITER
:
414 m_llist
->SetFontFamily(wxFIXED
); break;
415 case WXLOWIN_MENU_SANSSERIF
:
416 m_llist
->SetFontFamily(wxSWISS
); break;
421 wxLayoutWindow::OnSetFocus(wxFocusEvent
&ev
)
424 DoPaint(); // to repaint the cursor
428 wxLayoutWindow::OnKillFocus(wxFocusEvent
&ev
)
431 DoPaint(); // to repaint the cursor