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