]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/textctrl.cpp
fixed refresh problem due to rounding errors
[wxWidgets.git] / src / mac / carbon / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: AUTHOR
5 // Modified by:
6 // Created: ??/??/98
7 // RCS-ID: $Id$
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "textctrl.h"
14 #endif
15
16 #ifndef __WXMAC__
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #else
20 #include <stat.h>
21 #endif
22 #include <fstream.h>
23
24 #include "wx/textctrl.h"
25 #include "wx/settings.h"
26 #include "wx/filefn.h"
27 #include "wx/utils.h"
28
29 #if defined(__BORLANDC__) && !defined(__WIN32__)
30 #include <alloc.h>
31 #else
32 #ifndef __MWERKS__
33 #ifndef __GNUWIN32__
34 #include <malloc.h>
35 #endif
36 #endif
37 #endif
38
39 #include "wx/mac/uma.h"
40
41 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
42
43 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
44 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
45 EVT_CHAR(wxTextCtrl::OnChar)
46 END_EVENT_TABLE()
47
48 // Text item
49 wxTextCtrl::wxTextCtrl()
50 #ifndef NO_TEXT_WINDOW_STREAM
51 :streambuf()
52 #endif
53 {
54 m_fileName = "";
55 }
56
57 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
58 const wxString& st,
59 const wxPoint& pos,
60 const wxSize& size, long style,
61 const wxValidator& validator,
62 const wxString& name)
63 {
64 m_macHorizontalBorder = 2 ; // additional pixels around the real control
65 m_macVerticalBorder = 2 ;
66
67 wxSize mySize = size ;
68
69 Rect bounds ;
70 Str255 title ;
71
72 if ( mySize.y == -1 )
73 {
74 if ( UMAHasAppearance() )
75 mySize.y = 16 ;
76 else
77 mySize.y = 24 ;
78 }
79 MacPreControlCreate( parent , id , "" , pos , mySize ,style, validator , name , &bounds , title ) ;
80
81 m_macControl = UMANewControl( parent->GetMacRootWindow() , &bounds , "\p" , true , 0 , 0 , 1,
82 kControlEditTextProc , (long) this ) ;
83 MacPostControlCreate() ;
84
85 wxString value ;
86
87 if( wxApp::s_macDefaultEncodingIsPC )
88 value = wxMacMakeMacStringFromPC( st ) ;
89 else
90 value = st ;
91 UMASetControlData( m_macControl, 0, kControlEditTextTextTag , value.Length() , (char*) ((const char*)value) ) ;
92
93 return TRUE;
94 }
95
96 wxString wxTextCtrl::GetValue() const
97 {
98 Size actualsize;
99 UMAGetControlData( m_macControl, 0, kControlEditTextTextTag , 32767 , wxBuffer , &actualsize) ;
100 wxBuffer[actualsize] = 0 ;
101 if( wxApp::s_macDefaultEncodingIsPC )
102 return wxMacMakePCStringFromMac( wxBuffer ) ;
103 else
104 return wxString(wxBuffer);
105 }
106
107 void wxTextCtrl::SetValue(const wxString& st)
108 {
109 wxString value ;
110
111 if( wxApp::s_macDefaultEncodingIsPC )
112 value = wxMacMakeMacStringFromPC( st ) ;
113 else
114 value = st ;
115 UMASetControlData( m_macControl, 0, kControlEditTextTextTag , value.Length() , (char*) ((const char*)value) ) ;
116 Refresh() ;
117 // MacInvalidateControl() ;
118 }
119
120 void wxTextCtrl::SetSize(int x, int y, int width, int height, int sizeFlags)
121 {
122 wxControl::SetSize( x , y , width , height , sizeFlags ) ;
123 }
124
125 // Clipboard operations
126 void wxTextCtrl::Copy()
127 {
128 TEHandle teH ;
129 long size ;
130
131 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
132 TECopy( teH ) ;
133 }
134
135 void wxTextCtrl::Cut()
136 {
137 TEHandle teH ;
138 long size ;
139
140 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
141 TECut( teH ) ;
142 // MacInvalidateControl() ;
143 }
144
145 void wxTextCtrl::Paste()
146 {
147 TEHandle teH ;
148 long size ;
149
150 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
151 TEPaste( teH ) ;
152 // MacInvalidateControl() ;
153 }
154
155 void wxTextCtrl::SetEditable(bool editable)
156 {
157 if ( editable )
158 UMAActivateControl( m_macControl ) ;
159 else
160 UMADeactivateControl( m_macControl ) ;
161 }
162
163 void wxTextCtrl::SetInsertionPoint(long pos)
164 {
165 SetSelection( pos , pos ) ;
166 }
167
168 void wxTextCtrl::SetInsertionPointEnd()
169 {
170 long pos = GetLastPosition();
171 SetInsertionPoint(pos);
172 }
173
174 long wxTextCtrl::GetInsertionPoint() const
175 {
176 ControlEditTextSelectionRec selection ;
177 TEHandle teH ;
178 long size ;
179
180 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
181 // UMAGetControlData( m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection , &size ) ;
182 return (**teH).selStart ;
183 }
184
185 long wxTextCtrl::GetLastPosition() const
186 {
187 ControlEditTextSelectionRec selection ;
188 TEHandle teH ;
189 long size ;
190
191 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
192
193 // UMAGetControlData( m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection , &size ) ;
194 return (**teH).teLength ;
195 }
196
197 void wxTextCtrl::Replace(long from, long to, const wxString& value)
198 {
199 TEHandle teH ;
200 long size ;
201
202 ControlEditTextSelectionRec selection ;
203
204 selection.selStart = from ;
205 selection.selEnd = to ;
206 UMASetControlData( m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
207 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
208 TESetSelect( from , to , teH ) ;
209 TEDelete( teH ) ;
210 TEInsert( value , value.Length() , teH ) ;
211 // MacInvalidateControl() ;
212 }
213
214 void wxTextCtrl::Remove(long from, long to)
215 {
216 TEHandle teH ;
217 long size ;
218
219 ControlEditTextSelectionRec selection ;
220
221 selection.selStart = from ;
222 selection.selEnd = to ;
223 UMASetControlData( m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
224 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
225 TEDelete( teH ) ;
226 // MacInvalidateControl() ;
227 }
228
229 void wxTextCtrl::SetSelection(long from, long to)
230 {
231 ControlEditTextSelectionRec selection ;
232 TEHandle teH ;
233 long size ;
234
235 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
236
237 selection.selStart = from ;
238 selection.selEnd = to ;
239
240 UMASetControlData( m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
241 TESetSelect( selection.selStart , selection.selEnd , teH ) ;
242 }
243
244 bool wxTextCtrl::LoadFile(const wxString& file)
245 {
246 if (!wxFileExists(file))
247 return FALSE;
248
249 m_fileName = file;
250
251 Clear();
252
253 #ifndef __WXMAC__
254 ifstream input((char*) (const char*) file, ios::nocreate | ios::in);
255 #else
256 ifstream input((char*) (const char*) file, ios::in);
257 #endif
258 if (!input.bad())
259 {
260 struct stat stat_buf;
261 if (stat(file, &stat_buf) < 0)
262 return FALSE;
263 // This may need to be a bigger buffer than the file size suggests,
264 // if it's a UNIX file. Give it an extra 1000 just in case.
265 char *tmp_buffer = (char*)malloc((size_t)(stat_buf.st_size+1+1000));
266 long no_lines = 0;
267 long pos = 0;
268 while (!input.eof() && input.peek() != EOF)
269 {
270 input.getline(wxBuffer, 500);
271 int len = strlen(wxBuffer);
272 wxBuffer[len] = 13;
273 wxBuffer[len+1] = 10;
274 wxBuffer[len+2] = 0;
275 strcpy(tmp_buffer+pos, wxBuffer);
276 pos += strlen(wxBuffer);
277 no_lines++;
278 }
279
280 // TODO add line
281
282 free(tmp_buffer);
283
284 return TRUE;
285 }
286 return FALSE;
287 }
288
289 // If file is null, try saved file name first
290 // Returns TRUE if succeeds.
291 bool wxTextCtrl::SaveFile(const wxString& file)
292 {
293 wxString theFile(file);
294 if (theFile == "")
295 theFile = m_fileName;
296 if (theFile == "")
297 return FALSE;
298 m_fileName = theFile;
299
300 ofstream output((char*) (const char*) theFile);
301 if (output.bad())
302 return FALSE;
303
304 // TODO get and save text
305
306 return FALSE;
307 }
308
309 void wxTextCtrl::WriteText(const wxString& text)
310 {
311 TEHandle teH ;
312 long size ;
313
314 memcpy( wxBuffer, text , text.Length() ) ;
315 wxBuffer[text.Length() ] = 0 ;
316 // wxMacConvertNewlines( wxBuffer , wxBuffer ) ;
317
318 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
319
320 TEInsert( wxBuffer , strlen( wxBuffer) , teH ) ;
321 Refresh() ;
322 }
323
324 void wxTextCtrl::AppendText(const wxString& text)
325 {
326 SetInsertionPointEnd();
327 WriteText(text);
328 }
329
330 void wxTextCtrl::Clear()
331 {
332 TEHandle teH ;
333 long size ;
334 ControlEditTextSelectionRec selection ;
335
336 selection.selStart = 0 ;
337 selection.selEnd = 32767 ;
338
339 UMASetControlData( m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
340
341 UMAGetControlData( m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
342 TECut( teH ) ;
343 // MacInvalidateControl() ;
344 }
345
346 bool wxTextCtrl::IsModified() const
347 {
348 return TRUE;
349 }
350
351 // Makes 'unmodified'
352 void wxTextCtrl::DiscardEdits()
353 {
354 // TODO
355 }
356
357 int wxTextCtrl::GetNumberOfLines() const
358 {
359 // TODO
360 return 0;
361 }
362
363 long wxTextCtrl::XYToPosition(long x, long y) const
364 {
365 // TODO
366 return 0;
367 }
368
369 void wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
370 {
371 // TODO
372 }
373
374 void wxTextCtrl::ShowPosition(long pos)
375 {
376 // TODO
377 }
378
379 int wxTextCtrl::GetLineLength(long lineNo) const
380 {
381 return GetValue().Length();
382 }
383
384 wxString wxTextCtrl::GetLineText(long lineNo) const
385 {
386 return GetValue();
387 }
388
389 /*
390 * Text item
391 */
392
393 void wxTextCtrl::Command(wxCommandEvent & event)
394 {
395 SetValue (event.GetString());
396 ProcessCommand (event);
397 }
398
399 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
400 {
401 // By default, load the first file into the text window.
402 if (event.GetNumberOfFiles() > 0)
403 {
404 LoadFile(event.GetFiles()[0]);
405 }
406 }
407
408 void wxTextCtrl::OnChar(wxKeyEvent& event)
409 {
410 switch( event.KeyCode() )
411 {
412 case WXK_RETURN:
413 {
414 if ( !(m_windowStyle & wxTE_MULTILINE) )
415 {
416 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
417 event.SetEventObject( this );
418 if ( GetEventHandler()->ProcessEvent(event) )
419 return;
420 }
421 //else: multiline controls need Enter for themselves
422
423 break;
424 }
425 case WXK_TAB:
426 // always produce navigation event - even if we process TAB
427 // ourselves the fact that we got here means that the user code
428 // decided to skip processing of this TAB - probably to let it
429 // do its default job.
430 //
431 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
432 // handled by Windows
433 {
434 wxNavigationKeyEvent eventNav;
435 eventNav.SetDirection(!event.ShiftDown());
436 eventNav.SetWindowChange(FALSE);
437 eventNav.SetEventObject(this);
438
439 if ( GetEventHandler()->ProcessEvent(eventNav) )
440 return;
441 }
442 break;
443
444 default:
445 event.Skip();
446 return;
447 }
448
449 // don't just call event.Skip() because this will cause TABs and ENTERs
450 // be passed upwards and we don't always want this - instead process it
451 // right here
452
453 // FIXME
454 event.Skip();
455 }
456 // The streambuf code was partly taken from chapter 3 by Jerry Schwarz of
457 // AT&T's "C++ Lanuage System Release 3.0 Library Manual" - Stein Somers
458
459 //=========================================================================
460 // Called then the buffer is full (gcc 2.6.3)
461 // or when "endl" is output (Borland 4.5)
462 //=========================================================================
463 // Class declaration using multiple inheritance doesn't work properly for
464 // Borland. See note in wb_text.h.
465 #ifndef NO_TEXT_WINDOW_STREAM
466 int wxTextCtrl::overflow(int c)
467 {
468 // Make sure there is a holding area
469 if ( allocate()==EOF )
470 {
471 wxError("Streambuf allocation failed","Internal error");
472 return EOF;
473 }
474
475 // Verify that there are no characters in get area
476 if ( gptr() && gptr() < egptr() )
477 {
478 wxError("Who's trespassing my get area?","Internal error");
479 return EOF;
480 }
481
482 // Reset get area
483 setg(0,0,0);
484
485 // Make sure there is a put area
486 if ( ! pptr() )
487 {
488 /* This doesn't seem to be fatal so comment out error message */
489 // wxError("Put area not opened","Internal error");
490 setp( base(), base() );
491 }
492
493 // Determine how many characters have been inserted but no consumed
494 int plen = pptr() - pbase();
495
496 // Now Jerry relies on the fact that the buffer is at least 2 chars
497 // long, but the holding area "may be as small as 1" ???
498 // And we need an additional \0, so let's keep this inefficient but
499 // safe copy.
500
501 // If c!=EOF, it is a character that must also be comsumed
502 int xtra = c==EOF? 0 : 1;
503
504 // Write temporary C-string to wxTextWindow
505 {
506 char *txt = new char[plen+xtra+1];
507 memcpy(txt, pbase(), plen);
508 txt[plen] = (char)c; // append c
509 txt[plen+xtra] = '\0'; // append '\0' or overwrite c
510 // If the put area already contained \0, output will be truncated there
511 AppendText(txt);
512 delete[] txt;
513 }
514
515 // Reset put area
516 setp(pbase(), epptr());
517
518 #if defined(__WATCOMC__)
519 return __NOT_EOF;
520 #elif defined(zapeof) // HP-UX (all cfront based?)
521 return zapeof(c);
522 #else
523 return c!=EOF ? c : 0; // this should make everybody happy
524 #endif
525 }
526
527 //=========================================================================
528 // called then "endl" is output (gcc) or then explicit sync is done (Borland)
529 //=========================================================================
530 int wxTextCtrl::sync()
531 {
532 // Verify that there are no characters in get area
533 if ( gptr() && gptr() < egptr() )
534 {
535 wxError("Who's trespassing my get area?","Internal error");
536 return EOF;
537 }
538
539 if ( pptr() && pptr() > pbase() ) return overflow(EOF);
540
541 return 0;
542 /* OLD CODE
543 int len = pptr() - pbase();
544 char *txt = new char[len+1];
545 strncpy(txt, pbase(), len);
546 txt[len] = '\0';
547 (*this) << txt;
548 setp(pbase(), epptr());
549 delete[] txt;
550 return 0;
551 */
552 }
553
554 //=========================================================================
555 // Should not be called by a "ostream". Used by a "istream"
556 //=========================================================================
557 int wxTextCtrl::underflow()
558 {
559 return EOF;
560 }
561 #endif
562
563 wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
564 {
565 AppendText(s);
566 return *this;
567 }
568
569 wxTextCtrl& wxTextCtrl::operator<<(float f)
570 {
571 wxString str;
572 str.Printf("%.2f", f);
573 AppendText(str);
574 return *this;
575 }
576
577 wxTextCtrl& wxTextCtrl::operator<<(double d)
578 {
579 wxString str;
580 str.Printf("%.2f", d);
581 AppendText(str);
582 return *this;
583 }
584
585 wxTextCtrl& wxTextCtrl::operator<<(int i)
586 {
587 wxString str;
588 str.Printf("%d", i);
589 AppendText(str);
590 return *this;
591 }
592
593 wxTextCtrl& wxTextCtrl::operator<<(long i)
594 {
595 wxString str;
596 str.Printf("%ld", i);
597 AppendText(str);
598 return *this;
599 }
600
601 wxTextCtrl& wxTextCtrl::operator<<(const char c)
602 {
603 char buf[2];
604
605 buf[0] = c;
606 buf[1] = 0;
607 AppendText(buf);
608 return *this;
609 }
610