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