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