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