]> git.saurik.com Git - wxWidgets.git/blob - src/msw/textctrl.cpp
13d6c08be1e7286da96dd9a43393ea6f5871c9d3
[wxWidgets.git] / src / msw / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "textctrl.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/textctrl.h"
25 #include "wx/settings.h"
26 #endif
27
28 #if wxUSE_CLIPBOARD
29 #include "wx/app.h"
30 #include "wx/clipbrd.h"
31 #endif
32
33 #include "wx/msw/private.h"
34
35 #include <windows.h>
36 #include <stdlib.h>
37
38 #if wxUSE_IOSTREAMH
39 #include <fstream.h>
40 #else
41 #include <fstream>
42 # ifdef _MSC_VER
43 using namespace std;
44 # endif
45 #endif
46
47 #include <sys/types.h>
48 #ifndef __MWERKS__
49 #include <sys/stat.h>
50 #else
51 #include <stat.h>
52 #endif
53 #if defined(__BORLANDC__) && !defined(__WIN32__)
54 #include <alloc.h>
55 #else
56 #ifndef __GNUWIN32__
57 #include <malloc.h>
58 #endif
59 #define farmalloc malloc
60 #define farfree free
61 #endif
62 #include <windowsx.h>
63
64 #include <string.h>
65
66 #if defined(__WIN95__) && !defined(__GNUWIN32__)
67 #include <richedit.h>
68 #endif
69
70 #if !USE_SHARED_LIBRARY
71 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
72
73 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
74 EVT_CHAR(wxTextCtrl::OnChar)
75 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
76 EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground)
77 END_EVENT_TABLE()
78
79 #endif
80
81 // Text item
82 wxTextCtrl::wxTextCtrl(void)
83 #ifndef NO_TEXT_WINDOW_STREAM
84 :streambuf()
85 #endif
86 {
87 m_fileName = "";
88 m_isRich = FALSE;
89 }
90
91 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
92 const wxString& value,
93 const wxPoint& pos,
94 const wxSize& size, long style,
95 const wxValidator& validator,
96 const wxString& name)
97 {
98 m_fileName = "";
99 SetName(name);
100 SetValidator(validator);
101 if (parent) parent->AddChild(this);
102
103 m_windowStyle = style;
104
105 // Should this be taken from the system colours?
106 // SetBackgroundColour(wxColour(255, 255, 255));
107
108 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
109
110 SetForegroundColour(parent->GetForegroundColour()) ;
111
112 if ( id == -1 )
113 m_windowId = (int)NewControlId();
114 else
115 m_windowId = id;
116
117 int x = pos.x;
118 int y = pos.y;
119 int width = size.x;
120 int height = size.y;
121
122 #ifdef __WIN32__
123 WXHGLOBAL m_globalHandle = 0;
124 #else
125 // Obscure method from the MS Developer's Network Disk for
126 // using global memory instead of the local heap, which
127 // runs out far too soon. Solves the problem with
128 // failing to appear.
129
130 // Doesn't seem to work for Win95, so removing.
131 m_globalHandle=0;
132 // if ((wxGetOsVersion() != wxWINDOWS_NT) && (wxGetOsVersion() != wxWIN95))
133 // m_globalHandle = (WXHGLOBAL) GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
134 // 256L);
135 #endif
136
137 long msStyle = ES_LEFT | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
138 if (m_windowStyle & wxTE_MULTILINE)
139 msStyle |= ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL ; // WS_BORDER
140 else
141 msStyle |= ES_AUTOHSCROLL ;
142
143 if (m_windowStyle & wxTE_READONLY)
144 msStyle |= ES_READONLY;
145
146 if (m_windowStyle & wxHSCROLL)
147 msStyle |= (WS_HSCROLL | ES_AUTOHSCROLL) ;
148 if (m_windowStyle & wxTE_PASSWORD) // hidden input
149 msStyle |= ES_PASSWORD;
150
151 char *windowClass = "EDIT";
152 #if defined(__WIN95__)
153 if ( m_windowStyle & wxTE_MULTILINE )
154 {
155 msStyle |= ES_AUTOVSCROLL;
156 m_isRich = TRUE;
157 windowClass = "RichEdit" ;
158 }
159 else
160 #endif
161 m_isRich = FALSE;
162
163 bool want3D;
164 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ;
165
166 // If we're in Win95, and we want a simple 2D border,
167 // then make it an EDIT control instead.
168 #if defined(__WIN95__)
169 if (m_windowStyle & wxSIMPLE_BORDER)
170 {
171 windowClass = "EDIT";
172 m_isRich = FALSE;
173 }
174 #endif
175
176 // Even with extended styles, need to combine with WS_BORDER
177 // for them to look right.
178 if ( want3D || wxStyleHasBorder(m_windowStyle) )
179 msStyle |= WS_BORDER;
180
181 m_hWnd = (WXHWND)::CreateWindowEx(exStyle, windowClass, NULL,
182 msStyle,
183 0, 0, 0, 0, (HWND) ((wxWindow*)parent)->GetHWND(), (HMENU)m_windowId,
184 m_globalHandle ? (HINSTANCE) m_globalHandle : wxGetInstance(), NULL);
185
186 wxCHECK_MSG( m_hWnd, FALSE, "Failed to create text ctrl" );
187
188 #if CTL3D
189 if ( want3D )
190 {
191 Ctl3dSubclassCtl((HWND)m_hWnd);
192 m_useCtl3D = TRUE;
193 }
194 #endif
195
196 #if defined(__WIN95__)
197 if (m_isRich)
198 {
199 // Have to enable events
200 ::SendMessage((HWND)m_hWnd, EM_SETEVENTMASK, 0,
201 ENM_CHANGE | ENM_DROPFILES | ENM_SELCHANGE | ENM_UPDATE);
202 }
203 #endif
204
205 SubclassWin(GetHWND());
206
207 if ( parent->GetFont().Ok() && parent->GetFont().Ok() )
208 {
209 SetFont(parent->GetFont());
210 }
211 else
212 {
213 SetFont(wxSystemSettings::GetSystemFont(wxSYS_SYSTEM_FONT));
214 }
215
216 SetSize(x, y, width, height);
217
218 // Causes a crash for Symantec C++ and WIN32 for some reason
219 #if !(defined(__SC__) && defined(__WIN32__))
220 if ( !value.IsEmpty() )
221 {
222 SetValue(value);
223 }
224 #endif
225
226 return TRUE;
227 }
228
229 // Make sure the window style (etc.) reflects the HWND style (roughly)
230 void wxTextCtrl::AdoptAttributesFromHWND(void)
231 {
232 wxWindow::AdoptAttributesFromHWND();
233
234 HWND hWnd = (HWND) GetHWND();
235 long style = GetWindowLong((HWND) hWnd, GWL_STYLE);
236
237 char buf[256];
238
239 #ifndef __WIN32__
240 GetClassName((HWND) hWnd, buf, 256);
241 #else
242 #ifdef UNICODE
243 GetClassNameW((HWND) hWnd, buf, 256);
244 #else
245 GetClassNameA((HWND) hWnd, buf, 256);
246 #endif
247 #endif
248
249 wxString str(buf);
250 str.UpperCase();
251
252 if (str == "EDIT")
253 m_isRich = FALSE;
254 else
255 m_isRich = TRUE;
256
257 if (style & ES_MULTILINE)
258 m_windowStyle |= wxTE_MULTILINE;
259 if (style & ES_PASSWORD)
260 m_windowStyle |= wxTE_PASSWORD;
261 if (style & ES_READONLY)
262 m_windowStyle |= wxTE_READONLY;
263 if (style & ES_WANTRETURN)
264 m_windowStyle |= wxTE_PROCESS_ENTER;
265 }
266
267 void wxTextCtrl::SetupColours(void)
268 {
269 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
270 SetForegroundColour(GetParent()->GetForegroundColour());
271 }
272
273 wxString wxTextCtrl::GetValue(void) const
274 {
275 int length = GetWindowTextLength((HWND) GetHWND());
276 char *s = new char[length+1];
277 GetWindowText((HWND) GetHWND(), s, length+1);
278 wxString str(s);
279 delete[] s;
280 return str;
281 }
282
283 void wxTextCtrl::SetValue(const wxString& value)
284 {
285 // If newlines are denoted by just 10, must stick 13 in front.
286 int singletons = 0;
287 int len = value.Length();
288 int i;
289 for (i = 0; i < len; i ++)
290 {
291 if ((i > 0) && (value[i] == 10) && (value[i-1] != 13))
292 singletons ++;
293 }
294 if (singletons > 0)
295 {
296 char *tmp = new char[len + singletons + 1];
297 int j = 0;
298 for (i = 0; i < len; i ++)
299 {
300 if ((i > 0) && (value[i] == 10) && (value[i-1] != 13))
301 {
302 tmp[j] = 13;
303 j ++;
304 }
305 tmp[j] = value[i];
306 j ++;
307 }
308 tmp[j] = 0;
309 SetWindowText((HWND) GetHWND(), tmp);
310 delete[] tmp;
311 }
312 else
313 SetWindowText((HWND) GetHWND(), (const char *)value);
314 }
315
316 void wxTextCtrl::SetSize(int x, int y, int width, int height, int sizeFlags)
317 {
318 int currentX, currentY;
319 GetPosition(&currentX, &currentY);
320 int x1 = x;
321 int y1 = y;
322 int w1 = width;
323 int h1 = height;
324
325 if (x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
326 x1 = currentX;
327 if (y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
328 y1 = currentY;
329
330 AdjustForParentClientOrigin(x1, y1, sizeFlags);
331
332 int cx; // button font dimensions
333 int cy;
334
335 wxGetCharSize(GetHWND(), &cx, &cy, & GetFont());
336
337 int control_width, control_height, control_x, control_y;
338
339 // If we're prepared to use the existing size, then...
340 if (width == -1 && height == -1 && ((sizeFlags & wxSIZE_AUTO) != wxSIZE_AUTO))
341 {
342 GetSize(&w1, &h1);
343 }
344
345 // Deal with default size (using -1 values)
346 if (w1<=0)
347 w1 = DEFAULT_ITEM_WIDTH;
348
349 control_x = x1;
350 control_y = y1;
351 control_width = w1;
352 control_height = h1;
353
354 // Calculations may have made text size too small
355 if (control_height <= 0)
356 control_height = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
357
358 if (control_width <= 0)
359 control_width = DEFAULT_ITEM_WIDTH;
360
361 MoveWindow((HWND) GetHWND(), (int)control_x, (int)control_y,
362 (int)control_width, (int)control_height, TRUE);
363 }
364
365 // Clipboard operations
366 void wxTextCtrl::Copy(void)
367 {
368 HWND hWnd = (HWND) GetHWND();
369 SendMessage(hWnd, WM_COPY, 0, 0L);
370 }
371
372 void wxTextCtrl::Cut(void)
373 {
374 HWND hWnd = (HWND) GetHWND();
375 SendMessage(hWnd, WM_CUT, 0, 0L);
376 }
377
378 void wxTextCtrl::Paste(void)
379 {
380 HWND hWnd = (HWND) GetHWND();
381 SendMessage(hWnd, WM_PASTE, 0, 0L);
382 }
383
384 void wxTextCtrl::SetEditable(bool editable)
385 {
386 HWND hWnd = (HWND) GetHWND();
387 SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L);
388 }
389
390 void wxTextCtrl::SetInsertionPoint(long pos)
391 {
392 HWND hWnd = (HWND) GetHWND();
393 #ifdef __WIN32__
394 #if defined(__WIN95__)
395 if ( m_isRich)
396 {
397 CHARRANGE range;
398 range.cpMin = pos;
399 range.cpMax = pos;
400 SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM) &range);
401 SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
402 }
403 else
404 #endif
405 {
406 SendMessage(hWnd, EM_SETSEL, pos, pos);
407 SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
408 }
409 #else
410 SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(pos, pos));
411 #endif
412 char *nothing = "";
413 SendMessage(hWnd, EM_REPLACESEL, 0, (LPARAM)nothing);
414 }
415
416 void wxTextCtrl::SetInsertionPointEnd(void)
417 {
418 long pos = GetLastPosition();
419 SetInsertionPoint(pos);
420 }
421
422 long wxTextCtrl::GetInsertionPoint(void) const
423 {
424 #if defined(__WIN95__)
425 if (m_isRich)
426 {
427 CHARRANGE range;
428 range.cpMin = 0;
429 range.cpMax = 0;
430 SendMessage((HWND) GetHWND(), EM_EXGETSEL, 0, (LPARAM) &range);
431 return range.cpMin;
432 }
433 #endif
434
435 DWORD Pos=(DWORD)SendMessage((HWND) GetHWND(), EM_GETSEL, 0, 0L);
436 return Pos&0xFFFF;
437 }
438
439 long wxTextCtrl::GetLastPosition(void) const
440 {
441 HWND hWnd = (HWND) GetHWND();
442
443 // Will always return a number > 0 (according to docs)
444 int noLines = (int)SendMessage(hWnd, EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0L);
445
446 // This gets the char index for the _beginning_ of the last line
447 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)(noLines-1), (LPARAM)0L);
448
449 // Get number of characters in the last line. We'll add this to the character
450 // index for the last line, 1st position.
451 int lineLength = (int)SendMessage(hWnd, EM_LINELENGTH, (WPARAM)charIndex, (LPARAM)0L);
452
453 return (long)(charIndex + lineLength);
454 }
455
456 void wxTextCtrl::Replace(long from, long to, const wxString& value)
457 {
458 HWND hWnd = (HWND) GetHWND();
459 long fromChar = from;
460 long toChar = to;
461
462 // Set selection and remove it
463 #ifdef __WIN32__
464 SendMessage(hWnd, EM_SETSEL, fromChar, toChar);
465 #else
466 SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(fromChar, toChar));
467 #endif
468 SendMessage(hWnd, WM_CUT, (WPARAM)0, (LPARAM)0);
469
470 // Now replace with 'value', by pasting.
471 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const char *)value, 0, 0);
472
473 // Paste into edit control
474 SendMessage(hWnd, WM_PASTE, (WPARAM)0, (LPARAM)0L);
475 }
476
477 void wxTextCtrl::Remove(long from, long to)
478 {
479 HWND hWnd = (HWND) GetHWND();
480 long fromChar = from;
481 long toChar = to;
482
483 // Cut all selected text
484 #ifdef __WIN32__
485 SendMessage(hWnd, EM_SETSEL, fromChar, toChar);
486 #else
487 SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(fromChar, toChar));
488 #endif
489 SendMessage(hWnd, WM_CUT, (WPARAM)0, (LPARAM)0);
490 }
491
492 void wxTextCtrl::SetSelection(long from, long to)
493 {
494 HWND hWnd = (HWND) GetHWND();
495 long fromChar = from;
496 long toChar = to;
497 // if from and to are both -1, it means
498 // (in wxWindows) that all text should be selected.
499 // This translates into Windows convention
500 if ((from == -1) && (to == -1))
501 {
502 fromChar = 0;
503 toChar = -1;
504 }
505
506 #ifdef __WIN32__
507 SendMessage(hWnd, EM_SETSEL, (WPARAM)fromChar, (LPARAM)toChar);
508 SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
509 #else
510 // WPARAM is 0: selection is scrolled into view
511 SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(fromChar, toChar));
512 #endif
513 }
514
515 bool wxTextCtrl::LoadFile(const wxString& file)
516 {
517 if (!FileExists(WXSTRINGCAST file))
518 return FALSE;
519
520 m_fileName = file;
521
522 Clear();
523
524 // ifstream input(WXSTRINGCAST file, ios::nocreate | ios::in);
525 ifstream input(WXSTRINGCAST file, ios::in);
526
527 if (!input.bad())
528 {
529 // Previously a SETSEL/REPLACESEL call-pair were done to insert
530 // line by line into the control. Apart from being very slow this
531 // was limited to 32K of text by the external interface presenting
532 // positions as signed shorts. Now load in one chunk...
533 // Note use of 'farmalloc' as in Borland 3.1 'size_t' is 16-bits...
534
535 struct stat stat_buf;
536 if (stat(file, &stat_buf) < 0)
537 return FALSE;
538 // char *tmp_buffer = (char*)farmalloc(stat_buf.st_size+1);
539 // This may need to be a bigger buffer than the file size suggests,
540 // if it's a UNIX file. Give it an extra 1000 just in case.
541 char *tmp_buffer = (char*)farmalloc((size_t)(stat_buf.st_size+1+1000));
542 long no_lines = 0;
543 long pos = 0;
544 while (!input.eof() && input.peek() != EOF)
545 {
546 input.getline(wxBuffer, 500);
547 int len = strlen(wxBuffer);
548 wxBuffer[len] = 13;
549 wxBuffer[len+1] = 10;
550 wxBuffer[len+2] = 0;
551 strcpy(tmp_buffer+pos, wxBuffer);
552 pos += strlen(wxBuffer);
553 no_lines++;
554 }
555
556 // SendMessage((HWND) GetHWND(), WM_SETTEXT, 0, (LPARAM)tmp_buffer);
557 SetWindowText((HWND) GetHWND(), tmp_buffer);
558 SendMessage((HWND) GetHWND(), EM_SETMODIFY, FALSE, 0L);
559 farfree(tmp_buffer);
560
561 return TRUE;
562 }
563 return FALSE;
564 }
565
566 // If file is null, try saved file name first
567 // Returns TRUE if succeeds.
568 bool wxTextCtrl::SaveFile(const wxString& file)
569 {
570 wxString theFile(file);
571 if (theFile == "")
572 theFile = m_fileName;
573 if (theFile == "")
574 return FALSE;
575 m_fileName = theFile;
576
577 ofstream output((char*) (const char*) theFile);
578 if (output.bad())
579 return FALSE;
580
581 // This will only save 64K max
582 unsigned long nbytes = SendMessage((HWND) GetHWND(), WM_GETTEXTLENGTH, 0, 0);
583 char *tmp_buffer = (char*)farmalloc((size_t)(nbytes+1));
584 SendMessage((HWND) GetHWND(), WM_GETTEXT, (WPARAM)(nbytes+1), (LPARAM)tmp_buffer);
585 char *pstr = tmp_buffer;
586
587 // Convert \r\n to just \n
588 while (*pstr)
589 {
590 if (*pstr != '\r')
591 output << *pstr;
592 pstr++;
593 }
594
595 farfree(tmp_buffer);
596 SendMessage((HWND) GetHWND(), EM_SETMODIFY, FALSE, 0L);
597
598 return TRUE;
599 }
600
601 void wxTextCtrl::WriteText(const wxString& text)
602 {
603 // Covert \n to \r\n
604 int len = text.Length();
605 char *newtext = new char[(len*2)+1];
606 int i = 0;
607 int j = 0;
608 while (i < len)
609 {
610 if (text[i] == '\n')
611 {
612 newtext[j] = '\r';
613 j ++;
614 }
615 newtext[j] = text[i];
616 i ++;
617 j ++;
618 }
619 newtext[j] = 0;
620 SendMessage((HWND) GetHWND(), EM_REPLACESEL, 0, (LPARAM)newtext);
621 delete[] newtext;
622 }
623
624 void wxTextCtrl::Clear(void)
625 {
626 // SendMessage((HWND) GetHWND(), WM_SETTEXT, 0, (LPARAM)"");
627 SetWindowText((HWND) GetHWND(), "");
628 }
629
630 bool wxTextCtrl::IsModified(void) const
631 {
632 return (SendMessage((HWND) GetHWND(), EM_GETMODIFY, 0, 0) != 0);
633 }
634
635 // Makes 'unmodified'
636 void wxTextCtrl::DiscardEdits(void)
637 {
638 SendMessage((HWND) GetHWND(), EM_SETMODIFY, FALSE, 0L);
639 }
640
641 /*
642 * Some of the following functions are yet to be implemented
643 *
644 */
645
646 int wxTextCtrl::GetNumberOfLines(void) const
647 {
648 return (int)SendMessage((HWND) GetHWND(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
649 }
650
651 long wxTextCtrl::XYToPosition(long x, long y) const
652 {
653 HWND hWnd = (HWND) GetHWND();
654
655 // This gets the char index for the _beginning_ of this line
656 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)y, (LPARAM)0);
657 return (long)(x + charIndex);
658 }
659
660 void wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
661 {
662 HWND hWnd = (HWND) GetHWND();
663
664 // This gets the line number containing the character
665 int lineNo = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0);
666 // This gets the char index for the _beginning_ of this line
667 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)lineNo, (LPARAM)0);
668 // The X position must therefore be the different between pos and charIndex
669 *x = (long)(pos - charIndex);
670 *y = (long)lineNo;
671 }
672
673 void wxTextCtrl::ShowPosition(long pos)
674 {
675 HWND hWnd = (HWND) GetHWND();
676
677 // To scroll to a position, we pass the number of lines and characters
678 // to scroll *by*. This means that we need to:
679 // (1) Find the line position of the current line.
680 // (2) Find the line position of pos.
681 // (3) Scroll by (pos - current).
682 // For now, ignore the horizontal scrolling.
683
684 // Is this where scrolling is relative to - the line containing the caret?
685 // Or is the first visible line??? Try first visible line.
686 // int currentLineLineNo1 = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L);
687
688 int currentLineLineNo = (int)SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, (WPARAM)0, (LPARAM)0L);
689
690 int specifiedLineLineNo = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
691
692 int linesToScroll = specifiedLineLineNo - currentLineLineNo;
693
694 /*
695 wxDebugMsg("Caret line: %d; Current visible line: %d; Specified line: %d; lines to scroll: %d\n",
696 currentLineLineNo1, currentLineLineNo, specifiedLineLineNo, linesToScroll);
697 */
698
699 if (linesToScroll != 0)
700 (void)SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)MAKELPARAM(linesToScroll, 0));
701 }
702
703 int wxTextCtrl::GetLineLength(long lineNo) const
704 {
705 long charIndex = XYToPosition(0, lineNo);
706 HWND hWnd = (HWND) GetHWND();
707 int len = (int)SendMessage(hWnd, EM_LINELENGTH, (WPARAM)charIndex, (LPARAM)0);
708 return len;
709 }
710
711 wxString wxTextCtrl::GetLineText(long lineNo) const
712 {
713 HWND hWnd = (HWND) GetHWND();
714 *(WORD *)wxBuffer = 512;
715 int noChars = (int)SendMessage(hWnd, EM_GETLINE, (WPARAM)lineNo, (LPARAM)wxBuffer);
716 wxBuffer[noChars] = 0;
717 return wxString(wxBuffer);
718 }
719
720 /*
721 * Text item
722 */
723
724 void wxTextCtrl::Command(wxCommandEvent & event)
725 {
726 SetValue (event.GetString());
727 ProcessCommand (event);
728 }
729
730 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
731 {
732 // By default, load the first file into the text window.
733 if (event.GetNumberOfFiles() > 0)
734 {
735 LoadFile(event.GetFiles()[0]);
736 }
737 }
738
739 // The streambuf code was partly taken from chapter 3 by Jerry Schwarz of
740 // AT&T's "C++ Lanuage System Release 3.0 Library Manual" - Stein Somers
741
742 //=========================================================================
743 // Called then the buffer is full (gcc 2.6.3)
744 // or when "endl" is output (Borland 4.5)
745 //=========================================================================
746 // Class declaration using multiple inheritance doesn't work properly for
747 // Borland. See note in wb_text.h.
748 #ifndef NO_TEXT_WINDOW_STREAM
749 int wxTextCtrl::overflow(int c)
750 {
751 // Make sure there is a holding area
752 // this is not needed in <iostream> usage as it automagically allocates
753 // it, but does someone want to emulate it for safety's sake?
754 #if wxUSE_IOSTREAMH
755 if ( allocate()==EOF )
756 {
757 wxError("Streambuf allocation failed","Internal error");
758 return EOF;
759 }
760 #endif
761
762 // Verify that there are no characters in get area
763 if ( gptr() && gptr() < egptr() )
764 {
765 wxError("Who's trespassing my get area?","Internal error");
766 return EOF;
767 }
768
769 // Reset get area
770 setg(0,0,0);
771
772 // Make sure there is a put area
773 if ( ! pptr() )
774 {
775 /* This doesn't seem to be fatal so comment out error message */
776 // wxError("Put area not opened","Internal error");
777
778 #if wxUSE_IOSTREAMH
779 setp( base(), base() );
780 #else
781 setp( pbase(), pbase() );
782 #endif
783 }
784
785 // Determine how many characters have been inserted but no consumed
786 int plen = pptr() - pbase();
787
788 // Now Jerry relies on the fact that the buffer is at least 2 chars
789 // long, but the holding area "may be as small as 1" ???
790 // And we need an additional \0, so let's keep this inefficient but
791 // safe copy.
792
793 // If c!=EOF, it is a character that must also be comsumed
794 int xtra = c==EOF? 0 : 1;
795
796 // Write temporary C-string to wxTextWindow
797 {
798 char *txt = new char[plen+xtra+1];
799 memcpy(txt, pbase(), plen);
800 txt[plen] = (char)c; // append c
801 txt[plen+xtra] = '\0'; // append '\0' or overwrite c
802 // If the put area already contained \0, output will be truncated there
803 WriteText(txt);
804 delete[] txt;
805 }
806
807 // Reset put area
808 setp(pbase(), epptr());
809
810 #if defined(__WATCOMC__)
811 return __NOT_EOF;
812 #elif defined(zapeof) // HP-UX (all cfront based?)
813 return zapeof(c);
814 #else
815 return c!=EOF ? c : 0; // this should make everybody happy
816 #endif
817
818 /* OLD CODE
819 int len = pptr() - pbase();
820 char *txt = new char[len+1];
821 strncpy(txt, pbase(), len);
822 txt[len] = '\0';
823 (*this) << txt;
824 setp(pbase(), epptr());
825 delete[] txt;
826 return EOF;
827 */
828 }
829
830 //=========================================================================
831 // called then "endl" is output (gcc) or then explicit sync is done (Borland)
832 //=========================================================================
833 int wxTextCtrl::sync(void)
834 {
835 // Verify that there are no characters in get area
836 if ( gptr() && gptr() < egptr() )
837 {
838 wxError("Who's trespassing my get area?","Internal error");
839 return EOF;
840 }
841
842 if ( pptr() && pptr() > pbase() ) return overflow(EOF);
843
844 return 0;
845 /* OLD CODE
846 int len = pptr() - pbase();
847 char *txt = new char[len+1];
848 strncpy(txt, pbase(), len);
849 txt[len] = '\0';
850 (*this) << txt;
851 setp(pbase(), epptr());
852 delete[] txt;
853 return 0;
854 */
855 }
856
857 //=========================================================================
858 // Should not be called by a "ostream". Used by a "istream"
859 //=========================================================================
860 int wxTextCtrl::underflow(void)
861 {
862 return EOF;
863 }
864 #endif
865
866 wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
867 {
868 WriteText(s);
869 return *this;
870 }
871
872 wxTextCtrl& wxTextCtrl::operator<<(float f)
873 {
874 wxString str;
875 str.Printf("%.2f", f);
876 WriteText(str);
877 return *this;
878 }
879
880 wxTextCtrl& wxTextCtrl::operator<<(double d)
881 {
882 wxString str;
883 str.Printf("%.2f", d);
884 WriteText(str);
885 return *this;
886 }
887
888 wxTextCtrl& wxTextCtrl::operator<<(int i)
889 {
890 wxString str;
891 str.Printf("%d", i);
892 WriteText(str);
893 return *this;
894 }
895
896 wxTextCtrl& wxTextCtrl::operator<<(long i)
897 {
898 wxString str;
899 str.Printf("%ld", i);
900 WriteText(str);
901 return *this;
902 }
903
904 wxTextCtrl& wxTextCtrl::operator<<(const char c)
905 {
906 char buf[2];
907
908 buf[0] = c;
909 buf[1] = 0;
910 WriteText(buf);
911 return *this;
912 }
913
914 WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor,
915 WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
916 {
917 #if CTL3D
918 if ( m_useCtl3D )
919 {
920 HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam);
921 return (WXHBRUSH) hbrush;
922 }
923 #endif
924
925 if (GetParent()->GetTransparentBackground())
926 SetBkMode((HDC) pDC, TRANSPARENT);
927 else
928 SetBkMode((HDC) pDC, OPAQUE);
929
930 ::SetBkColor((HDC) pDC, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
931 ::SetTextColor((HDC) pDC, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
932
933 wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID);
934
935 // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush
936 // has a zero usage count.
937 // NOT NOW - will be cleaned up at end of app.
938 // backgroundBrush->RealizeResource();
939 return (WXHBRUSH) backgroundBrush->GetResourceHandle();
940 }
941
942 void wxTextCtrl::OnChar(wxKeyEvent& event)
943 {
944 // Fix by Marcel Rasche to allow Alt-Ctrl insertion of special characters
945 switch(event.KeyCode())
946 {
947 case '{':
948 case '}':
949 case '[':
950 case ']':
951 case '|':
952 case '~':
953 case '\\':
954 {
955 char c=(char)event.KeyCode();
956 *this << c;
957 }
958 break;
959 }
960 if ( (event.KeyCode() == WXK_RETURN) && (m_windowStyle & wxPROCESS_ENTER))
961 {
962 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
963 event.SetEventObject( this );
964 if ( GetEventHandler()->ProcessEvent(event) )
965 return;
966 }
967 else if ( event.KeyCode() == WXK_TAB ) {
968 wxNavigationKeyEvent event;
969 event.SetDirection(!(::GetKeyState(VK_SHIFT) & 0x100));
970 event.SetWindowChange(FALSE);
971 event.SetEventObject(this);
972
973 if ( GetEventHandler()->ProcessEvent(event) )
974 return;
975 }
976
977 event.Skip();
978 }
979
980 long wxTextCtrl::MSWGetDlgCode()
981 {
982 long lRc = DLGC_WANTCHARS | DLGC_WANTARROWS;
983 if ( m_windowStyle & wxPROCESS_ENTER )
984 lRc |= DLGC_WANTMESSAGE;
985 else if ( m_windowStyle & wxTE_MULTILINE )
986 lRc |= DLGC_WANTMESSAGE;
987
988 return lRc;
989 }
990
991 void wxTextCtrl::OnEraseBackground(wxEraseEvent& event)
992 {
993 if ( m_windowStyle & wxTE_MULTILINE )
994 {
995 // No flicker - only problem is we probably can't change the background
996 Default();
997 /*
998 RECT rect;
999 ::GetClientRect((HWND) GetHWND(), &rect);
1000
1001 HBRUSH hBrush = ::CreateSolidBrush(PALETTERGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
1002 int mode = ::SetMapMode((HDC) event.GetDC()->GetHDC(), MM_TEXT);
1003
1004 ::FillRect ((HDC) event.GetDC()->GetHDC(), &rect, hBrush);
1005 ::DeleteObject(hBrush);
1006 ::SetMapMode((HDC) event.GetDC()->GetHDC(), mode);
1007 */
1008 }
1009 // wxWindow::OnEraseBackground(event);
1010 }
1011
1012 bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
1013 {
1014 /*
1015 // Debugging
1016 wxDebugMsg("Edit control %d: ", (int)id);
1017 switch (param)
1018 {
1019 case EN_SETFOCUS:
1020 wxDebugMsg("EN_SETFOCUS\n");
1021 break;
1022 case EN_KILLFOCUS:
1023 wxDebugMsg("EN_KILLFOCUS\n");
1024 break;
1025 case EN_CHANGE:
1026 wxDebugMsg("EN_CHANGE\n");
1027 break;
1028 case EN_UPDATE:
1029 wxDebugMsg("EN_UPDATE\n");
1030 break;
1031 case EN_ERRSPACE:
1032 wxDebugMsg("EN_ERRSPACE\n");
1033 break;
1034 case EN_MAXTEXT:
1035 wxDebugMsg("EN_MAXTEXT\n");
1036 break;
1037 case EN_HSCROLL:
1038 wxDebugMsg("EN_HSCROLL\n");
1039 break;
1040 case EN_VSCROLL:
1041 wxDebugMsg("EN_VSCROLL\n");
1042 break;
1043 default:
1044 wxDebugMsg("Unknown EDIT notification\n");
1045 break;
1046 }
1047 */
1048 switch (param)
1049 {
1050 case EN_SETFOCUS:
1051 case EN_KILLFOCUS:
1052 {
1053 wxFocusEvent event(param == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
1054 : wxEVT_SET_FOCUS,
1055 m_windowId);
1056 event.SetEventObject( this );
1057 GetEventHandler()->ProcessEvent(event);
1058 }
1059 break;
1060
1061 case EN_CHANGE:
1062 {
1063 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1064 wxString val(GetValue());
1065 if ( !val.IsNull() )
1066 event.m_commandString = WXSTRINGCAST val;
1067 event.SetEventObject( this );
1068 ProcessCommand(event);
1069 }
1070 break;
1071
1072 // the other notification messages are not processed
1073 case EN_UPDATE:
1074 case EN_ERRSPACE:
1075 case EN_MAXTEXT:
1076 case EN_HSCROLL:
1077 case EN_VSCROLL:
1078 default:
1079 return FALSE;
1080 }
1081
1082 // processed
1083 return TRUE;
1084 }
1085
1086
1087 // For Rich Edit controls. Do we need it?
1088 #if 0
1089 #if defined(__WIN95__)
1090 bool wxTextCtrl::MSWNotify(WXWPARAM wParam, WXLPARAM lParam)
1091 {
1092 wxCommandEvent event(0, m_windowId);
1093 int eventType = 0;
1094 NMHDR *hdr1 = (NMHDR *) lParam;
1095 switch ( hdr1->code )
1096 {
1097 // Insert case code here
1098 default :
1099 return wxControl::MSWNotify(wParam, lParam);
1100 break;
1101 }
1102
1103 event.SetEventObject( this );
1104 event.SetEventType(eventType);
1105
1106 if ( !GetEventHandler()->ProcessEvent(event) )
1107 return FALSE;
1108
1109 return TRUE;
1110 }
1111 #endif
1112 #endif
1113