]> git.saurik.com Git - wxWidgets.git/blame - src/stc/PlatWX.cpp
fixed crash when string couldn't be converted to UTF8 in GetTextExtent() under GTK 2
[wxWidgets.git] / src / stc / PlatWX.cpp
CommitLineData
9ce192d4 1// Scintilla source code edit control
be5a51fb 2// PlatWX.cxx - implementation of platform facilities on wxWidgets
9ce192d4
RD
3// Copyright 1998-1999 by Neil Hodgson <neilh@scintilla.org>
4// Robin Dunn <robin@aldunn.com>
5// The License.txt file describes the conditions under which this software may be distributed.
6
f6bcfd97 7#include <ctype.h>
9ce192d4 8
1a2fb4cd 9#include <wx/wx.h>
10ef30eb 10#include <wx/encconv.h>
9e730a78
RD
11#include <wx/listctrl.h>
12#include <wx/mstream.h>
13#include <wx/image.h>
14#include <wx/imaglist.h>
1a2fb4cd 15
9ce192d4 16#include "Platform.h"
1a2fb4cd 17#include "PlatWX.h"
9ce192d4
RD
18#include "wx/stc/stc.h"
19
f97d84a6
RD
20
21#ifdef __WXGTK__
22#include <gtk/gtk.h>
23#endif
24
1a2fb4cd 25
9ce192d4 26Point Point::FromLong(long lpoint) {
f6bcfd97 27 return Point(lpoint & 0xFFFF, lpoint >> 16);
9ce192d4
RD
28}
29
30wxRect wxRectFromPRectangle(PRectangle prc) {
d13ea3aa
RD
31 wxRect r(prc.left, prc.top,
32 prc.Width(), prc.Height());
33 return r;
9ce192d4
RD
34}
35
36PRectangle PRectangleFromwxRect(wxRect rc) {
bec17edf 37 return PRectangle(rc.GetLeft(), rc.GetTop(),
04ebdf40 38 rc.GetRight()+1, rc.GetBottom()+1);
9ce192d4
RD
39}
40
1a2fb4cd
RD
41wxColour wxColourFromCA(const ColourAllocated& ca) {
42 ColourDesired cd(ca.AsLong());
43 return wxColour(cd.GetRed(), cd.GetGreen(), cd.GetBlue());
9ce192d4
RD
44}
45
1a2fb4cd 46//----------------------------------------------------------------------
9ce192d4
RD
47
48Palette::Palette() {
49 used = 0;
50 allowRealization = false;
51}
52
53Palette::~Palette() {
54 Release();
55}
56
57void Palette::Release() {
58 used = 0;
59}
60
61// This method either adds a colour to the list of wanted colours (want==true)
62// or retrieves the allocated colour back to the ColourPair.
63// This is one method to make it easier to keep the code for wanting and retrieving in sync.
64void Palette::WantFind(ColourPair &cp, bool want) {
65 if (want) {
66 for (int i=0; i < used; i++) {
67 if (entries[i].desired == cp.desired)
68 return;
69 }
70
71 if (used < numEntries) {
72 entries[used].desired = cp.desired;
1a2fb4cd 73 entries[used].allocated.Set(cp.desired.AsLong());
9ce192d4
RD
74 used++;
75 }
76 } else {
77 for (int i=0; i < used; i++) {
78 if (entries[i].desired == cp.desired) {
79 cp.allocated = entries[i].allocated;
80 return;
81 }
82 }
1a2fb4cd 83 cp.allocated.Set(cp.desired.AsLong());
9ce192d4
RD
84 }
85}
86
87void Palette::Allocate(Window &) {
88 if (allowRealization) {
89 }
90}
91
92
1a2fb4cd
RD
93//----------------------------------------------------------------------
94
9ce192d4
RD
95Font::Font() {
96 id = 0;
97 ascent = 0;
98}
99
100Font::~Font() {
101}
102
d1558f3d 103void Font::Create(const char *faceName, int characterSet, int size, bool bold, bool italic, bool extraFontFlag) {
1a2fb4cd 104 wxFontEncoding encoding;
65ec6247 105
9ce192d4 106 Release();
1a2fb4cd
RD
107
108 switch (characterSet) {
109 default:
110 case wxSTC_CHARSET_ANSI:
111 case wxSTC_CHARSET_DEFAULT:
112 encoding = wxFONTENCODING_DEFAULT;
113 break;
114
115 case wxSTC_CHARSET_BALTIC:
116 encoding = wxFONTENCODING_ISO8859_13;
117 break;
118
119 case wxSTC_CHARSET_CHINESEBIG5:
120 encoding = wxFONTENCODING_CP950;
121 break;
122
123 case wxSTC_CHARSET_EASTEUROPE:
124 encoding = wxFONTENCODING_ISO8859_2;
125 break;
126
127 case wxSTC_CHARSET_GB2312:
128 encoding = wxFONTENCODING_CP936;
129 break;
130
131 case wxSTC_CHARSET_GREEK:
132 encoding = wxFONTENCODING_ISO8859_7;
133 break;
134
135 case wxSTC_CHARSET_HANGUL:
136 encoding = wxFONTENCODING_CP949;
137 break;
138
139 case wxSTC_CHARSET_MAC:
140 encoding = wxFONTENCODING_DEFAULT;
141 break;
142
143 case wxSTC_CHARSET_OEM:
144 encoding = wxFONTENCODING_DEFAULT;
145 break;
146
147 case wxSTC_CHARSET_RUSSIAN:
148 encoding = wxFONTENCODING_KOI8;
149 break;
150
151 case wxSTC_CHARSET_SHIFTJIS:
152 encoding = wxFONTENCODING_CP932;
153 break;
154
155 case wxSTC_CHARSET_SYMBOL:
156 encoding = wxFONTENCODING_DEFAULT;
157 break;
158
159 case wxSTC_CHARSET_TURKISH:
160 encoding = wxFONTENCODING_ISO8859_9;
161 break;
162
163 case wxSTC_CHARSET_JOHAB:
164 encoding = wxFONTENCODING_DEFAULT;
165 break;
166
167 case wxSTC_CHARSET_HEBREW:
168 encoding = wxFONTENCODING_ISO8859_8;
169 break;
170
171 case wxSTC_CHARSET_ARABIC:
172 encoding = wxFONTENCODING_ISO8859_6;
173 break;
174
175 case wxSTC_CHARSET_VIETNAMESE:
176 encoding = wxFONTENCODING_DEFAULT;
177 break;
178
179 case wxSTC_CHARSET_THAI:
180 encoding = wxFONTENCODING_ISO8859_11;
181 break;
182 }
183
10ef30eb
RD
184 wxFontEncodingArray ea = wxEncodingConverter::GetPlatformEquivalents(encoding);
185 if (ea.GetCount())
186 encoding = ea[0];
1a2fb4cd 187
d1558f3d 188 wxFont* font = new wxFont(size,
9ce192d4
RD
189 wxDEFAULT,
190 italic ? wxITALIC : wxNORMAL,
191 bold ? wxBOLD : wxNORMAL,
192 false,
0c5b83b0 193 stc2wx(faceName),
1a2fb4cd 194 encoding);
d1558f3d
RD
195 font->SetNoAntiAliasing(!extraFontFlag);
196 id = font;
9ce192d4
RD
197}
198
199
200void Font::Release() {
201 if (id)
1a2fb4cd 202 delete (wxFont*)id;
9ce192d4
RD
203 id = 0;
204}
205
1a2fb4cd
RD
206//----------------------------------------------------------------------
207
208class SurfaceImpl : public Surface {
209private:
210 wxDC* hdc;
211 bool hdcOwned;
212 wxBitmap* bitmap;
213 int x;
214 int y;
215 bool unicodeMode;
9ce192d4 216
1a2fb4cd
RD
217public:
218 SurfaceImpl();
219 ~SurfaceImpl();
220
9e730a78
RD
221 virtual void Init(WindowID wid);
222 virtual void Init(SurfaceID sid, WindowID wid);
223 virtual void InitPixMap(int width, int height, Surface *surface_, WindowID wid);
224
225 virtual void Release();
226 virtual bool Initialised();
227 virtual void PenColour(ColourAllocated fore);
228 virtual int LogPixelsY();
229 virtual int DeviceHeightFont(int points);
230 virtual void MoveTo(int x_, int y_);
231 virtual void LineTo(int x_, int y_);
232 virtual void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back);
233 virtual void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back);
234 virtual void FillRectangle(PRectangle rc, ColourAllocated back);
235 virtual void FillRectangle(PRectangle rc, Surface &surfacePattern);
236 virtual void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back);
237 virtual void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);
238 virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource);
239
240 virtual void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
241 virtual void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
242 virtual void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
243 virtual void MeasureWidths(Font &font_, const char *s, int len, int *positions);
244 virtual int WidthText(Font &font_, const char *s, int len);
245 virtual int WidthChar(Font &font_, char ch);
246 virtual int Ascent(Font &font_);
247 virtual int Descent(Font &font_);
248 virtual int InternalLeading(Font &font_);
249 virtual int ExternalLeading(Font &font_);
250 virtual int Height(Font &font_);
251 virtual int AverageCharWidth(Font &font_);
252
253 virtual int SetPalette(Palette *pal, bool inBackGround);
254 virtual void SetClip(PRectangle rc);
255 virtual void FlushCachedState();
256
257 virtual void SetUnicodeMode(bool unicodeMode_);
258 virtual void SetDBCSMode(int codePage);
1a2fb4cd
RD
259
260 void BrushColour(ColourAllocated back);
261 void SetFont(Font &font_);
262};
263
264
265
266SurfaceImpl::SurfaceImpl() :
9ce192d4 267 hdc(0), hdcOwned(0), bitmap(0),
1a2fb4cd
RD
268 x(0), y(0), unicodeMode(0)
269{}
9ce192d4 270
1a2fb4cd 271SurfaceImpl::~SurfaceImpl() {
9ce192d4
RD
272 Release();
273}
274
9e730a78 275void SurfaceImpl::Init(WindowID wid) {
81b32ce5 276#if 0
9ce192d4
RD
277 Release();
278 hdc = new wxMemoryDC();
279 hdcOwned = true;
81b32ce5 280#else
09bb2551 281 // On Mac and GTK the DC is not really valid until it has a bitmap
81b32ce5
RD
282 // selected into it. So instead of just creating the DC with no bitmap,
283 // go ahead and give it one.
9e730a78 284 InitPixMap(1,1,NULL,wid);
0f713d48 285#endif
9ce192d4
RD
286}
287
9e730a78 288void SurfaceImpl::Init(SurfaceID hdc_, WindowID) {
9ce192d4 289 Release();
1a2fb4cd 290 hdc = (wxDC*)hdc_;
9ce192d4
RD
291}
292
88a8b04e 293void SurfaceImpl::InitPixMap(int width, int height, Surface *WXUNUSED(surface_), WindowID) {
9ce192d4 294 Release();
1a2fb4cd 295 hdc = new wxMemoryDC();
9ce192d4 296 hdcOwned = true;
2beb01db
RD
297 if (width < 1) width = 1;
298 if (height < 1) height = 1;
21156596 299 bitmap = new wxBitmap(width, height);
9ce192d4 300 ((wxMemoryDC*)hdc)->SelectObject(*bitmap);
9ce192d4
RD
301}
302
9e730a78
RD
303
304void SurfaceImpl::Release() {
305 if (bitmap) {
306 ((wxMemoryDC*)hdc)->SelectObject(wxNullBitmap);
307 delete bitmap;
308 bitmap = 0;
309 }
310 if (hdcOwned) {
311 delete hdc;
312 hdc = 0;
313 hdcOwned = false;
314 }
315}
316
317
318bool SurfaceImpl::Initialised() {
319 return hdc != 0;
320}
321
322
1a2fb4cd
RD
323void SurfaceImpl::PenColour(ColourAllocated fore) {
324 hdc->SetPen(wxPen(wxColourFromCA(fore), 1, wxSOLID));
9ce192d4
RD
325}
326
1a2fb4cd
RD
327void SurfaceImpl::BrushColour(ColourAllocated back) {
328 hdc->SetBrush(wxBrush(wxColourFromCA(back), wxSOLID));
9ce192d4
RD
329}
330
1a2fb4cd 331void SurfaceImpl::SetFont(Font &font_) {
21156596 332 if (font_.GetID()) {
1a2fb4cd 333 hdc->SetFont(*((wxFont*)font_.GetID()));
f6bcfd97 334 }
9ce192d4
RD
335}
336
1a2fb4cd 337int SurfaceImpl::LogPixelsY() {
9ce192d4
RD
338 return hdc->GetPPI().y;
339}
340
1a2fb4cd 341int SurfaceImpl::DeviceHeightFont(int points) {
9968ba85 342 return points;
f6bcfd97
BP
343}
344
1a2fb4cd 345void SurfaceImpl::MoveTo(int x_, int y_) {
9ce192d4
RD
346 x = x_;
347 y = y_;
348}
349
1a2fb4cd 350void SurfaceImpl::LineTo(int x_, int y_) {
9ce192d4
RD
351 hdc->DrawLine(x,y, x_,y_);
352 x = x_;
353 y = y_;
354}
355
1a2fb4cd 356void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) {
9ce192d4 357 PenColour(fore);
1a2fb4cd 358 BrushColour(back);
9ce192d4
RD
359 hdc->DrawPolygon(npts, (wxPoint*)pts);
360}
361
1a2fb4cd 362void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
9ce192d4 363 PenColour(fore);
1a2fb4cd 364 BrushColour(back);
9ce192d4
RD
365 hdc->DrawRectangle(wxRectFromPRectangle(rc));
366}
367
1a2fb4cd
RD
368void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
369 BrushColour(back);
9ce192d4
RD
370 hdc->SetPen(*wxTRANSPARENT_PEN);
371 hdc->DrawRectangle(wxRectFromPRectangle(rc));
372}
373
1a2fb4cd 374void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
9ce192d4 375 wxBrush br;
1a2fb4cd
RD
376 if (((SurfaceImpl&)surfacePattern).bitmap)
377 br = wxBrush(*((SurfaceImpl&)surfacePattern).bitmap);
9ce192d4
RD
378 else // Something is wrong so display in red
379 br = wxBrush(*wxRED, wxSOLID);
380 hdc->SetPen(*wxTRANSPARENT_PEN);
381 hdc->SetBrush(br);
382 hdc->DrawRectangle(wxRectFromPRectangle(rc));
383}
384
1a2fb4cd 385void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
9ce192d4 386 PenColour(fore);
1a2fb4cd 387 BrushColour(back);
f6bcfd97 388 hdc->DrawRoundedRectangle(wxRectFromPRectangle(rc), 4);
9ce192d4
RD
389}
390
1a2fb4cd 391void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
9ce192d4 392 PenColour(fore);
1a2fb4cd 393 BrushColour(back);
9ce192d4
RD
394 hdc->DrawEllipse(wxRectFromPRectangle(rc));
395}
396
1a2fb4cd 397void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
f6bcfd97
BP
398 wxRect r = wxRectFromPRectangle(rc);
399 hdc->Blit(r.x, r.y, r.width, r.height,
1a2fb4cd
RD
400 ((SurfaceImpl&)surfaceSource).hdc,
401 from.x, from.y, wxCOPY);
9ce192d4
RD
402}
403
1a2fb4cd
RD
404void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font, int ybase,
405 const char *s, int len,
406 ColourAllocated fore, ColourAllocated back) {
9ce192d4 407 SetFont(font);
1a2fb4cd
RD
408 hdc->SetTextForeground(wxColourFromCA(fore));
409 hdc->SetTextBackground(wxColourFromCA(back));
3d7a4fe8 410 FillRectangle(rc, back);
9ce192d4
RD
411
412 // ybase is where the baseline should be, but wxWin uses the upper left
413 // corner, so I need to calculate the real position for the text...
d13ea3aa 414 hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
9ce192d4
RD
415}
416
1a2fb4cd
RD
417void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font, int ybase,
418 const char *s, int len,
419 ColourAllocated fore, ColourAllocated back) {
9ce192d4 420 SetFont(font);
1a2fb4cd
RD
421 hdc->SetTextForeground(wxColourFromCA(fore));
422 hdc->SetTextBackground(wxColourFromCA(back));
3d7a4fe8 423 FillRectangle(rc, back);
9ce192d4
RD
424 hdc->SetClippingRegion(wxRectFromPRectangle(rc));
425
426 // see comments above
d13ea3aa 427 hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
3d7a4fe8 428 hdc->DestroyClippingRegion();
9ce192d4
RD
429}
430
9e730a78
RD
431
432void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font, int ybase,
433 const char *s, int len,
434 ColourAllocated fore) {
435
9ce192d4 436 SetFont(font);
9e730a78
RD
437 hdc->SetTextForeground(wxColourFromCA(fore));
438 hdc->SetBackgroundMode(wxTRANSPARENT);
1a2fb4cd 439
9e730a78
RD
440 // ybase is where the baseline should be, but wxWin uses the upper left
441 // corner, so I need to calculate the real position for the text...
d13ea3aa 442 hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
9e730a78
RD
443
444 hdc->SetBackgroundMode(wxSOLID);
9ce192d4
RD
445}
446
1a2fb4cd 447
10ef30eb 448void SurfaceImpl::MeasureWidths(Font &font, const char *s, int len, int *positions) {
9e730a78 449
d1558f3d
RD
450 wxString str = stc2wx(s, len);
451 wxArrayInt tpos;
10ef30eb 452
d1558f3d 453 SetFont(font);
9e730a78 454
d1558f3d 455 hdc->GetPartialTextExtents(str, tpos);
10ef30eb
RD
456
457#if wxUSE_UNICODE
458 // Map the widths for UCS-2 characters back to the UTF-8 input string
9e730a78
RD
459 // NOTE: I don't think this is right for when sizeof(wxChar) > 2, ie wxGTK2
460 // so figure it out and fix it!
d1558f3d 461 size_t i = 0;
10ef30eb 462 size_t ui = 0;
d99859e4 463 while ((int)i < len) {
10ef30eb
RD
464 unsigned char uch = (unsigned char)s[i];
465 positions[i++] = tpos[ui];
466 if (uch >= 0x80) {
467 if (uch < (0x80 + 0x40 + 0x20)) {
468 positions[i++] = tpos[ui];
469 } else {
470 positions[i++] = tpos[ui];
471 positions[i++] = tpos[ui];
472 }
473 }
474 ui++;
475 }
476#else
477
478 // If not unicode then just use the widths we have
d1558f3d 479 memcpy(positions, tpos.begin(), len * sizeof(int));
10ef30eb 480#endif
9ce192d4
RD
481}
482
10ef30eb 483
9e730a78
RD
484int SurfaceImpl::WidthText(Font &font, const char *s, int len) {
485 SetFont(font);
486 int w;
487 int h;
488
489 hdc->GetTextExtent(stc2wx(s, len), &w, &h);
490 return w;
491}
492
493
1a2fb4cd 494int SurfaceImpl::WidthChar(Font &font, char ch) {
9ce192d4
RD
495 SetFont(font);
496 int w;
497 int h;
10ef30eb
RD
498 char s[2] = { ch, 0 };
499
0c5b83b0 500 hdc->GetTextExtent(stc2wx(s, 1), &w, &h);
9ce192d4
RD
501 return w;
502}
503
1a2fb4cd 504#define EXTENT_TEST wxT(" `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
9ce192d4 505
1a2fb4cd 506int SurfaceImpl::Ascent(Font &font) {
9ce192d4
RD
507 SetFont(font);
508 int w, h, d, e;
509 hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
510 font.ascent = h - d;
511 return font.ascent;
512}
513
1a2fb4cd 514int SurfaceImpl::Descent(Font &font) {
9ce192d4
RD
515 SetFont(font);
516 int w, h, d, e;
517 hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
518 return d;
519}
520
88a8b04e 521int SurfaceImpl::InternalLeading(Font &WXUNUSED(font)) {
9ce192d4
RD
522 return 0;
523}
524
1a2fb4cd 525int SurfaceImpl::ExternalLeading(Font &font) {
9ce192d4
RD
526 SetFont(font);
527 int w, h, d, e;
528 hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
529 return e;
530}
531
1a2fb4cd 532int SurfaceImpl::Height(Font &font) {
9ce192d4 533 SetFont(font);
d13ea3aa 534 return hdc->GetCharHeight() + 1;
9ce192d4
RD
535}
536
1a2fb4cd 537int SurfaceImpl::AverageCharWidth(Font &font) {
9ce192d4
RD
538 SetFont(font);
539 return hdc->GetCharWidth();
540}
541
88a8b04e 542int SurfaceImpl::SetPalette(Palette *WXUNUSED(pal), bool WXUNUSED(inBackGround)) {
65ec6247 543 return 0;
9ce192d4
RD
544}
545
1a2fb4cd 546void SurfaceImpl::SetClip(PRectangle rc) {
9ce192d4
RD
547 hdc->SetClippingRegion(wxRectFromPRectangle(rc));
548}
549
1a2fb4cd 550void SurfaceImpl::FlushCachedState() {
f6bcfd97 551}
9ce192d4 552
1a2fb4cd 553void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
1a2fb4cd
RD
554 unicodeMode=unicodeMode_;
555}
556
88a8b04e 557void SurfaceImpl::SetDBCSMode(int WXUNUSED(codePage)) {
9e730a78
RD
558 // dbcsMode = codePage == SC_CP_DBCS;
559}
560
561
1a2fb4cd
RD
562Surface *Surface::Allocate() {
563 return new SurfaceImpl;
564}
565
566
567//----------------------------------------------------------------------
568
569
570inline wxWindow* GETWIN(WindowID id) { return (wxWindow*)id; }
571
9ce192d4
RD
572Window::~Window() {
573}
574
575void Window::Destroy() {
9e730a78
RD
576 if (id) {
577 Show(FALSE);
1a2fb4cd 578 GETWIN(id)->Destroy();
9e730a78 579 }
9ce192d4
RD
580 id = 0;
581}
582
583bool Window::HasFocus() {
1a2fb4cd 584 return wxWindow::FindFocus() == GETWIN(id);
9ce192d4
RD
585}
586
587PRectangle Window::GetPosition() {
9e730a78 588 if (! id) return PRectangle();
1a2fb4cd 589 wxRect rc(GETWIN(id)->GetPosition(), GETWIN(id)->GetSize());
9ce192d4
RD
590 return PRectangleFromwxRect(rc);
591}
592
593void Window::SetPosition(PRectangle rc) {
f6bcfd97 594 wxRect r = wxRectFromPRectangle(rc);
1a2fb4cd 595 GETWIN(id)->SetSize(r);
9ce192d4
RD
596}
597
598void Window::SetPositionRelative(PRectangle rc, Window) {
599 SetPosition(rc); // ????
600}
601
602PRectangle Window::GetClientPosition() {
9e730a78 603 if (! id) return PRectangle();
1a2fb4cd 604 wxSize sz = GETWIN(id)->GetClientSize();
21156596 605 return PRectangle(0, 0, sz.x, sz.y);
9ce192d4
RD
606}
607
608void Window::Show(bool show) {
1a2fb4cd 609 GETWIN(id)->Show(show);
9ce192d4
RD
610}
611
612void Window::InvalidateAll() {
1a2fb4cd 613 GETWIN(id)->Refresh(false);
26f4607d 614 wxWakeUpIdle();
9ce192d4
RD
615}
616
617void Window::InvalidateRectangle(PRectangle rc) {
f6bcfd97 618 wxRect r = wxRectFromPRectangle(rc);
1a2fb4cd 619 GETWIN(id)->Refresh(false, &r);
26f4607d 620 wxWakeUpIdle();
9ce192d4
RD
621}
622
623void Window::SetFont(Font &font) {
1a2fb4cd 624 GETWIN(id)->SetFont(*((wxFont*)font.GetID()));
9ce192d4
RD
625}
626
627void Window::SetCursor(Cursor curs) {
628 int cursorId;
629
630 switch (curs) {
631 case cursorText:
632 cursorId = wxCURSOR_IBEAM;
633 break;
634 case cursorArrow:
635 cursorId = wxCURSOR_ARROW;
636 break;
637 case cursorUp:
638 cursorId = wxCURSOR_ARROW; // ** no up arrow... wxCURSOR_UPARROW;
639 break;
640 case cursorWait:
641 cursorId = wxCURSOR_WAIT;
642 break;
643 case cursorHoriz:
644 cursorId = wxCURSOR_SIZEWE;
645 break;
646 case cursorVert:
647 cursorId = wxCURSOR_SIZENS;
648 break;
649 case cursorReverseArrow:
15dadf31 650 cursorId = wxCURSOR_RIGHT_ARROW;
9ce192d4 651 break;
9e730a78
RD
652 case cursorHand:
653 cursorId = wxCURSOR_HAND;
1e545382 654 break;
9ce192d4
RD
655 default:
656 cursorId = wxCURSOR_ARROW;
657 break;
658 }
9f79d14b
CE
659#ifdef __WXMOTIF__
660 wxCursor wc = wxStockCursor(cursorId) ;
661#else
662 wxCursor wc = wxCursor(cursorId) ;
663#endif
cb1871ca 664 GETWIN(id)->SetCursor(wc);
9ce192d4
RD
665}
666
667
668void Window::SetTitle(const char *s) {
0c5b83b0 669 GETWIN(id)->SetTitle(stc2wx(s));
9ce192d4
RD
670}
671
672
769a9cb2
RD
673//----------------------------------------------------------------------
674// Helper classes for ListBox
675
267484bc 676
b0d0494f 677// This is a simple subclass of wxListView that just resets focus to the
9e730a78
RD
678// parent when it gets it.
679class wxSTCListBox : public wxListView {
451c5cc7 680public:
9e730a78
RD
681 wxSTCListBox(wxWindow* parent, wxWindowID id,
682 const wxPoint& pos, const wxSize& size,
683 long style)
684 : wxListView(parent, id, pos, size, style)
685 {}
451c5cc7 686
719ee9c3 687
451c5cc7
RD
688 void OnFocus(wxFocusEvent& event) {
689 GetParent()->SetFocus();
690 event.Skip();
691 }
692
5f9eb69c 693 void OnKillFocus(wxFocusEvent& WXUNUSED(event)) {
b0d0494f
RD
694 // Do nothing. Prevents base class from resetting the colors...
695 }
719ee9c3
RD
696
697#ifdef __WXMAC__
698 // For some reason I don't understand yet the focus doesn't really leave
699 // the listbox like it should, so if we get any events feed them back to
700 // the wxSTC
701 void OnKeyDown(wxKeyEvent& event) {
702 GetGrandParent()->GetEventHandler()->ProcessEvent(event);
703 }
704 void OnChar(wxKeyEvent& event) {
705 GetGrandParent()->GetEventHandler()->ProcessEvent(event);
706 }
b0d0494f 707
719ee9c3
RD
708 // And we need to force the focus back when being destroyed
709 ~wxSTCListBox() {
710 GetGrandParent()->SetFocus();
711 }
712#endif
713
451c5cc7
RD
714private:
715 DECLARE_EVENT_TABLE()
716};
717
9e730a78
RD
718BEGIN_EVENT_TABLE(wxSTCListBox, wxListView)
719 EVT_SET_FOCUS( wxSTCListBox::OnFocus)
b0d0494f 720 EVT_KILL_FOCUS(wxSTCListBox::OnKillFocus)
719ee9c3
RD
721#ifdef __WXMAC__
722 EVT_KEY_DOWN( wxSTCListBox::OnKeyDown)
723 EVT_CHAR( wxSTCListBox::OnChar)
724#endif
451c5cc7
RD
725END_EVENT_TABLE()
726
727
728
267484bc 729
9e730a78
RD
730// A window to place the wxSTCListBox upon
731class wxSTCListBoxWin : public wxWindow {
732private:
733 wxListView* lv;
734 CallBackAction doubleClickAction;
735 void* doubleClickActionData;
f97d84a6 736public:
9e730a78 737 wxSTCListBoxWin(wxWindow* parent, wxWindowID id) :
d13ea3aa 738 wxWindow(parent, id, wxDefaultPosition, wxSize(0,0), wxSIMPLE_BORDER )
9e730a78
RD
739 {
740
9e730a78
RD
741 lv = new wxSTCListBox(this, id, wxDefaultPosition, wxDefaultSize,
742 wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxNO_BORDER);
743 lv->SetCursor(wxCursor(wxCURSOR_ARROW));
744 lv->InsertColumn(0, wxEmptyString);
745 lv->InsertColumn(1, wxEmptyString);
b0d0494f
RD
746
747 // Eventhough we immediately reset the focus to the parent, this helps
748 // things to look right...
749 lv->SetFocus();
750
6612393c
RD
751 Hide();
752 }
753
d13ea3aa 754
a4f3565e
RD
755 // On OSX and (possibly others) there can still be pending
756 // messages/events for the list control when Scintilla wants to
757 // close it, so do a pending delete of it instead of destroying
758 // immediately.
759 bool Destroy() {
d13ea3aa 760#ifdef __WXMAC__
719ee9c3 761 // The bottom edge of this window is not getting properly
d13ea3aa
RD
762 // refreshed upon deletion, so help it out...
763 wxWindow* p = GetParent();
764 wxRect r(GetPosition(), GetSize());
765 r.SetHeight(r.GetHeight()+1);
766 p->Refresh(false, &r);
767#endif
a4f3565e
RD
768 if ( !wxPendingDelete.Member(this) )
769 wxPendingDelete.Append(this);
770 return TRUE;
f97d84a6
RD
771 }
772
a4f3565e 773
9e730a78
RD
774 int IconWidth() {
775 wxImageList* il = lv->GetImageList(wxIMAGE_LIST_SMALL);
776 if (il != NULL) {
777 int w, h;
778 il->GetSize(0, w, h);
779 return w;
780 }
781 return 0;
782 }
f97d84a6 783
769a9cb2 784
9e730a78
RD
785 void SetDoubleClickAction(CallBackAction action, void *data) {
786 doubleClickAction = action;
787 doubleClickActionData = data;
788 }
451c5cc7 789
769a9cb2 790
9e730a78
RD
791 void OnFocus(wxFocusEvent& event) {
792 GetParent()->SetFocus();
793 event.Skip();
794 }
769a9cb2
RD
795
796 void OnSize(wxSizeEvent& event) {
d13ea3aa 797 // resize the child
9e730a78 798 wxSize sz = GetClientSize();
d13ea3aa 799 lv->SetSize(sz);
9e730a78
RD
800 // reset the column widths
801 lv->SetColumnWidth(0, IconWidth()+4);
802 lv->SetColumnWidth(1, sz.x - 2 - lv->GetColumnWidth(0) -
803 wxSystemSettings::GetMetric(wxSYS_VSCROLL_X));
804 event.Skip();
769a9cb2 805 }
769a9cb2 806
5f9eb69c 807 void OnActivate(wxListEvent& WXUNUSED(event)) {
9e730a78 808 doubleClickAction(doubleClickActionData);
769a9cb2 809 }
9e730a78
RD
810
811 wxListView* GetLB() { return lv; }
769a9cb2
RD
812
813private:
769a9cb2
RD
814 DECLARE_EVENT_TABLE()
815};
816
9e730a78
RD
817
818BEGIN_EVENT_TABLE(wxSTCListBoxWin, wxWindow)
819 EVT_SET_FOCUS ( wxSTCListBoxWin::OnFocus)
820 EVT_SIZE ( wxSTCListBoxWin::OnSize)
821 EVT_LIST_ITEM_ACTIVATED(-1, wxSTCListBoxWin::OnActivate)
769a9cb2 822END_EVENT_TABLE()
769a9cb2 823
9e730a78
RD
824
825
826inline wxSTCListBoxWin* GETLBW(WindowID win) {
827 return ((wxSTCListBoxWin*)win);
828}
829
830inline wxListView* GETLB(WindowID win) {
831 return GETLBW(win)->GetLB();
1a2fb4cd 832}
769a9cb2
RD
833
834//----------------------------------------------------------------------
835
9e730a78
RD
836class ListBoxImpl : public ListBox {
837private:
838 int lineHeight;
839 bool unicodeMode;
840 int desiredVisibleRows;
841 int aveCharWidth;
842 int maxStrWidth;
843 wxImageList* imgList;
844 wxArrayInt* imgTypeMap;
845
846public:
847 ListBoxImpl();
848 ~ListBoxImpl();
849
850 virtual void SetFont(Font &font);
851 virtual void Create(Window &parent, int ctrlID, int lineHeight_, bool unicodeMode_);
852 virtual void SetAverageCharWidth(int width);
853 virtual void SetVisibleRows(int rows);
854 virtual PRectangle GetDesiredRect();
855 virtual int CaretFromEdge();
856 virtual void Clear();
857 virtual void Append(char *s, int type = -1);
858 virtual int Length();
859 virtual void Select(int n);
860 virtual int GetSelection();
861 virtual int Find(const char *prefix);
862 virtual void GetValue(int n, char *value, int len);
9e730a78
RD
863 virtual void RegisterImage(int type, const char *xpm_data);
864 virtual void ClearRegisteredImages();
865 virtual void SetDoubleClickAction(CallBackAction, void *);
866
867};
868
869
870ListBoxImpl::ListBoxImpl()
871 : lineHeight(10), unicodeMode(false),
872 desiredVisibleRows(5), aveCharWidth(8), maxStrWidth(0),
873 imgList(NULL), imgTypeMap(NULL)
874{
9ce192d4
RD
875}
876
9e730a78
RD
877ListBoxImpl::~ListBoxImpl() {
878 if (imgList) {
879 delete imgList;
880 imgList = NULL;
881 }
882 if (imgTypeMap) {
883 delete imgTypeMap;
884 imgTypeMap = NULL;
885 }
9ce192d4
RD
886}
887
9e730a78
RD
888
889void ListBoxImpl::SetFont(Font &font) {
890 GETLB(id)->SetFont(*((wxFont*)font.GetID()));
891}
892
893
894void ListBoxImpl::Create(Window &parent, int ctrlID, int lineHeight_, bool unicodeMode_) {
895 lineHeight = lineHeight_;
896 unicodeMode = unicodeMode_;
897 maxStrWidth = 0;
1a2fb4cd 898 id = new wxSTCListBoxWin(GETWIN(parent.GetID()), ctrlID);
9e730a78
RD
899 if (imgList != NULL)
900 GETLB(id)->SetImageList(imgList, wxIMAGE_LIST_SMALL);
9ce192d4
RD
901}
902
9e730a78
RD
903
904void ListBoxImpl::SetAverageCharWidth(int width) {
905 aveCharWidth = width;
906}
907
908
909void ListBoxImpl::SetVisibleRows(int rows) {
769a9cb2 910 desiredVisibleRows = rows;
f3c2c221
RD
911}
912
9e730a78
RD
913
914PRectangle ListBoxImpl::GetDesiredRect() {
915 // wxListCtrl doesn't have a DoGetBestSize, so instead we kept track of
916 // the max size in Append and calculate it here...
917 int maxw = maxStrWidth;
1e545382 918 int maxh ;
9e730a78
RD
919
920 // give it a default if there are no lines, and/or add a bit more
921 if (maxw == 0) maxw = 100;
922 maxw += aveCharWidth * 3 +
923 GETLBW(id)->IconWidth() + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
924 if (maxw > 350)
925 maxw = 350;
926
927 // estimate a desired height
928 int count = GETLB(id)->GetItemCount();
929 if (count) {
930 wxRect rect;
931 GETLB(id)->GetItemRect(0, rect);
932 maxh = count * rect.GetHeight();
933 if (maxh > 140) // TODO: Use desiredVisibleRows??
934 maxh = 140;
935
936 // Try to make the size an exact multiple of some number of lines
937 int lines = maxh / rect.GetHeight();
938 maxh = (lines + 1) * rect.GetHeight() + 2;
939 }
940 else
941 maxh = 100;
942
d134f170
RD
943 PRectangle rc;
944 rc.top = 0;
945 rc.left = 0;
9e730a78
RD
946 rc.right = maxw;
947 rc.bottom = maxh;
d134f170
RD
948 return rc;
949}
950
d134f170 951
9e730a78
RD
952int ListBoxImpl::CaretFromEdge() {
953 return 4 + GETLBW(id)->IconWidth();
d134f170
RD
954}
955
9e730a78
RD
956
957void ListBoxImpl::Clear() {
958 GETLB(id)->DeleteAllItems();
9ce192d4
RD
959}
960
9e730a78
RD
961
962void ListBoxImpl::Append(char *s, int type) {
963 wxString text = stc2wx(s);
964 long count = GETLB(id)->GetItemCount();
965 long itemID = GETLB(id)->InsertItem(count, wxEmptyString);
966 GETLB(id)->SetItem(itemID, 1, text);
967 int itemWidth = 0;
968 GETLB(id)->GetTextExtent(text, &itemWidth, NULL);
969 maxStrWidth = wxMax(maxStrWidth, itemWidth);
970 if (type != -1) {
971 wxCHECK_RET(imgTypeMap, wxT("Unexpected NULL imgTypeMap"));
972 long idx = imgTypeMap->Item(type);
973 GETLB(id)->SetItemImage(itemID, idx, idx);
974 }
9ce192d4
RD
975}
976
9e730a78
RD
977
978int ListBoxImpl::Length() {
979 return GETLB(id)->GetItemCount();
9ce192d4
RD
980}
981
9e730a78
RD
982
983void ListBoxImpl::Select(int n) {
895066d8
RD
984 bool select = TRUE;
985 if (n == -1) {
986 n = 0;
987 select = FALSE;
988 }
9e730a78
RD
989 GETLB(id)->Focus(n);
990 GETLB(id)->Select(n, select);
9ce192d4
RD
991}
992
9e730a78
RD
993
994int ListBoxImpl::GetSelection() {
995 return GETLB(id)->GetFirstSelected();
9ce192d4
RD
996}
997
9e730a78 998
88a8b04e 999int ListBoxImpl::Find(const char *WXUNUSED(prefix)) {
b8b0e402 1000 // No longer used
f6bcfd97 1001 return -1;
9ce192d4
RD
1002}
1003
9e730a78
RD
1004
1005void ListBoxImpl::GetValue(int n, char *value, int len) {
1006 wxListItem item;
1007 item.SetId(n);
1008 item.SetColumn(1);
1009 item.SetMask(wxLIST_MASK_TEXT);
1010 GETLB(id)->GetItem(item);
1011 strncpy(value, wx2stc(item.GetText()), len);
9ce192d4
RD
1012 value[len-1] = '\0';
1013}
1014
9e730a78
RD
1015
1016void ListBoxImpl::RegisterImage(int type, const char *xpm_data) {
1017 wxMemoryInputStream stream(xpm_data, strlen(xpm_data)+1);
1018 wxBitmap bmp(wxImage(stream, wxBITMAP_TYPE_XPM));
1019
1020 if (! imgList) {
1021 // assumes all images are the same size
1022 imgList = new wxImageList(bmp.GetWidth(), bmp.GetHeight(), TRUE);
1023 imgTypeMap = new wxArrayInt;
1024 }
1025
1026 int idx = imgList->Add(bmp);
1027
1028 // do we need to extend the mapping array?
1029 wxArrayInt& itm = *imgTypeMap;
9a8ffadd 1030 if ( itm.GetCount() < (size_t)type+1)
9e730a78
RD
1031 itm.Add(-1, type - itm.GetCount() + 1);
1032
1033 // Add an item that maps type to the image index
1034 itm[type] = idx;
1035}
1036
1037void ListBoxImpl::ClearRegisteredImages() {
1038 if (imgList) {
1039 delete imgList;
1040 imgList = NULL;
1041 }
1042 if (imgTypeMap) {
1043 delete imgTypeMap;
1044 imgTypeMap = NULL;
1045 }
1046 if (id)
1047 GETLB(id)->SetImageList(NULL, wxIMAGE_LIST_SMALL);
1048}
1049
1050
1051void ListBoxImpl::SetDoubleClickAction(CallBackAction action, void *data) {
1052 GETLBW(id)->SetDoubleClickAction(action, data);
1053}
1054
1055
1056
1057ListBox::ListBox() {
1058}
1059
1060ListBox::~ListBox() {
1061}
1062
1063ListBox *ListBox::Allocate() {
1064 return new ListBoxImpl();
9ce192d4
RD
1065}
1066
1a2fb4cd 1067//----------------------------------------------------------------------
9ce192d4
RD
1068
1069Menu::Menu() : id(0) {
1070}
1071
1072void Menu::CreatePopUp() {
1073 Destroy();
1074 id = new wxMenu();
1075}
1076
1077void Menu::Destroy() {
1078 if (id)
1a2fb4cd 1079 delete (wxMenu*)id;
9ce192d4
RD
1080 id = 0;
1081}
1082
1083void Menu::Show(Point pt, Window &w) {
1a2fb4cd 1084 GETWIN(w.GetID())->PopupMenu((wxMenu*)id, pt.x - 4, pt.y);
9ce192d4
RD
1085 Destroy();
1086}
1087
1a2fb4cd 1088//----------------------------------------------------------------------
9ce192d4 1089
88a8b04e 1090DynamicLibrary *DynamicLibrary::Load(const char *WXUNUSED(modulePath)) {
e14d10b0
RD
1091 wxFAIL_MSG(wxT("Dynamic lexer loading not implemented yet"));
1092 return NULL;
1093}
1094
1095//----------------------------------------------------------------------
1096
1a2fb4cd 1097ColourDesired Platform::Chrome() {
9ce192d4 1098 wxColour c;
e1c6c6ae 1099 c = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
1a2fb4cd 1100 return ColourDesired(c.Red(), c.Green(), c.Blue());
9ce192d4
RD
1101}
1102
1a2fb4cd 1103ColourDesired Platform::ChromeHighlight() {
9ce192d4 1104 wxColour c;
e1c6c6ae 1105 c = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT);
1a2fb4cd 1106 return ColourDesired(c.Red(), c.Green(), c.Blue());
9ce192d4
RD
1107}
1108
1109const char *Platform::DefaultFont() {
10ef30eb
RD
1110 static char buf[128];
1111 strcpy(buf, wxNORMAL_FONT->GetFaceName().mbc_str());
1112 return buf;
9ce192d4
RD
1113}
1114
1115int Platform::DefaultFontSize() {
9e730a78 1116 return wxNORMAL_FONT->GetPointSize();
9ce192d4
RD
1117}
1118
1119unsigned int Platform::DoubleClickTime() {
1120 return 500; // **** ::GetDoubleClickTime();
1121}
1122
9e730a78
RD
1123bool Platform::MouseButtonBounce() {
1124 return FALSE;
1125}
9ce192d4 1126void Platform::DebugDisplay(const char *s) {
0c5b83b0 1127 wxLogDebug(stc2wx(s));
9ce192d4
RD
1128}
1129
88a8b04e 1130bool Platform::IsKeyDown(int WXUNUSED(key)) {
9ce192d4
RD
1131 return false; // I don't think we'll need this.
1132}
1133
1134long Platform::SendScintilla(WindowID w,
1135 unsigned int msg,
1136 unsigned long wParam,
1137 long lParam) {
1138
1139 wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w;
1140 return stc->SendMsg(msg, wParam, lParam);
1141}
1142
a834585d
RD
1143long Platform::SendScintillaPointer(WindowID w,
1144 unsigned int msg,
1145 unsigned long wParam,
1146 void *lParam) {
1147
1148 wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w;
1149 return stc->SendMsg(msg, wParam, (long)lParam);
1150}
1151
9ce192d4
RD
1152
1153// These are utility functions not really tied to a platform
1154
1155int Platform::Minimum(int a, int b) {
1156 if (a < b)
1157 return a;
1158 else
1159 return b;
1160}
1161
1162int Platform::Maximum(int a, int b) {
1163 if (a > b)
1164 return a;
1165 else
1166 return b;
1167}
1168
1169#define TRACE
1170
1171void Platform::DebugPrintf(const char *format, ...) {
1172#ifdef TRACE
1173 char buffer[2000];
1174 va_list pArguments;
1175 va_start(pArguments, format);
1176 vsprintf(buffer,format,pArguments);
1177 va_end(pArguments);
1178 Platform::DebugDisplay(buffer);
1179#endif
1180}
1181
65ec6247
RD
1182
1183static bool assertionPopUps = true;
1184
1185bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
1186 bool ret = assertionPopUps;
1187 assertionPopUps = assertionPopUps_;
1188 return ret;
1189}
1190
1191void Platform::Assert(const char *c, const char *file, int line) {
1192 char buffer[2000];
1193 sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
1194 if (assertionPopUps) {
0c5b83b0
RD
1195 /*int idButton = */
1196 wxMessageBox(stc2wx(buffer),
1197 wxT("Assertion failure"),
1198 wxICON_HAND | wxOK);
65ec6247
RD
1199// if (idButton == IDRETRY) {
1200// ::DebugBreak();
1201// } else if (idButton == IDIGNORE) {
1202// // all OK
1203// } else {
1204// abort();
1205// }
1206 } else {
1207 strcat(buffer, "\r\n");
1208 Platform::DebugDisplay(buffer);
1209 abort();
1210 }
1211}
1212
1213
9ce192d4
RD
1214int Platform::Clamp(int val, int minVal, int maxVal) {
1215 if (val > maxVal)
1216 val = maxVal;
1217 if (val < minVal)
1218 val = minVal;
1219 return val;
1220}
1221
1222
88a8b04e 1223bool Platform::IsDBCSLeadByte(int WXUNUSED(codePage), char WXUNUSED(ch)) {
1a2fb4cd
RD
1224 return false;
1225}
1226
88a8b04e 1227int Platform::DBCSCharLength(int WXUNUSED(codePage), const char *WXUNUSED(s)) {
215ef7ae 1228 return 1;
9e730a78
RD
1229}
1230
1231int Platform::DBCSCharMaxLength() {
215ef7ae 1232 return 1;
9e730a78 1233}
1a2fb4cd
RD
1234
1235
1236//----------------------------------------------------------------------
1237
1238ElapsedTime::ElapsedTime() {
1239 wxStartTimer();
1240}
1241
1242double ElapsedTime::Duration(bool reset) {
1243 double result = wxGetElapsedTime(reset);
1244 result /= 1000.0;
1245 return result;
1246}
1247
1248
1249//----------------------------------------------------------------------
9ce192d4 1250
d99859e4
RD
1251#if wxUSE_UNICODE
1252wxString stc2wx(const char* str, size_t len)
1253{
8a07b43c
RD
1254 if (str[len] == 0)
1255 // It's already terminated correctly.
1256 return wxString(str, wxConvUTF8, len);
1257
d99859e4
RD
1258 char *buffer=new char[len+1];
1259 strncpy(buffer, str, len);
1260 buffer[len]=0;
1261
4261ba88 1262 wxString cstr(buffer, wxConvUTF8, len);
d99859e4
RD
1263
1264 delete[] buffer;
1265 return cstr;
1266}
1267#endif
1268
1269
1270
9ce192d4
RD
1271
1272
1273