Oops, took out too much...
[wxWidgets.git] / src / stc / PlatWX.cpp
1 // Scintilla source code edit control
2 // PlatWX.cxx - implementation of platform facilities on wxWindows
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(cd.GetRed(), cd.GetGreen(), cd.GetBlue());
44 }
45
46 //----------------------------------------------------------------------
47
48 Palette::Palette() {
49 used = 0;
50 allowRealization = false;
51 }
52
53 Palette::~Palette() {
54 Release();
55 }
56
57 void 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.
64 void 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;
73 entries[used].allocated.Set(cp.desired.AsLong());
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 }
83 cp.allocated.Set(cp.desired.AsLong());
84 }
85 }
86
87 void Palette::Allocate(Window &) {
88 if (allowRealization) {
89 }
90 }
91
92
93 //----------------------------------------------------------------------
94
95 Font::Font() {
96 id = 0;
97 ascent = 0;
98 }
99
100 Font::~Font() {
101 }
102
103 void Font::Create(const char *faceName, int characterSet, int size, bool bold, bool italic, bool extraFontFlag) {
104 wxFontEncoding encoding;
105
106 Release();
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
184 wxFontEncodingArray ea = wxEncodingConverter::GetPlatformEquivalents(encoding);
185 if (ea.GetCount())
186 encoding = ea[0];
187
188 wxFont* font = new wxFont(size,
189 wxDEFAULT,
190 italic ? wxITALIC : wxNORMAL,
191 bold ? wxBOLD : wxNORMAL,
192 false,
193 stc2wx(faceName),
194 encoding);
195 font->SetNoAntiAliasing(!extraFontFlag);
196 id = font;
197 }
198
199
200 void Font::Release() {
201 if (id)
202 delete (wxFont*)id;
203 id = 0;
204 }
205
206 //----------------------------------------------------------------------
207
208 class SurfaceImpl : public Surface {
209 private:
210 wxDC* hdc;
211 bool hdcOwned;
212 wxBitmap* bitmap;
213 int x;
214 int y;
215 bool unicodeMode;
216
217 public:
218 SurfaceImpl();
219 ~SurfaceImpl();
220
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);
259
260 void BrushColour(ColourAllocated back);
261 void SetFont(Font &font_);
262 };
263
264
265
266 SurfaceImpl::SurfaceImpl() :
267 hdc(0), hdcOwned(0), bitmap(0),
268 x(0), y(0), unicodeMode(0)
269 {}
270
271 SurfaceImpl::~SurfaceImpl() {
272 Release();
273 }
274
275 void SurfaceImpl::Init(WindowID wid) {
276 #if 0
277 Release();
278 hdc = new wxMemoryDC();
279 hdcOwned = true;
280 #else
281 // On Mac and GTK the DC is not really valid until it has a bitmap
282 // selected into it. So instead of just creating the DC with no bitmap,
283 // go ahead and give it one.
284 InitPixMap(1,1,NULL,wid);
285 #endif
286 }
287
288 void SurfaceImpl::Init(SurfaceID hdc_, WindowID) {
289 Release();
290 hdc = (wxDC*)hdc_;
291 }
292
293 void SurfaceImpl::InitPixMap(int width, int height, Surface *WXUNUSED(surface_), WindowID) {
294 Release();
295 hdc = new wxMemoryDC();
296 hdcOwned = true;
297 if (width < 1) width = 1;
298 if (height < 1) height = 1;
299 bitmap = new wxBitmap(width, height);
300 ((wxMemoryDC*)hdc)->SelectObject(*bitmap);
301 }
302
303
304 void 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
318 bool SurfaceImpl::Initialised() {
319 return hdc != 0;
320 }
321
322
323 void SurfaceImpl::PenColour(ColourAllocated fore) {
324 hdc->SetPen(wxPen(wxColourFromCA(fore), 1, wxSOLID));
325 }
326
327 void SurfaceImpl::BrushColour(ColourAllocated back) {
328 hdc->SetBrush(wxBrush(wxColourFromCA(back), wxSOLID));
329 }
330
331 void SurfaceImpl::SetFont(Font &font_) {
332 if (font_.GetID()) {
333 hdc->SetFont(*((wxFont*)font_.GetID()));
334 }
335 }
336
337 int SurfaceImpl::LogPixelsY() {
338 return hdc->GetPPI().y;
339 }
340
341 int SurfaceImpl::DeviceHeightFont(int points) {
342 return points;
343 }
344
345 void SurfaceImpl::MoveTo(int x_, int y_) {
346 x = x_;
347 y = y_;
348 }
349
350 void SurfaceImpl::LineTo(int x_, int y_) {
351 hdc->DrawLine(x,y, x_,y_);
352 x = x_;
353 y = y_;
354 }
355
356 void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) {
357 PenColour(fore);
358 BrushColour(back);
359 hdc->DrawPolygon(npts, (wxPoint*)pts);
360 }
361
362 void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
363 PenColour(fore);
364 BrushColour(back);
365 hdc->DrawRectangle(wxRectFromPRectangle(rc));
366 }
367
368 void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
369 BrushColour(back);
370 hdc->SetPen(*wxTRANSPARENT_PEN);
371 hdc->DrawRectangle(wxRectFromPRectangle(rc));
372 }
373
374 void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
375 wxBrush br;
376 if (((SurfaceImpl&)surfacePattern).bitmap)
377 br = wxBrush(*((SurfaceImpl&)surfacePattern).bitmap);
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
385 void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
386 PenColour(fore);
387 BrushColour(back);
388 hdc->DrawRoundedRectangle(wxRectFromPRectangle(rc), 4);
389 }
390
391 void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
392 PenColour(fore);
393 BrushColour(back);
394 hdc->DrawEllipse(wxRectFromPRectangle(rc));
395 }
396
397 void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
398 wxRect r = wxRectFromPRectangle(rc);
399 hdc->Blit(r.x, r.y, r.width, r.height,
400 ((SurfaceImpl&)surfaceSource).hdc,
401 from.x, from.y, wxCOPY);
402 }
403
404 void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font, int ybase,
405 const char *s, int len,
406 ColourAllocated fore, ColourAllocated back) {
407 SetFont(font);
408 hdc->SetTextForeground(wxColourFromCA(fore));
409 hdc->SetTextBackground(wxColourFromCA(back));
410 FillRectangle(rc, back);
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...
414 hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
415 }
416
417 void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font, int ybase,
418 const char *s, int len,
419 ColourAllocated fore, ColourAllocated back) {
420 SetFont(font);
421 hdc->SetTextForeground(wxColourFromCA(fore));
422 hdc->SetTextBackground(wxColourFromCA(back));
423 FillRectangle(rc, back);
424 hdc->SetClippingRegion(wxRectFromPRectangle(rc));
425
426 // see comments above
427 hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
428 hdc->DestroyClippingRegion();
429 }
430
431
432 void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font, int ybase,
433 const char *s, int len,
434 ColourAllocated fore) {
435
436 SetFont(font);
437 hdc->SetTextForeground(wxColourFromCA(fore));
438 hdc->SetBackgroundMode(wxTRANSPARENT);
439
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...
442 hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
443
444 hdc->SetBackgroundMode(wxSOLID);
445 }
446
447
448 void SurfaceImpl::MeasureWidths(Font &font, const char *s, int len, int *positions) {
449
450 wxString str = stc2wx(s, len);
451 wxArrayInt tpos;
452
453 SetFont(font);
454
455 hdc->GetPartialTextExtents(str, tpos);
456
457 #if wxUSE_UNICODE
458 // Map the widths for UCS-2 characters back to the UTF-8 input string
459 // NOTE: I don't think this is right for when sizeof(wxChar) > 2, ie wxGTK2
460 // so figure it out and fix it!
461 size_t i = 0;
462 size_t ui = 0;
463 while ((int)i < len) {
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
479 memcpy(positions, tpos.begin(), len * sizeof(int));
480 #endif
481 }
482
483
484 int 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
494 int SurfaceImpl::WidthChar(Font &font, char ch) {
495 SetFont(font);
496 int w;
497 int h;
498 char s[2] = { ch, 0 };
499
500 hdc->GetTextExtent(stc2wx(s, 1), &w, &h);
501 return w;
502 }
503
504 #define EXTENT_TEST wxT(" `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
505
506 int SurfaceImpl::Ascent(Font &font) {
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
514 int SurfaceImpl::Descent(Font &font) {
515 SetFont(font);
516 int w, h, d, e;
517 hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
518 return d;
519 }
520
521 int SurfaceImpl::InternalLeading(Font &WXUNUSED(font)) {
522 return 0;
523 }
524
525 int SurfaceImpl::ExternalLeading(Font &font) {
526 SetFont(font);
527 int w, h, d, e;
528 hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
529 return e;
530 }
531
532 int SurfaceImpl::Height(Font &font) {
533 SetFont(font);
534 return hdc->GetCharHeight() + 1;
535 }
536
537 int SurfaceImpl::AverageCharWidth(Font &font) {
538 SetFont(font);
539 return hdc->GetCharWidth();
540 }
541
542 int SurfaceImpl::SetPalette(Palette *WXUNUSED(pal), bool WXUNUSED(inBackGround)) {
543 return 0;
544 }
545
546 void SurfaceImpl::SetClip(PRectangle rc) {
547 hdc->SetClippingRegion(wxRectFromPRectangle(rc));
548 }
549
550 void SurfaceImpl::FlushCachedState() {
551 }
552
553 void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
554 unicodeMode=unicodeMode_;
555 }
556
557 void SurfaceImpl::SetDBCSMode(int WXUNUSED(codePage)) {
558 // dbcsMode = codePage == SC_CP_DBCS;
559 }
560
561
562 Surface *Surface::Allocate() {
563 return new SurfaceImpl;
564 }
565
566
567 //----------------------------------------------------------------------
568
569
570 inline wxWindow* GETWIN(WindowID id) { return (wxWindow*)id; }
571
572 Window::~Window() {
573 }
574
575 void Window::Destroy() {
576 if (id) {
577 Show(FALSE);
578 GETWIN(id)->Destroy();
579 }
580 id = 0;
581 }
582
583 bool Window::HasFocus() {
584 return wxWindow::FindFocus() == GETWIN(id);
585 }
586
587 PRectangle Window::GetPosition() {
588 if (! id) return PRectangle();
589 wxRect rc(GETWIN(id)->GetPosition(), GETWIN(id)->GetSize());
590 return PRectangleFromwxRect(rc);
591 }
592
593 void Window::SetPosition(PRectangle rc) {
594 wxRect r = wxRectFromPRectangle(rc);
595 GETWIN(id)->SetSize(r);
596 }
597
598 void Window::SetPositionRelative(PRectangle rc, Window) {
599 SetPosition(rc); // ????
600 }
601
602 PRectangle Window::GetClientPosition() {
603 if (! id) return PRectangle();
604 wxSize sz = GETWIN(id)->GetClientSize();
605 return PRectangle(0, 0, sz.x, sz.y);
606 }
607
608 void Window::Show(bool show) {
609 GETWIN(id)->Show(show);
610 }
611
612 void Window::InvalidateAll() {
613 GETWIN(id)->Refresh(false);
614 wxWakeUpIdle();
615 }
616
617 void Window::InvalidateRectangle(PRectangle rc) {
618 wxRect r = wxRectFromPRectangle(rc);
619 GETWIN(id)->Refresh(false, &r);
620 wxWakeUpIdle();
621 }
622
623 void Window::SetFont(Font &font) {
624 GETWIN(id)->SetFont(*((wxFont*)font.GetID()));
625 }
626
627 void 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:
650 cursorId = wxCURSOR_RIGHT_ARROW;
651 break;
652 case cursorHand:
653 cursorId = wxCURSOR_HAND;
654 break;
655 default:
656 cursorId = wxCURSOR_ARROW;
657 break;
658 }
659 #ifdef __WXMOTIF__
660 wxCursor wc = wxStockCursor(cursorId) ;
661 #else
662 wxCursor wc = wxCursor(cursorId) ;
663 #endif
664 GETWIN(id)->SetCursor(wc);
665 }
666
667
668 void Window::SetTitle(const char *s) {
669 GETWIN(id)->SetTitle(stc2wx(s));
670 }
671
672
673 //----------------------------------------------------------------------
674 // Helper classes for ListBox
675
676
677 // This is a simple subclass of wxListView that just resets focus to the
678 // parent when it gets it.
679 class wxSTCListBox : public wxListView {
680 public:
681 wxSTCListBox(wxWindow* parent, wxWindowID id,
682 const wxPoint& pos, const wxSize& size,
683 long style)
684 : wxListView(parent, id, pos, size, style)
685 {}
686
687 void OnFocus(wxFocusEvent& event) {
688 GetParent()->SetFocus();
689 event.Skip();
690 }
691
692 void OnKillFocus(wxFocusEvent& WXUNUSED(event)) {
693 // Do nothing. Prevents base class from resetting the colors...
694 }
695
696 private:
697 DECLARE_EVENT_TABLE()
698 };
699
700 BEGIN_EVENT_TABLE(wxSTCListBox, wxListView)
701 EVT_SET_FOCUS( wxSTCListBox::OnFocus)
702 EVT_KILL_FOCUS(wxSTCListBox::OnKillFocus)
703 END_EVENT_TABLE()
704
705
706
707
708 // A window to place the wxSTCListBox upon
709 class wxSTCListBoxWin : public wxWindow {
710 private:
711 wxListView* lv;
712 CallBackAction doubleClickAction;
713 void* doubleClickActionData;
714 public:
715 wxSTCListBoxWin(wxWindow* parent, wxWindowID id) :
716 wxWindow(parent, id, wxDefaultPosition, wxSize(0,0), wxSIMPLE_BORDER )
717 {
718
719 lv = new wxSTCListBox(this, id, wxDefaultPosition, wxDefaultSize,
720 wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxNO_BORDER);
721 lv->SetCursor(wxCursor(wxCURSOR_ARROW));
722 lv->InsertColumn(0, wxEmptyString);
723 lv->InsertColumn(1, wxEmptyString);
724
725 // Eventhough we immediately reset the focus to the parent, this helps
726 // things to look right...
727 lv->SetFocus();
728
729 Hide();
730 }
731
732
733 // On OSX and (possibly others) there can still be pending
734 // messages/events for the list control when Scintilla wants to
735 // close it, so do a pending delete of it instead of destroying
736 // immediately.
737 bool Destroy() {
738 #ifdef __WXMAC__
739 // There bottom edge of this window is not getting properly
740 // refreshed upon deletion, so help it out...
741 wxWindow* p = GetParent();
742 wxRect r(GetPosition(), GetSize());
743 r.SetHeight(r.GetHeight()+1);
744 p->Refresh(false, &r);
745 #endif
746 if ( !wxPendingDelete.Member(this) )
747 wxPendingDelete.Append(this);
748 return TRUE;
749 }
750
751
752 int IconWidth() {
753 wxImageList* il = lv->GetImageList(wxIMAGE_LIST_SMALL);
754 if (il != NULL) {
755 int w, h;
756 il->GetSize(0, w, h);
757 return w;
758 }
759 return 0;
760 }
761
762
763 void SetDoubleClickAction(CallBackAction action, void *data) {
764 doubleClickAction = action;
765 doubleClickActionData = data;
766 }
767
768
769 void OnFocus(wxFocusEvent& event) {
770 GetParent()->SetFocus();
771 event.Skip();
772 }
773
774 void OnSize(wxSizeEvent& event) {
775 // resize the child
776 wxSize sz = GetClientSize();
777 lv->SetSize(sz);
778 // reset the column widths
779 lv->SetColumnWidth(0, IconWidth()+4);
780 lv->SetColumnWidth(1, sz.x - 2 - lv->GetColumnWidth(0) -
781 wxSystemSettings::GetMetric(wxSYS_VSCROLL_X));
782 event.Skip();
783 }
784
785 void OnActivate(wxListEvent& WXUNUSED(event)) {
786 doubleClickAction(doubleClickActionData);
787 }
788
789 wxListView* GetLB() { return lv; }
790
791 private:
792 DECLARE_EVENT_TABLE()
793 };
794
795
796 BEGIN_EVENT_TABLE(wxSTCListBoxWin, wxWindow)
797 EVT_SET_FOCUS ( wxSTCListBoxWin::OnFocus)
798 EVT_SIZE ( wxSTCListBoxWin::OnSize)
799 EVT_LIST_ITEM_ACTIVATED(-1, wxSTCListBoxWin::OnActivate)
800 END_EVENT_TABLE()
801
802
803
804 inline wxSTCListBoxWin* GETLBW(WindowID win) {
805 return ((wxSTCListBoxWin*)win);
806 }
807
808 inline wxListView* GETLB(WindowID win) {
809 return GETLBW(win)->GetLB();
810 }
811
812 //----------------------------------------------------------------------
813
814 class ListBoxImpl : public ListBox {
815 private:
816 int lineHeight;
817 bool unicodeMode;
818 int desiredVisibleRows;
819 int aveCharWidth;
820 int maxStrWidth;
821 wxImageList* imgList;
822 wxArrayInt* imgTypeMap;
823
824 public:
825 ListBoxImpl();
826 ~ListBoxImpl();
827
828 virtual void SetFont(Font &font);
829 virtual void Create(Window &parent, int ctrlID, int lineHeight_, bool unicodeMode_);
830 virtual void SetAverageCharWidth(int width);
831 virtual void SetVisibleRows(int rows);
832 virtual PRectangle GetDesiredRect();
833 virtual int CaretFromEdge();
834 virtual void Clear();
835 virtual void Append(char *s, int type = -1);
836 virtual int Length();
837 virtual void Select(int n);
838 virtual int GetSelection();
839 virtual int Find(const char *prefix);
840 virtual void GetValue(int n, char *value, int len);
841 virtual void RegisterImage(int type, const char *xpm_data);
842 virtual void ClearRegisteredImages();
843 virtual void SetDoubleClickAction(CallBackAction, void *);
844
845 };
846
847
848 ListBoxImpl::ListBoxImpl()
849 : lineHeight(10), unicodeMode(false),
850 desiredVisibleRows(5), aveCharWidth(8), maxStrWidth(0),
851 imgList(NULL), imgTypeMap(NULL)
852 {
853 }
854
855 ListBoxImpl::~ListBoxImpl() {
856 if (imgList) {
857 delete imgList;
858 imgList = NULL;
859 }
860 if (imgTypeMap) {
861 delete imgTypeMap;
862 imgTypeMap = NULL;
863 }
864 }
865
866
867 void ListBoxImpl::SetFont(Font &font) {
868 GETLB(id)->SetFont(*((wxFont*)font.GetID()));
869 }
870
871
872 void ListBoxImpl::Create(Window &parent, int ctrlID, int lineHeight_, bool unicodeMode_) {
873 lineHeight = lineHeight_;
874 unicodeMode = unicodeMode_;
875 maxStrWidth = 0;
876 id = new wxSTCListBoxWin(GETWIN(parent.GetID()), ctrlID);
877 if (imgList != NULL)
878 GETLB(id)->SetImageList(imgList, wxIMAGE_LIST_SMALL);
879 }
880
881
882 void ListBoxImpl::SetAverageCharWidth(int width) {
883 aveCharWidth = width;
884 }
885
886
887 void ListBoxImpl::SetVisibleRows(int rows) {
888 desiredVisibleRows = rows;
889 }
890
891
892 PRectangle ListBoxImpl::GetDesiredRect() {
893 // wxListCtrl doesn't have a DoGetBestSize, so instead we kept track of
894 // the max size in Append and calculate it here...
895 int maxw = maxStrWidth;
896 int maxh ;
897
898 // give it a default if there are no lines, and/or add a bit more
899 if (maxw == 0) maxw = 100;
900 maxw += aveCharWidth * 3 +
901 GETLBW(id)->IconWidth() + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
902 if (maxw > 350)
903 maxw = 350;
904
905 // estimate a desired height
906 int count = GETLB(id)->GetItemCount();
907 if (count) {
908 wxRect rect;
909 GETLB(id)->GetItemRect(0, rect);
910 maxh = count * rect.GetHeight();
911 if (maxh > 140) // TODO: Use desiredVisibleRows??
912 maxh = 140;
913
914 // Try to make the size an exact multiple of some number of lines
915 int lines = maxh / rect.GetHeight();
916 maxh = (lines + 1) * rect.GetHeight() + 2;
917 }
918 else
919 maxh = 100;
920
921 PRectangle rc;
922 rc.top = 0;
923 rc.left = 0;
924 rc.right = maxw;
925 rc.bottom = maxh;
926 return rc;
927 }
928
929
930 int ListBoxImpl::CaretFromEdge() {
931 return 4 + GETLBW(id)->IconWidth();
932 }
933
934
935 void ListBoxImpl::Clear() {
936 GETLB(id)->DeleteAllItems();
937 }
938
939
940 void ListBoxImpl::Append(char *s, int type) {
941 wxString text = stc2wx(s);
942 long count = GETLB(id)->GetItemCount();
943 long itemID = GETLB(id)->InsertItem(count, wxEmptyString);
944 GETLB(id)->SetItem(itemID, 1, text);
945 int itemWidth = 0;
946 GETLB(id)->GetTextExtent(text, &itemWidth, NULL);
947 maxStrWidth = wxMax(maxStrWidth, itemWidth);
948 if (type != -1) {
949 wxCHECK_RET(imgTypeMap, wxT("Unexpected NULL imgTypeMap"));
950 long idx = imgTypeMap->Item(type);
951 GETLB(id)->SetItemImage(itemID, idx, idx);
952 }
953 }
954
955
956 int ListBoxImpl::Length() {
957 return GETLB(id)->GetItemCount();
958 }
959
960
961 void ListBoxImpl::Select(int n) {
962 bool select = TRUE;
963 if (n == -1) {
964 n = 0;
965 select = FALSE;
966 }
967 GETLB(id)->Focus(n);
968 GETLB(id)->Select(n, select);
969 }
970
971
972 int ListBoxImpl::GetSelection() {
973 return GETLB(id)->GetFirstSelected();
974 }
975
976
977 int ListBoxImpl::Find(const char *WXUNUSED(prefix)) {
978 // No longer used
979 return -1;
980 }
981
982
983 void ListBoxImpl::GetValue(int n, char *value, int len) {
984 wxListItem item;
985 item.SetId(n);
986 item.SetColumn(1);
987 item.SetMask(wxLIST_MASK_TEXT);
988 GETLB(id)->GetItem(item);
989 strncpy(value, wx2stc(item.GetText()), len);
990 value[len-1] = '\0';
991 }
992
993
994 void ListBoxImpl::RegisterImage(int type, const char *xpm_data) {
995 wxMemoryInputStream stream(xpm_data, strlen(xpm_data)+1);
996 wxBitmap bmp(wxImage(stream, wxBITMAP_TYPE_XPM));
997
998 if (! imgList) {
999 // assumes all images are the same size
1000 imgList = new wxImageList(bmp.GetWidth(), bmp.GetHeight(), TRUE);
1001 imgTypeMap = new wxArrayInt;
1002 }
1003
1004 int idx = imgList->Add(bmp);
1005
1006 // do we need to extend the mapping array?
1007 wxArrayInt& itm = *imgTypeMap;
1008 if ( itm.GetCount() < (size_t)type+1)
1009 itm.Add(-1, type - itm.GetCount() + 1);
1010
1011 // Add an item that maps type to the image index
1012 itm[type] = idx;
1013 }
1014
1015 void ListBoxImpl::ClearRegisteredImages() {
1016 if (imgList) {
1017 delete imgList;
1018 imgList = NULL;
1019 }
1020 if (imgTypeMap) {
1021 delete imgTypeMap;
1022 imgTypeMap = NULL;
1023 }
1024 if (id)
1025 GETLB(id)->SetImageList(NULL, wxIMAGE_LIST_SMALL);
1026 }
1027
1028
1029 void ListBoxImpl::SetDoubleClickAction(CallBackAction action, void *data) {
1030 GETLBW(id)->SetDoubleClickAction(action, data);
1031 }
1032
1033
1034
1035 ListBox::ListBox() {
1036 }
1037
1038 ListBox::~ListBox() {
1039 }
1040
1041 ListBox *ListBox::Allocate() {
1042 return new ListBoxImpl();
1043 }
1044
1045 //----------------------------------------------------------------------
1046
1047 Menu::Menu() : id(0) {
1048 }
1049
1050 void Menu::CreatePopUp() {
1051 Destroy();
1052 id = new wxMenu();
1053 }
1054
1055 void Menu::Destroy() {
1056 if (id)
1057 delete (wxMenu*)id;
1058 id = 0;
1059 }
1060
1061 void Menu::Show(Point pt, Window &w) {
1062 GETWIN(w.GetID())->PopupMenu((wxMenu*)id, pt.x - 4, pt.y);
1063 Destroy();
1064 }
1065
1066 //----------------------------------------------------------------------
1067
1068 DynamicLibrary *DynamicLibrary::Load(const char *WXUNUSED(modulePath)) {
1069 wxFAIL_MSG(wxT("Dynamic lexer loading not implemented yet"));
1070 return NULL;
1071 }
1072
1073 //----------------------------------------------------------------------
1074
1075 ColourDesired Platform::Chrome() {
1076 wxColour c;
1077 c = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
1078 return ColourDesired(c.Red(), c.Green(), c.Blue());
1079 }
1080
1081 ColourDesired Platform::ChromeHighlight() {
1082 wxColour c;
1083 c = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT);
1084 return ColourDesired(c.Red(), c.Green(), c.Blue());
1085 }
1086
1087 const char *Platform::DefaultFont() {
1088 static char buf[128];
1089 strcpy(buf, wxNORMAL_FONT->GetFaceName().mbc_str());
1090 return buf;
1091 }
1092
1093 int Platform::DefaultFontSize() {
1094 return wxNORMAL_FONT->GetPointSize();
1095 }
1096
1097 unsigned int Platform::DoubleClickTime() {
1098 return 500; // **** ::GetDoubleClickTime();
1099 }
1100
1101 bool Platform::MouseButtonBounce() {
1102 return FALSE;
1103 }
1104 void Platform::DebugDisplay(const char *s) {
1105 wxLogDebug(stc2wx(s));
1106 }
1107
1108 bool Platform::IsKeyDown(int WXUNUSED(key)) {
1109 return false; // I don't think we'll need this.
1110 }
1111
1112 long Platform::SendScintilla(WindowID w,
1113 unsigned int msg,
1114 unsigned long wParam,
1115 long lParam) {
1116
1117 wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w;
1118 return stc->SendMsg(msg, wParam, lParam);
1119 }
1120
1121 long Platform::SendScintillaPointer(WindowID w,
1122 unsigned int msg,
1123 unsigned long wParam,
1124 void *lParam) {
1125
1126 wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w;
1127 return stc->SendMsg(msg, wParam, (long)lParam);
1128 }
1129
1130
1131 // These are utility functions not really tied to a platform
1132
1133 int Platform::Minimum(int a, int b) {
1134 if (a < b)
1135 return a;
1136 else
1137 return b;
1138 }
1139
1140 int Platform::Maximum(int a, int b) {
1141 if (a > b)
1142 return a;
1143 else
1144 return b;
1145 }
1146
1147 #define TRACE
1148
1149 void Platform::DebugPrintf(const char *format, ...) {
1150 #ifdef TRACE
1151 char buffer[2000];
1152 va_list pArguments;
1153 va_start(pArguments, format);
1154 vsprintf(buffer,format,pArguments);
1155 va_end(pArguments);
1156 Platform::DebugDisplay(buffer);
1157 #endif
1158 }
1159
1160
1161 static bool assertionPopUps = true;
1162
1163 bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
1164 bool ret = assertionPopUps;
1165 assertionPopUps = assertionPopUps_;
1166 return ret;
1167 }
1168
1169 void Platform::Assert(const char *c, const char *file, int line) {
1170 char buffer[2000];
1171 sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
1172 if (assertionPopUps) {
1173 /*int idButton = */
1174 wxMessageBox(stc2wx(buffer),
1175 wxT("Assertion failure"),
1176 wxICON_HAND | wxOK);
1177 // if (idButton == IDRETRY) {
1178 // ::DebugBreak();
1179 // } else if (idButton == IDIGNORE) {
1180 // // all OK
1181 // } else {
1182 // abort();
1183 // }
1184 } else {
1185 strcat(buffer, "\r\n");
1186 Platform::DebugDisplay(buffer);
1187 abort();
1188 }
1189 }
1190
1191
1192 int Platform::Clamp(int val, int minVal, int maxVal) {
1193 if (val > maxVal)
1194 val = maxVal;
1195 if (val < minVal)
1196 val = minVal;
1197 return val;
1198 }
1199
1200
1201 bool Platform::IsDBCSLeadByte(int WXUNUSED(codePage), char WXUNUSED(ch)) {
1202 return false;
1203 }
1204
1205 int Platform::DBCSCharLength(int WXUNUSED(codePage), const char *WXUNUSED(s)) {
1206 return 1;
1207 }
1208
1209 int Platform::DBCSCharMaxLength() {
1210 return 1;
1211 }
1212
1213
1214 //----------------------------------------------------------------------
1215
1216 ElapsedTime::ElapsedTime() {
1217 wxStartTimer();
1218 }
1219
1220 double ElapsedTime::Duration(bool reset) {
1221 double result = wxGetElapsedTime(reset);
1222 result /= 1000.0;
1223 return result;
1224 }
1225
1226
1227 //----------------------------------------------------------------------
1228
1229 #if wxUSE_UNICODE
1230 wxString stc2wx(const char* str, size_t len)
1231 {
1232 char *buffer=new char[len+1];
1233 strncpy(buffer, str, len);
1234 buffer[len]=0;
1235
1236 wxString cstr(buffer, wxConvUTF8);
1237
1238 delete[] buffer;
1239 return cstr;
1240 }
1241 #endif
1242
1243
1244
1245
1246
1247