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