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