]> git.saurik.com Git - wxWidgets.git/blame - src/msw/textctrl.cpp
Added a few files; fixed some warnings and wxMotif compile problems
[wxWidgets.git] / src / msw / textctrl.cpp
CommitLineData
2bda0e17
KB
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
c085e333 9// Licence: wxWindows license
2bda0e17
KB
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"
2432b92d
JS
26#include "wx/brush.h"
27#include "wx/utils.h"
28#include "wx/log.h"
2bda0e17
KB
29#endif
30
47d67540 31#if wxUSE_CLIPBOARD
2bda0e17
KB
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>
fbc535ff
JS
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
2bda0e17
KB
49
50#include <sys/types.h>
17dff81c 51#ifndef __MWERKS__
2bda0e17 52#include <sys/stat.h>
17dff81c
SC
53#else
54#include <stat.h>
55#endif
2bda0e17
KB
56#if defined(__BORLANDC__) && !defined(__WIN32__)
57#include <alloc.h>
58#else
ce3ed50d 59#if !defined(__GNUWIN32__) && !defined(__SALFORDC__)
2bda0e17
KB
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
57c208c5
JS
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__)
2bda0e17
KB
76#include <richedit.h>
77#endif
78
79#if !USE_SHARED_LIBRARY
80IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
81
82BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
c085e333
VZ
83 EVT_CHAR(wxTextCtrl::OnChar)
84 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
85 EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground)
2bda0e17
KB
86END_EVENT_TABLE()
87
88#endif
89
90// Text item
91wxTextCtrl::wxTextCtrl(void)
92#ifndef NO_TEXT_WINDOW_STREAM
93 :streambuf()
94#endif
95{
b823f5a1 96 m_fileName = "";
2bda0e17
KB
97 m_isRich = FALSE;
98}
99
debe6624 100bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
c085e333
VZ
101 const wxString& value,
102 const wxPoint& pos,
103 const wxSize& size, long style,
104 const wxValidator& validator,
105 const wxString& name)
2bda0e17 106{
b823f5a1 107 m_fileName = "";
2bda0e17
KB
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
fd71308f 119 SetForegroundColour(parent->GetForegroundColour()) ;
2bda0e17
KB
120
121 if ( id == -1 )
c085e333 122 m_windowId = (int)NewControlId();
2bda0e17 123 else
c085e333 124 m_windowId = id;
2bda0e17
KB
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
c085e333 145
2bda0e17
KB
146 long msStyle = ES_LEFT | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
147 if (m_windowStyle & wxTE_MULTILINE)
c085e333 148 msStyle |= ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL ; // WS_BORDER
2bda0e17
KB
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";
57c208c5 161#if wxUSE_RICHEDIT
2bda0e17 162 if ( m_windowStyle & wxTE_MULTILINE )
2bda0e17 163 {
c085e333
VZ
164 msStyle |= ES_AUTOVSCROLL;
165 m_isRich = TRUE;
166 windowClass = "RichEdit" ;
2bda0e17
KB
167 }
168 else
c085e333
VZ
169#endif
170 m_isRich = FALSE;
2bda0e17
KB
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.
57c208c5 177#if wxUSE_RICHEDIT
2bda0e17
KB
178 if (m_windowStyle & wxSIMPLE_BORDER)
179 {
180 windowClass = "EDIT";
c085e333 181 m_isRich = FALSE;
2bda0e17
KB
182 }
183#endif
184
185 // Even with extended styles, need to combine with WS_BORDER
186 // for them to look right.
c085e333 187 if ( want3D || wxStyleHasBorder(m_windowStyle) )
2bda0e17
KB
188 msStyle |= WS_BORDER;
189
c085e333 190 m_hWnd = (WXHWND)::CreateWindowEx(exStyle, windowClass, NULL,
2bda0e17
KB
191 msStyle,
192 0, 0, 0, 0, (HWND) ((wxWindow*)parent)->GetHWND(), (HMENU)m_windowId,
c4e7c2aa 193 m_globalHandle ? (HINSTANCE) m_globalHandle : wxGetInstance(), NULL);
2bda0e17 194
c085e333
VZ
195 wxCHECK_MSG( m_hWnd, FALSE, "Failed to create text ctrl" );
196
2bda0e17
KB
197#if CTL3D
198 if ( want3D )
199 {
c085e333
VZ
200 Ctl3dSubclassCtl((HWND)m_hWnd);
201 m_useCtl3D = TRUE;
2bda0e17
KB
202 }
203#endif
204
57c208c5 205#if wxUSE_RICHEDIT
2bda0e17
KB
206 if (m_isRich)
207 {
c085e333
VZ
208 // Have to enable events
209 ::SendMessage((HWND)m_hWnd, EM_SETEVENTMASK, 0,
210 ENM_CHANGE | ENM_DROPFILES | ENM_SELCHANGE | ENM_UPDATE);
2bda0e17
KB
211 }
212#endif
213
214 SubclassWin(GetHWND());
215
c0ed460c 216 if ( parent->GetFont().Ok() && parent->GetFont().Ok() )
2bda0e17 217 {
c0ed460c 218 SetFont(parent->GetFont());
2bda0e17
KB
219 }
220 else
221 {
c085e333 222 SetFont(wxSystemSettings::GetSystemFont(wxSYS_SYSTEM_FONT));
2bda0e17
KB
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__))
c085e333
VZ
229 if ( !value.IsEmpty() )
230 {
231 SetValue(value);
232 }
2bda0e17
KB
233#endif
234
235 return TRUE;
236}
237
238// Make sure the window style (etc.) reflects the HWND style (roughly)
239void wxTextCtrl::AdoptAttributesFromHWND(void)
240{
c085e333 241 wxWindow::AdoptAttributesFromHWND();
2bda0e17 242
c085e333
VZ
243 HWND hWnd = (HWND) GetHWND();
244 long style = GetWindowLong((HWND) hWnd, GWL_STYLE);
2bda0e17
KB
245
246 char buf[256];
247
248#ifndef __WIN32__
c085e333 249 GetClassName((HWND) hWnd, buf, 256);
2bda0e17
KB
250#else
251#ifdef UNICODE
c085e333 252 GetClassNameW((HWND) hWnd, buf, 256);
57c208c5
JS
253#else
254#ifdef __TWIN32__
255 GetClassName((HWND) hWnd, buf, 256);
2bda0e17 256#else
c085e333 257 GetClassNameA((HWND) hWnd, buf, 256);
2bda0e17 258#endif
57c208c5 259#endif
2bda0e17
KB
260#endif
261
c085e333
VZ
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;
2bda0e17
KB
278}
279
280void wxTextCtrl::SetupColours(void)
281{
282 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
fd71308f 283 SetForegroundColour(GetParent()->GetForegroundColour());
2bda0e17
KB
284}
285
286wxString 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;
c085e333 293 return str;
2bda0e17
KB
294}
295
296void 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
debe6624 329void wxTextCtrl::SetSize(int x, int y, int width, int height, int sizeFlags)
2bda0e17
KB
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
81d66cf3
JS
343 AdjustForParentClientOrigin(x1, y1, sizeFlags);
344
2bda0e17
KB
345 int cx; // button font dimensions
346 int cy;
347
ce3ed50d 348 wxGetCharSize(GetHWND(), &cx, &cy, & this->GetFont());
2bda0e17 349
1c4a764c 350 int control_width, control_height, control_x, control_y;
2bda0e17
KB
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
1c4a764c
VZ
362 control_x = x1;
363 control_y = y1;
364 control_width = w1;
365 control_height = h1;
2bda0e17
KB
366
367 // Calculations may have made text size too small
368 if (control_height <= 0)
1c4a764c 369 control_height = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
2bda0e17
KB
370
371 if (control_width <= 0)
1c4a764c 372 control_width = DEFAULT_ITEM_WIDTH;
2bda0e17
KB
373
374 MoveWindow((HWND) GetHWND(), (int)control_x, (int)control_y,
375 (int)control_width, (int)control_height, TRUE);
2bda0e17
KB
376}
377
378// Clipboard operations
379void wxTextCtrl::Copy(void)
380{
381 HWND hWnd = (HWND) GetHWND();
382 SendMessage(hWnd, WM_COPY, 0, 0L);
383}
384
385void wxTextCtrl::Cut(void)
386{
387 HWND hWnd = (HWND) GetHWND();
388 SendMessage(hWnd, WM_CUT, 0, 0L);
389}
390
391void wxTextCtrl::Paste(void)
392{
393 HWND hWnd = (HWND) GetHWND();
394 SendMessage(hWnd, WM_PASTE, 0, 0L);
395}
396
debe6624 397void wxTextCtrl::SetEditable(bool editable)
2bda0e17
KB
398{
399 HWND hWnd = (HWND) GetHWND();
400 SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L);
401}
402
debe6624 403void wxTextCtrl::SetInsertionPoint(long pos)
2bda0e17
KB
404{
405 HWND hWnd = (HWND) GetHWND();
406#ifdef __WIN32__
57c208c5 407#if wxUSE_RICHEDIT
2bda0e17
KB
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
429void wxTextCtrl::SetInsertionPointEnd(void)
430{
431 long pos = GetLastPosition();
432 SetInsertionPoint(pos);
433}
434
435long wxTextCtrl::GetInsertionPoint(void) const
436{
57c208c5 437#if wxUSE_RICHEDIT
2bda0e17
KB
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
452long 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
debe6624 469void wxTextCtrl::Replace(long from, long to, const wxString& value)
2bda0e17
KB
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.
b3324be2 484 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const char *)value, 0, 0);
2bda0e17
KB
485
486 // Paste into edit control
487 SendMessage(hWnd, WM_PASTE, (WPARAM)0, (LPARAM)0L);
488}
489
debe6624 490void wxTextCtrl::Remove(long from, long to)
2bda0e17
KB
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
debe6624 505void wxTextCtrl::SetSelection(long from, long to)
2bda0e17
KB
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
528bool wxTextCtrl::LoadFile(const wxString& file)
529{
2432b92d 530 if (!wxFileExists(WXSTRINGCAST file))
2bda0e17
KB
531 return FALSE;
532
b823f5a1 533 m_fileName = file;
2bda0e17
KB
534
535 Clear();
536
fbc535ff
JS
537// ifstream input(WXSTRINGCAST file, ios::nocreate | ios::in);
538 ifstream input(WXSTRINGCAST file, ios::in);
2bda0e17
KB
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
ce3ed50d
JS
548#ifdef __SALFORDC__
549 struct _stat stat_buf;
550 if (stat((char*) (const char*) file, &stat_buf) < 0)
551 return FALSE;
552#else
2bda0e17
KB
553 struct stat stat_buf;
554 if (stat(file, &stat_buf) < 0)
555 return FALSE;
ce3ed50d
JS
556#endif
557
2bda0e17
KB
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);
c085e333
VZ
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++;
2bda0e17
KB
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.
588bool wxTextCtrl::SaveFile(const wxString& file)
589{
b823f5a1
JS
590 wxString theFile(file);
591 if (theFile == "")
592 theFile = m_fileName;
593 if (theFile == "")
2bda0e17 594 return FALSE;
b823f5a1 595 m_fileName = theFile;
2bda0e17 596
b823f5a1 597 ofstream output((char*) (const char*) theFile);
2bda0e17 598 if (output.bad())
c085e333 599 return FALSE;
2bda0e17
KB
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
c085e333
VZ
607 // Convert \r\n to just \n
608 while (*pstr)
609 {
610 if (*pstr != '\r')
611 output << *pstr;
612 pstr++;
613 }
2bda0e17
KB
614
615 farfree(tmp_buffer);
616 SendMessage((HWND) GetHWND(), EM_SETMODIFY, FALSE, 0L);
617
618 return TRUE;
619}
620
621void 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
644void wxTextCtrl::Clear(void)
645{
646// SendMessage((HWND) GetHWND(), WM_SETTEXT, 0, (LPARAM)"");
647 SetWindowText((HWND) GetHWND(), "");
648}
649
650bool wxTextCtrl::IsModified(void) const
651{
652 return (SendMessage((HWND) GetHWND(), EM_GETMODIFY, 0, 0) != 0);
653}
654
655// Makes 'unmodified'
656void 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
666int wxTextCtrl::GetNumberOfLines(void) const
667{
668 return (int)SendMessage((HWND) GetHWND(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
669}
670
debe6624 671long wxTextCtrl::XYToPosition(long x, long y) const
2bda0e17
KB
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
debe6624 680void wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
2bda0e17
KB
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
debe6624 693void wxTextCtrl::ShowPosition(long pos)
2bda0e17
KB
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
debe6624 723int wxTextCtrl::GetLineLength(long lineNo) const
2bda0e17
KB
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
debe6624 731wxString wxTextCtrl::GetLineText(long lineNo) const
2bda0e17
KB
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;
c085e333 737 return wxString(wxBuffer);
2bda0e17
KB
738}
739
740/*
741 * Text item
742 */
743
744void wxTextCtrl::Command(wxCommandEvent & event)
745{
746 SetValue (event.GetString());
747 ProcessCommand (event);
748}
749
750void 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
3f1af920 767// Borland. See note in textctrl.h.
2bda0e17
KB
768#ifndef NO_TEXT_WINDOW_STREAM
769int wxTextCtrl::overflow(int c)
770{
771 // Make sure there is a holding area
7cf98a65
UU
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
2bda0e17
KB
775 if ( allocate()==EOF )
776 {
2432b92d 777 wxLogError("Streambuf allocation failed");
2bda0e17
KB
778 return EOF;
779 }
7cf98a65 780#endif
2bda0e17
KB
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");
7cf98a65
UU
797
798#if wxUSE_IOSTREAMH
799 setp( base(), base() );
800#else
801 setp( pbase(), pbase() );
802#endif
2bda0e17
KB
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//=========================================================================
853int 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//=========================================================================
880int wxTextCtrl::underflow(void)
881{
882 return EOF;
883}
884#endif
885
886wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
887{
888 WriteText(s);
889 return *this;
890}
891
debe6624 892wxTextCtrl& wxTextCtrl::operator<<(float f)
2bda0e17 893{
b823f5a1
JS
894 wxString str;
895 str.Printf("%.2f", f);
896 WriteText(str);
897 return *this;
2bda0e17
KB
898}
899
debe6624 900wxTextCtrl& wxTextCtrl::operator<<(double d)
2bda0e17 901{
b823f5a1
JS
902 wxString str;
903 str.Printf("%.2f", d);
904 WriteText(str);
905 return *this;
2bda0e17
KB
906}
907
debe6624 908wxTextCtrl& wxTextCtrl::operator<<(int i)
2bda0e17 909{
b823f5a1
JS
910 wxString str;
911 str.Printf("%d", i);
912 WriteText(str);
913 return *this;
2bda0e17
KB
914}
915
debe6624 916wxTextCtrl& wxTextCtrl::operator<<(long i)
2bda0e17 917{
b823f5a1
JS
918 wxString str;
919 str.Printf("%ld", i);
920 WriteText(str);
921 return *this;
2bda0e17
KB
922}
923
924wxTextCtrl& wxTextCtrl::operator<<(const char c)
925{
b823f5a1 926 char buf[2];
2bda0e17 927
b823f5a1
JS
928 buf[0] = c;
929 buf[1] = 0;
930 WriteText(buf);
931 return *this;
2bda0e17
KB
932}
933
debe6624 934WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor,
c085e333 935 WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
2bda0e17
KB
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
962void wxTextCtrl::OnChar(wxKeyEvent& event)
963{
4fabb575
JS
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 }
c085e333
VZ
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) )
ae29de83 985 return;
c085e333 986 }
ae29de83
VZ
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();
2bda0e17
KB
998}
999
ae29de83 1000long wxTextCtrl::MSWGetDlgCode()
2bda0e17 1001{
ae29de83 1002 long lRc = DLGC_WANTCHARS | DLGC_WANTARROWS;
2004484f 1003 if ( m_windowStyle & wxTE_PROCESS_ENTER )
c59147ba
VZ
1004 lRc |= DLGC_WANTMESSAGE;
1005 else if ( m_windowStyle & wxTE_MULTILINE )
ae29de83 1006 lRc |= DLGC_WANTMESSAGE;
2004484f
JS
1007 // ??
1008 if ( m_windowStyle & wxTE_PROCESS_TAB )
1009 lRc |= DLGC_WANTTAB;
ae29de83
VZ
1010
1011 return lRc;
1012}
1013
2bda0e17
KB
1014void 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
debe6624 1035bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
2bda0e17
KB
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*/
2bda0e17
KB
1071 switch (param)
1072 {
1073 case EN_SETFOCUS:
2bda0e17 1074 case EN_KILLFOCUS:
ae29de83
VZ
1075 {
1076 wxFocusEvent event(param == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
1077 : wxEVT_SET_FOCUS,
1078 m_windowId);
1079 event.SetEventObject( this );
02800301 1080 GetEventHandler()->ProcessEvent(event);
ae29de83 1081 }
2bda0e17 1082 break;
ae29de83 1083
2bda0e17 1084 case EN_CHANGE:
ae29de83
VZ
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 }
2bda0e17 1093 break;
ae29de83
VZ
1094
1095 // the other notification messages are not processed
1096 case EN_UPDATE:
2bda0e17 1097 case EN_ERRSPACE:
2bda0e17 1098 case EN_MAXTEXT:
2bda0e17 1099 case EN_HSCROLL:
2bda0e17 1100 case EN_VSCROLL:
2bda0e17 1101 default:
ae29de83 1102 return FALSE;
2bda0e17 1103 }
2bda0e17 1104
ae29de83
VZ
1105 // processed
1106 return TRUE;
2bda0e17
KB
1107}
1108
1109
1110// For Rich Edit controls. Do we need it?
1111#if 0
57c208c5 1112#if wxUSE_RICHEDIT
debe6624 1113bool wxTextCtrl::MSWNotify(WXWPARAM wParam, WXLPARAM lParam)
2bda0e17 1114{
c085e333
VZ
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
02800301 1129 if ( !GetEventHandler()->ProcessEvent(event) )
c085e333
VZ
1130 return FALSE;
1131
1132 return TRUE;
2bda0e17
KB
1133}
1134#endif
1135#endif
1136