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