]> git.saurik.com Git - wxWidgets.git/blobdiff - src/stc/PlatWX.cpp
added line selection
[wxWidgets.git] / src / stc / PlatWX.cpp
index 0dbd3d5ea77e501b7d9ee4a5481c92d49667f4e0..ec41de273331d17a729f4bf07f449eb00325bfa8 100644 (file)
@@ -4,53 +4,46 @@
 //                        Robin Dunn <robin@aldunn.com>
 // The License.txt file describes the conditions under which this software may be distributed.
 
+#include <ctype.h>
+
+#include <wx/wx.h>
+#include <wx/encconv.h>
+#include <wx/listctrl.h>
+#include <wx/mstream.h>
+#include <wx/image.h>
+#include <wx/imaglist.h>
 
 #include "Platform.h"
+#include "PlatWX.h"
 #include "wx/stc/stc.h"
 
+
+#ifdef __WXGTK__
+#include <gtk/gtk.h>
+#endif
+
+
 Point Point::FromLong(long lpoint) {
-    return Point(lpoint & 0xFFFF, lpoint >> 32);
+    return Point(lpoint & 0xFFFF, lpoint >> 16);
 }
 
 wxRect wxRectFromPRectangle(PRectangle prc) {
     wxRect rc(prc.left, prc.top,
-              prc.right-prc.left+1, prc.bottom-prc.top+1);
+              prc.right-prc.left, prc.bottom-prc.top);
     return rc;
 }
 
 PRectangle PRectangleFromwxRect(wxRect rc) {
-    return PRectangle(rc.GetLeft(), rc.GetTop(), rc.GetRight(), rc.GetBottom());
-}
-
-Colour::Colour(long lcol) {
-    co.Set(lcol & 0xff, (lcol >> 8) & 0xff, (lcol >> 16) & 0xff);
-}
-
-Colour::Colour(unsigned int red, unsigned int green, unsigned int blue) {
-    co.Set(red, green, blue);
-}
-
-bool Colour::operator==(const Colour &other) const {
-    return co == other.co;
-}
-
-long Colour::AsLong() const {
-    return (((long)co.Blue()  << 16) |
-            ((long)co.Green() <<  8) |
-            ((long)co.Red()));
-}
-
-unsigned int Colour::GetRed() {
-    return co.Red();
+    return PRectangle(rc.GetLeft(), rc.GetTop(),
+                      rc.GetRight()+1, rc.GetBottom()+1);
 }
 
-unsigned int Colour::GetGreen() {
-    return co.Green();
+wxColour wxColourFromCA(const ColourAllocated& ca) {
+    ColourDesired cd(ca.AsLong());
+    return wxColour(cd.GetRed(), cd.GetGreen(), cd.GetBlue());
 }
 
-unsigned int Colour::GetBlue() {
-    return co.Blue();
-}
+//----------------------------------------------------------------------
 
 Palette::Palette() {
     used = 0;
@@ -77,7 +70,7 @@ void Palette::WantFind(ColourPair &cp, bool want) {
 
         if (used < numEntries) {
             entries[used].desired = cp.desired;
-            entries[used].allocated = cp.desired;
+            entries[used].allocated.Set(cp.desired.AsLong());
             used++;
         }
     } else {
@@ -87,7 +80,7 @@ void Palette::WantFind(ColourPair &cp, bool want) {
                 return;
             }
         }
-        cp.allocated = cp.desired;
+        cp.allocated.Set(cp.desired.AsLong());
     }
 }
 
@@ -97,6 +90,8 @@ void Palette::Allocate(Window &) {
 }
 
 
+//----------------------------------------------------------------------
+
 Font::Font() {
     id = 0;
     ascent = 0;
@@ -105,34 +100,206 @@ Font::Font() {
 Font::~Font() {
 }
 
-void Font::Create(const char *faceName, int size, bool bold, bool italic) {
+void Font::Create(const char *faceName, int characterSet, int size, bool bold, bool italic) {
+    wxFontEncoding encoding;
+
     Release();
+
+    switch (characterSet) {
+        default:
+        case wxSTC_CHARSET_ANSI:
+        case wxSTC_CHARSET_DEFAULT:
+            encoding = wxFONTENCODING_DEFAULT;
+            break;
+
+        case wxSTC_CHARSET_BALTIC:
+            encoding = wxFONTENCODING_ISO8859_13;
+            break;
+
+        case wxSTC_CHARSET_CHINESEBIG5:
+            encoding = wxFONTENCODING_CP950;
+            break;
+
+        case wxSTC_CHARSET_EASTEUROPE:
+            encoding = wxFONTENCODING_ISO8859_2;
+            break;
+
+        case wxSTC_CHARSET_GB2312:
+            encoding = wxFONTENCODING_CP936;
+            break;
+
+        case wxSTC_CHARSET_GREEK:
+            encoding = wxFONTENCODING_ISO8859_7;
+            break;
+
+        case wxSTC_CHARSET_HANGUL:
+            encoding = wxFONTENCODING_CP949;
+            break;
+
+        case wxSTC_CHARSET_MAC:
+            encoding = wxFONTENCODING_DEFAULT;
+            break;
+
+        case wxSTC_CHARSET_OEM:
+            encoding = wxFONTENCODING_DEFAULT;
+            break;
+
+        case wxSTC_CHARSET_RUSSIAN:
+            encoding = wxFONTENCODING_KOI8;
+            break;
+
+        case wxSTC_CHARSET_SHIFTJIS:
+            encoding = wxFONTENCODING_CP932;
+            break;
+
+        case wxSTC_CHARSET_SYMBOL:
+            encoding = wxFONTENCODING_DEFAULT;
+            break;
+
+        case wxSTC_CHARSET_TURKISH:
+            encoding = wxFONTENCODING_ISO8859_9;
+            break;
+
+        case wxSTC_CHARSET_JOHAB:
+            encoding = wxFONTENCODING_DEFAULT;
+            break;
+
+        case wxSTC_CHARSET_HEBREW:
+            encoding = wxFONTENCODING_ISO8859_8;
+            break;
+
+        case wxSTC_CHARSET_ARABIC:
+            encoding = wxFONTENCODING_ISO8859_6;
+            break;
+
+        case wxSTC_CHARSET_VIETNAMESE:
+            encoding = wxFONTENCODING_DEFAULT;
+            break;
+
+        case wxSTC_CHARSET_THAI:
+            encoding = wxFONTENCODING_ISO8859_11;
+            break;
+    }
+
+    wxFontEncodingArray ea = wxEncodingConverter::GetPlatformEquivalents(encoding);
+    if (ea.GetCount())
+        encoding = ea[0];
+
     id = new wxFont(size,
                     wxDEFAULT,
                     italic ? wxITALIC :  wxNORMAL,
                     bold ? wxBOLD : wxNORMAL,
                     false,
-                    faceName);
+                    stc2wx(faceName),
+                    encoding);
 }
 
 
 void Font::Release() {
     if (id)
-        delete id;
+        delete (wxFont*)id;
     id = 0;
 }
 
-
-Surface::Surface() :
+//----------------------------------------------------------------------
+
+class SurfaceImpl : public Surface {
+private:
+    wxDC*       hdc;
+    bool        hdcOwned;
+    wxBitmap*   bitmap;
+    int         x;
+    int         y;
+    bool        unicodeMode;
+
+public:
+    SurfaceImpl();
+    ~SurfaceImpl();
+
+    virtual void Init(WindowID wid);
+    virtual void Init(SurfaceID sid, WindowID wid);
+    virtual void InitPixMap(int width, int height, Surface *surface_, WindowID wid);
+
+    virtual void Release();
+    virtual bool Initialised();
+    virtual void PenColour(ColourAllocated fore);
+    virtual int LogPixelsY();
+    virtual int DeviceHeightFont(int points);
+    virtual void MoveTo(int x_, int y_);
+    virtual void LineTo(int x_, int y_);
+    virtual void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back);
+    virtual void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back);
+    virtual void FillRectangle(PRectangle rc, ColourAllocated back);
+    virtual void FillRectangle(PRectangle rc, Surface &surfacePattern);
+    virtual void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back);
+    virtual void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);
+    virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource);
+
+    virtual void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
+    virtual void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
+    virtual void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
+    virtual void MeasureWidths(Font &font_, const char *s, int len, int *positions);
+    virtual int WidthText(Font &font_, const char *s, int len);
+    virtual int WidthChar(Font &font_, char ch);
+    virtual int Ascent(Font &font_);
+    virtual int Descent(Font &font_);
+    virtual int InternalLeading(Font &font_);
+    virtual int ExternalLeading(Font &font_);
+    virtual int Height(Font &font_);
+    virtual int AverageCharWidth(Font &font_);
+
+    virtual int SetPalette(Palette *pal, bool inBackGround);
+    virtual void SetClip(PRectangle rc);
+    virtual void FlushCachedState();
+
+    virtual void SetUnicodeMode(bool unicodeMode_);
+    virtual void SetDBCSMode(int codePage);
+
+    void BrushColour(ColourAllocated back);
+    void SetFont(Font &font_);
+};
+
+
+
+SurfaceImpl::SurfaceImpl() :
     hdc(0), hdcOwned(0), bitmap(0),
-    x(0), y(0) {
+    x(0), y(0), unicodeMode(0)
+{}
+
+SurfaceImpl::~SurfaceImpl() {
+    Release();
+}
+
+void SurfaceImpl::Init(WindowID wid) {
+#if 0
+    Release();
+    hdc = new wxMemoryDC();
+    hdcOwned = true;
+#else
+    // On Mac and GTK the DC is not really valid until it has a bitmap
+    // selected into it.  So instead of just creating the DC with no bitmap,
+    // go ahead and give it one.
+    InitPixMap(1,1,NULL,wid);
+#endif
 }
 
-Surface::~Surface() {
+void SurfaceImpl::Init(SurfaceID hdc_, WindowID) {
     Release();
+    hdc = (wxDC*)hdc_;
 }
 
-void Surface::Release() {
+void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) {
+    Release();
+    hdc = new wxMemoryDC();
+    hdcOwned = true;
+    if (width < 1) width = 1;
+    if (height < 1) height = 1;
+    bitmap = new wxBitmap(width, height);
+    ((wxMemoryDC*)hdc)->SelectObject(*bitmap);
+}
+
+
+void SurfaceImpl::Release() {
     if (bitmap) {
         ((wxMemoryDC*)hdc)->SelectObject(wxNullBitmap);
         delete bitmap;
@@ -146,82 +313,66 @@ void Surface::Release() {
 }
 
 
-bool Surface::Initialised() {
+bool SurfaceImpl::Initialised() {
     return hdc != 0;
 }
 
-void Surface::Init() {
-    Release();
-    hdc = new wxMemoryDC();
-    hdcOwned = true;
-    // **** ::SetTextAlign(hdc, TA_BASELINE);
-}
 
-void Surface::Init(SurfaceID hdc_) {
-    Release();
-    hdc = hdc_;
-    // **** ::SetTextAlign(hdc, TA_BASELINE);
+void SurfaceImpl::PenColour(ColourAllocated fore) {
+    hdc->SetPen(wxPen(wxColourFromCA(fore), 1, wxSOLID));
 }
 
-void Surface::InitPixMap(int width, int height, Surface *surface_) {
-    Release();
-    hdc = new wxMemoryDC(surface_->hdc);
-    hdcOwned = true;
-    bitmap = new wxBitmap(width, height);
-    ((wxMemoryDC*)hdc)->SelectObject(*bitmap);
-    // **** ::SetTextAlign(hdc, TA_BASELINE);
-}
-
-void Surface::PenColour(Colour fore) {
-    hdc->SetPen(wxPen(fore.co, 1, wxSOLID));
+void SurfaceImpl::BrushColour(ColourAllocated back) {
+    hdc->SetBrush(wxBrush(wxColourFromCA(back), wxSOLID));
 }
 
-void Surface::BrushColor(Colour back) {
-    hdc->SetBrush(wxBrush(back.co, wxSOLID));
+void SurfaceImpl::SetFont(Font &font_) {
+  if (font_.GetID()) {
+      hdc->SetFont(*((wxFont*)font_.GetID()));
+    }
 }
 
-void Surface::SetFont(Font &font_) {
-    hdc->SetFont(*font_.GetID());
+int SurfaceImpl::LogPixelsY() {
+    return hdc->GetPPI().y;
 }
 
-int Surface::LogPixelsY() {
-    return hdc->GetPPI().y;
+int SurfaceImpl::DeviceHeightFont(int points) {
+    return points;
 }
 
-void Surface::MoveTo(int x_, int y_) {
+void SurfaceImpl::MoveTo(int x_, int y_) {
     x = x_;
     y = y_;
 }
 
-void Surface::LineTo(int x_, int y_) {
+void SurfaceImpl::LineTo(int x_, int y_) {
     hdc->DrawLine(x,y, x_,y_);
     x = x_;
     y = y_;
 }
 
-void Surface::Polygon(Point *pts, int npts, Colour fore,
-                      Colour back) {
+void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) {
     PenColour(fore);
-    BrushColor(back);
+    BrushColour(back);
     hdc->DrawPolygon(npts, (wxPoint*)pts);
 }
 
-void Surface::RectangleDraw(PRectangle rc, Colour fore, Colour back) {
+void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
     PenColour(fore);
-    BrushColor(back);
+    BrushColour(back);
     hdc->DrawRectangle(wxRectFromPRectangle(rc));
 }
 
-void Surface::FillRectangle(PRectangle rc, Colour back) {
-    BrushColor(back);
+void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
+    BrushColour(back);
     hdc->SetPen(*wxTRANSPARENT_PEN);
     hdc->DrawRectangle(wxRectFromPRectangle(rc));
 }
 
-void Surface::FillRectangle(PRectangle rc, Surface &surfacePattern) {
+void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
     wxBrush br;
-    if (surfacePattern.bitmap)
-        br = wxBrush(*surfacePattern.bitmap);
+    if (((SurfaceImpl&)surfacePattern).bitmap)
+        br = wxBrush(*((SurfaceImpl&)surfacePattern).bitmap);
     else    // Something is wrong so display in red
         br = wxBrush(*wxRED, wxSOLID);
     hdc->SetPen(*wxTRANSPARENT_PEN);
@@ -229,78 +380,153 @@ void Surface::FillRectangle(PRectangle rc, Surface &surfacePattern) {
     hdc->DrawRectangle(wxRectFromPRectangle(rc));
 }
 
-void Surface::RoundedRectangle(PRectangle rc, Colour fore, Colour back) {
+void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
     PenColour(fore);
-    BrushColor(back);
-    hdc->DrawRoundedRectangle(wxRectFromPRectangle(rc), 8);
+    BrushColour(back);
+    hdc->DrawRoundedRectangle(wxRectFromPRectangle(rc), 4);
 }
 
-void Surface::Ellipse(PRectangle rc, Colour fore, Colour back) {
+void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
     PenColour(fore);
-    BrushColor(back);
+    BrushColour(back);
     hdc->DrawEllipse(wxRectFromPRectangle(rc));
 }
 
-void Surface::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
-    hdc->Blit(rc.left, rc.top, rc.Width(), rc.Height(),
-              surfaceSource.hdc, from.x, from.y, wxCOPY);
+void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
+    wxRect r = wxRectFromPRectangle(rc);
+    hdc->Blit(r.x, r.y, r.width, r.height,
+              ((SurfaceImpl&)surfaceSource).hdc,
+              from.x, from.y, wxCOPY);
 }
 
-void Surface::DrawText(PRectangle rc, Font &font, int ybase,
-                       const char *s, int len, Colour fore, Colour back) {
+void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font, int ybase,
+                                 const char *s, int len,
+                                 ColourAllocated fore, ColourAllocated back) {
     SetFont(font);
-    hdc->SetTextForeground(fore.co);
-    hdc->SetTextBackground(back.co);
-    FillRectangle(rc, back);
+    hdc->SetTextForeground(wxColourFromCA(fore));
+    hdc->SetTextBackground(wxColourFromCA(back));
+    //FillRectangle(rc, back);
 
     // ybase is where the baseline should be, but wxWin uses the upper left
     // corner, so I need to calculate the real position for the text...
-    hdc->DrawText(wxString(s, len), rc.left, ybase - font.ascent);
+    hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
 }
 
-void Surface::DrawTextClipped(PRectangle rc, Font &font, int ybase, const char *s, int len, Colour fore, Colour back) {
+void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font, int ybase,
+                                  const char *s, int len,
+                                  ColourAllocated fore, ColourAllocated back) {
     SetFont(font);
-    hdc->SetTextForeground(fore.co);
-    hdc->SetTextBackground(back.co);
-    FillRectangle(rc, back);
+    hdc->SetTextForeground(wxColourFromCA(fore));
+    hdc->SetTextBackground(wxColourFromCA(back));
+    //FillRectangle(rc, back);
     hdc->SetClippingRegion(wxRectFromPRectangle(rc));
 
     // see comments above
-    hdc->DrawText(wxString(s, len), rc.left, ybase - font.ascent);
-    hdc->DestroyClippingRegion();
+    hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
 }
 
-int Surface::WidthText(Font &font, const char *s, int len) {
+
+void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font, int ybase,
+                                      const char *s, int len,
+                                      ColourAllocated fore) {
+
     SetFont(font);
-    int w;
-    int h;
-    hdc->GetTextExtent(wxString(s, len), &w, &h);
-    return w;
+    hdc->SetTextForeground(wxColourFromCA(fore));
+    hdc->SetBackgroundMode(wxTRANSPARENT);
+
+    // ybase is where the baseline should be, but wxWin uses the upper left
+    // corner, so I need to calculate the real position for the text...
+    hdc->DrawText(stc2wx(s, len), rc.left, ybase - font.ascent);
+
+    hdc->SetBackgroundMode(wxSOLID);
 }
 
-void Surface::MeasureWidths(Font &font, const char *s, int len, int *positions) {
+
+void SurfaceImpl::MeasureWidths(Font &font, const char *s, int len, int *positions) {
+
+    wxString str = stc2wx(s, len);
     SetFont(font);
+
+#ifndef __WXMAC__
+    // Calculate the position of each character based on the widths of
+    // the previous characters
+    int* tpos = new int[len];
     int totalWidth = 0;
-    for (int i=0; i<len; i++) {
-        int w;
-        int h;
-        hdc->GetTextExtent(s[i], &w, &h);
+    size_t i;
+    for (i=0; i<str.Length(); i++) {
+        int w, h;
+        hdc->GetTextExtent(str[i], &w, &h);
         totalWidth += w;
-        positions[i] = totalWidth;
+        tpos[i] = totalWidth;
+    }
+#else
+    // Instead of a running total, remeasure from the begining of the
+    // text for each character's position.  This is because with AA fonts
+    // on OS X widths can be fractions of pixels wide when more than one
+    // are drawn together, so the sum of all character widths is not necessarily
+    // (and probably not) the same as the whole string width.
+    int* tpos = new int[len];
+    size_t i;
+    for (i=0; i<str.Length(); i++) {
+        int w, h;
+        hdc->GetTextExtent(str.Left(i+1), &w, &h);
+        tpos[i] = w;
     }
+#endif
+
+
+#if wxUSE_UNICODE
+    // Map the widths for UCS-2 characters back to the UTF-8 input string
+    // NOTE:  I don't think this is right for when sizeof(wxChar) > 2, ie wxGTK2
+    // so figure it out and fix it!
+    i = 0;
+    size_t ui = 0;
+    while (i < len) {
+        unsigned char uch = (unsigned char)s[i];
+        positions[i++] = tpos[ui];
+        if (uch >= 0x80) {
+            if (uch < (0x80 + 0x40 + 0x20)) {
+                positions[i++] = tpos[ui];
+            } else {
+                positions[i++] = tpos[ui];
+                positions[i++] = tpos[ui];
+            }
+        }
+        ui++;
+    }
+#else
+
+    // If not unicode then just use the widths we have
+    memcpy(positions, tpos, len * sizeof(*tpos));
+#endif
+
+    delete [] tpos;
+}
+
+
+int SurfaceImpl::WidthText(Font &font, const char *s, int len) {
+    SetFont(font);
+    int w;
+    int h;
+
+    hdc->GetTextExtent(stc2wx(s, len), &w, &h);
+    return w;
 }
 
-int Surface::WidthChar(Font &font, char ch) {
+
+int SurfaceImpl::WidthChar(Font &font, char ch) {
     SetFont(font);
     int w;
     int h;
-    hdc->GetTextExtent(ch, &w, &h);
+    char s[2] = { ch, 0 };
+
+    hdc->GetTextExtent(stc2wx(s, 1), &w, &h);
     return w;
 }
 
-#define EXTENT_TEST " `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define EXTENT_TEST wxT(" `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
 
-int Surface::Ascent(Font &font) {
+int SurfaceImpl::Ascent(Font &font) {
     SetFont(font);
     int w, h, d, e;
     hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
@@ -308,64 +534,95 @@ int Surface::Ascent(Font &font) {
     return font.ascent;
 }
 
-int Surface::Descent(Font &font) {
+int SurfaceImpl::Descent(Font &font) {
     SetFont(font);
     int w, h, d, e;
     hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
     return d;
 }
 
-int Surface::InternalLeading(Font &font) {
+int SurfaceImpl::InternalLeading(Font &font) {
     return 0;
 }
 
-int Surface::ExternalLeading(Font &font) {
+int SurfaceImpl::ExternalLeading(Font &font) {
     SetFont(font);
     int w, h, d, e;
     hdc->GetTextExtent(EXTENT_TEST, &w, &h, &d, &e);
     return e;
 }
 
-int Surface::Height(Font &font) {
+int SurfaceImpl::Height(Font &font) {
     SetFont(font);
     return hdc->GetCharHeight();
 }
 
-int Surface::AverageCharWidth(Font &font) {
+int SurfaceImpl::AverageCharWidth(Font &font) {
     SetFont(font);
     return hdc->GetCharWidth();
 }
 
-int Surface::SetPalette(Palette *pal, bool inBackGround) {
-    return 0;  // **** figure out what to do with palettes...
+int SurfaceImpl::SetPalette(Palette *pal, bool inBackGround) {
+    return 0;
 }
 
-void Surface::SetClip(PRectangle rc) {
+void SurfaceImpl::SetClip(PRectangle rc) {
     hdc->SetClippingRegion(wxRectFromPRectangle(rc));
 }
 
+void SurfaceImpl::FlushCachedState() {
+}
+
+void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
+    unicodeMode=unicodeMode_;
+#if wxUSE_UNICODE
+    wxASSERT_MSG(unicodeMode == wxUSE_UNICODE,
+                 wxT("Only unicode may be used when wxUSE_UNICODE is on."));
+#else
+    wxASSERT_MSG(unicodeMode == wxUSE_UNICODE,
+                 wxT("Only non-unicode may be used when wxUSE_UNICODE is off."));
+#endif
+}
+
+void SurfaceImpl::SetDBCSMode(int codePage) {
+    // dbcsMode = codePage == SC_CP_DBCS;
+}
 
 
+Surface *Surface::Allocate() {
+    return new SurfaceImpl;
+}
+
+
+//----------------------------------------------------------------------
+
+
+inline wxWindow* GETWIN(WindowID id) { return (wxWindow*)id; }
+
 Window::~Window() {
 }
 
 void Window::Destroy() {
-    if (id)
-        id->Destroy();
+    if (id) {
+        Show(FALSE);
+        GETWIN(id)->Destroy();
+    }
     id = 0;
 }
 
 bool Window::HasFocus() {
-    return wxWindow::FindFocus() == id;
+    return wxWindow::FindFocus() == GETWIN(id);
 }
 
 PRectangle Window::GetPosition() {
-    wxRect rc(id->GetPosition(), id->GetSize());
+    if (! id) return PRectangle();
+    wxRect rc(GETWIN(id)->GetPosition(), GETWIN(id)->GetSize());
     return PRectangleFromwxRect(rc);
 }
 
 void Window::SetPosition(PRectangle rc) {
-    id->SetSize(rc.left, rc.top, rc.Width(), rc.Height());
+    wxRect r = wxRectFromPRectangle(rc);
+    GETWIN(id)->SetSize(r);
 }
 
 void Window::SetPositionRelative(PRectangle rc, Window) {
@@ -373,24 +630,28 @@ void Window::SetPositionRelative(PRectangle rc, Window) {
 }
 
 PRectangle Window::GetClientPosition() {
-    wxSize sz = id->GetClientSize();
-    return  PRectangle(0, 0, sz.x - 1, sz.y - 1);
+    if (! id) return PRectangle();
+    wxSize sz = GETWIN(id)->GetClientSize();
+    return  PRectangle(0, 0, sz.x, sz.y);
 }
 
 void Window::Show(bool show) {
-    id->Show(show);
+    GETWIN(id)->Show(show);
 }
 
 void Window::InvalidateAll() {
-    id->Refresh(false);
+    GETWIN(id)->Refresh(false);
+    wxWakeUpIdle();
 }
 
 void Window::InvalidateRectangle(PRectangle rc) {
-    id->Refresh(false, &wxRectFromPRectangle(rc));
+    wxRect r = wxRectFromPRectangle(rc);
+    GETWIN(id)->Refresh(false, &r);
+    wxWakeUpIdle();
 }
 
 void Window::SetFont(Font &font) {
-    id->SetFont(*font.GetID());
+    GETWIN(id)->SetFont(*((wxFont*)font.GetID()));
 }
 
 void Window::SetCursor(Cursor curs) {
@@ -416,68 +677,376 @@ void Window::SetCursor(Cursor curs) {
         cursorId = wxCURSOR_SIZENS;
         break;
     case cursorReverseArrow:
-        cursorId = wxCURSOR_POINT_RIGHT;
+        cursorId = wxCURSOR_RIGHT_ARROW;
         break;
+    case cursorHand:
+        cursorId = wxCURSOR_HAND;
     default:
         cursorId = wxCURSOR_ARROW;
         break;
     }
-
-    id->SetCursor(wxCursor(cursorId));
+#ifdef __WXMOTIF__
+       wxCursor wc = wxStockCursor(cursorId) ;
+#else
+       wxCursor wc = wxCursor(cursorId) ;
+#endif
+       GETWIN(id)->SetCursor(wc);
 }
 
 
 void Window::SetTitle(const char *s) {
-    id->SetTitle(s);
+    GETWIN(id)->SetTitle(stc2wx(s));
 }
 
 
+//----------------------------------------------------------------------
+// Helper classes for ListBox
 
-ListBox::ListBox() {
+
+// This is a simple subclass of wxLIstView that just resets focus to the
+// parent when it gets it.
+class wxSTCListBox : public wxListView {
+public:
+    wxSTCListBox(wxWindow* parent, wxWindowID id,
+                 const wxPoint& pos, const wxSize& size,
+                 long style)
+        : wxListView(parent, id, pos, size, style)
+    {}
+
+    void OnFocus(wxFocusEvent& event) {
+        GetParent()->SetFocus();
+        event.Skip();
+    }
+
+private:
+    DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(wxSTCListBox, wxListView)
+    EVT_SET_FOCUS( wxSTCListBox::OnFocus)
+END_EVENT_TABLE()
+
+
+
+
+// A window to place the wxSTCListBox upon
+class wxSTCListBoxWin : public wxWindow {
+private:
+    wxListView*         lv;
+    CallBackAction      doubleClickAction;
+    void*               doubleClickActionData;
+public:
+    wxSTCListBoxWin(wxWindow* parent, wxWindowID id) :
+        wxWindow(parent, id, wxDefaultPosition, wxSize(0,0), wxNO_BORDER )
+    {
+
+        SetBackgroundColour(*wxBLACK);
+        lv = new wxSTCListBox(this, id, wxDefaultPosition, wxDefaultSize,
+                              wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxNO_BORDER);
+        lv->SetCursor(wxCursor(wxCURSOR_ARROW));
+        lv->InsertColumn(0, wxEmptyString);
+        lv->InsertColumn(1, wxEmptyString);
+        Hide();
+    }
+
+    int IconWidth() {
+        wxImageList* il = lv->GetImageList(wxIMAGE_LIST_SMALL);
+        if (il != NULL) {
+            int w, h;
+            il->GetSize(0, w, h);
+            return w;
+        }
+        return 0;
+    }
+
+
+    void SetDoubleClickAction(CallBackAction action, void *data) {
+        doubleClickAction = action;
+        doubleClickActionData = data;
+    }
+
+
+    void OnFocus(wxFocusEvent& event) {
+        GetParent()->SetFocus();
+        event.Skip();
+    }
+
+    void OnSize(wxSizeEvent& event) {
+        // resize the child, leaving a 1 pixel border
+        wxSize sz = GetClientSize();
+        lv->SetSize(1, 1, sz.x-2, sz.y-2);
+        // reset the column widths
+        lv->SetColumnWidth(0, IconWidth()+4);
+        lv->SetColumnWidth(1, sz.x - 2 - lv->GetColumnWidth(0) -
+                           wxSystemSettings::GetMetric(wxSYS_VSCROLL_X));
+        event.Skip();
+    }
+
+    void OnActivate(wxListEvent& event) {
+        doubleClickAction(doubleClickActionData);
+    }
+
+    wxListView* GetLB() { return lv; }
+
+private:
+    DECLARE_EVENT_TABLE()
+};
+
+
+BEGIN_EVENT_TABLE(wxSTCListBoxWin, wxWindow)
+    EVT_SET_FOCUS          (    wxSTCListBoxWin::OnFocus)
+    EVT_SIZE               (    wxSTCListBoxWin::OnSize)
+    EVT_LIST_ITEM_ACTIVATED(-1, wxSTCListBoxWin::OnActivate)
+END_EVENT_TABLE()
+
+
+
+inline wxSTCListBoxWin* GETLBW(WindowID win) {
+    return ((wxSTCListBoxWin*)win);
 }
 
-ListBox::~ListBox() {
+inline wxListView* GETLB(WindowID win) {
+    return GETLBW(win)->GetLB();
+}
+
+//----------------------------------------------------------------------
+
+class ListBoxImpl : public ListBox {
+private:
+    int                 lineHeight;
+    bool                unicodeMode;
+    int                 desiredVisibleRows;
+    int                 aveCharWidth;
+    int                 maxStrWidth;
+    wxImageList*        imgList;
+    wxArrayInt*         imgTypeMap;
+
+public:
+    ListBoxImpl();
+    ~ListBoxImpl();
+
+    virtual void SetFont(Font &font);
+    virtual void Create(Window &parent, int ctrlID, int lineHeight_, bool unicodeMode_);
+    virtual void SetAverageCharWidth(int width);
+    virtual void SetVisibleRows(int rows);
+    virtual PRectangle GetDesiredRect();
+    virtual int CaretFromEdge();
+    virtual void Clear();
+    virtual void Append(char *s, int type = -1);
+    virtual int Length();
+    virtual void Select(int n);
+    virtual int GetSelection();
+    virtual int Find(const char *prefix);
+    virtual void GetValue(int n, char *value, int len);
+    virtual void Sort();
+    virtual void RegisterImage(int type, const char *xpm_data);
+    virtual void ClearRegisteredImages();
+    virtual void SetDoubleClickAction(CallBackAction, void *);
+
+};
+
+
+ListBoxImpl::ListBoxImpl()
+    : lineHeight(10), unicodeMode(false),
+      desiredVisibleRows(5), aveCharWidth(8), maxStrWidth(0),
+      imgList(NULL), imgTypeMap(NULL)
+{
+}
+
+ListBoxImpl::~ListBoxImpl() {
+    if (imgList) {
+        delete imgList;
+        imgList = NULL;
+    }
+    if (imgTypeMap) {
+        delete imgTypeMap;
+        imgTypeMap = NULL;
+    }
 }
 
-void ListBox::Create(Window &parent, int ctrlID) {
-    id = new wxListBox(parent.id, ctrlID, wxDefaultPosition, wxDefaultSize,
-                       0, NULL, wxLB_SINGLE | wxLB_SORT);
+
+void ListBoxImpl::SetFont(Font &font) {
+    GETLB(id)->SetFont(*((wxFont*)font.GetID()));
+}
+
+
+void ListBoxImpl::Create(Window &parent, int ctrlID, int lineHeight_, bool unicodeMode_) {
+    lineHeight =  lineHeight_;
+    unicodeMode = unicodeMode_;
+    maxStrWidth = 0;
+    id = new wxSTCListBoxWin(GETWIN(parent.GetID()), ctrlID);
+    if (imgList != NULL)
+        GETLB(id)->SetImageList(imgList, wxIMAGE_LIST_SMALL);
+}
+
+
+void ListBoxImpl::SetAverageCharWidth(int width) {
+    aveCharWidth = width;
+}
+
+
+void ListBoxImpl::SetVisibleRows(int rows) {
+    desiredVisibleRows = rows;
+}
+
+
+PRectangle ListBoxImpl::GetDesiredRect() {
+    // wxListCtrl doesn't have a DoGetBestSize, so instead we kept track of
+    // the max size in Append and calculate it here...
+    int maxw = maxStrWidth;
+    int maxh = 0;
+
+    // give it a default if there are no lines, and/or add a bit more
+    if (maxw == 0) maxw = 100;
+    maxw += aveCharWidth * 3 +
+            GETLBW(id)->IconWidth() + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
+    if (maxw > 350)
+        maxw = 350;
+
+    // estimate a desired height
+    int count = GETLB(id)->GetItemCount();
+    if (count) {
+        wxRect rect;
+        GETLB(id)->GetItemRect(0, rect);
+        maxh = count * rect.GetHeight();
+        if (maxh > 140)  // TODO:  Use desiredVisibleRows??
+            maxh = 140;
+
+        // Try to make the size an exact multiple of some number of lines
+        int lines = maxh / rect.GetHeight();
+        maxh = (lines + 1) * rect.GetHeight() + 2;
+    }
+    else
+        maxh = 100;
+
+    PRectangle rc;
+    rc.top = 0;
+    rc.left = 0;
+    rc.right = maxw;
+    rc.bottom = maxh;
+    return rc;
+}
+
+
+int ListBoxImpl::CaretFromEdge() {
+    return 4 + GETLBW(id)->IconWidth();
 }
 
-void ListBox::Clear() {
-    ((wxListBox*)id)->Clear();
+
+void ListBoxImpl::Clear() {
+    GETLB(id)->DeleteAllItems();
 }
 
-void ListBox::Append(char *s) {
-    ((wxListBox*)id)->Append(s);
+
+void ListBoxImpl::Append(char *s, int type) {
+    wxString text = stc2wx(s);
+    long count  = GETLB(id)->GetItemCount();
+    long itemID  = GETLB(id)->InsertItem(count, wxEmptyString);
+    GETLB(id)->SetItem(itemID, 1, text);
+    int itemWidth = 0;
+    GETLB(id)->GetTextExtent(text, &itemWidth, NULL);
+    maxStrWidth = wxMax(maxStrWidth, itemWidth);
+    if (type != -1) {
+        wxCHECK_RET(imgTypeMap, wxT("Unexpected NULL imgTypeMap"));
+        long idx = imgTypeMap->Item(type);
+        GETLB(id)->SetItemImage(itemID, idx, idx);
+    }
 }
 
-int ListBox::Length() {
-    return ((wxListBox*)id)->Number();
+
+int ListBoxImpl::Length() {
+    return GETLB(id)->GetItemCount();
 }
 
-void ListBox::Select(int n) {
-    ((wxListBox*)id)->SetSelection(n);
+
+void ListBoxImpl::Select(int n) {
+    bool select = TRUE;
+    if (n == -1) {
+        n = 0;
+        select = FALSE;
+    }
+    GETLB(id)->Focus(n);
+    GETLB(id)->Select(n, select);
 }
 
-int ListBox::GetSelection() {
-    return ((wxListBox*)id)->GetSelection();
+
+int ListBoxImpl::GetSelection() {
+    return GETLB(id)->GetFirstSelected();
 }
 
-int ListBox::Find(const char *prefix) {
-    return ((wxListBox*)id)->FindString(prefix);
+
+int ListBoxImpl::Find(const char *prefix) {
+    // No longer used
+    return -1;
 }
 
-void ListBox::GetValue(int n, char *value, int len) {
-    wxString text = ((wxListBox*)id)->GetString(n);
-    strncpy(value, text.c_str(), len);
+
+void ListBoxImpl::GetValue(int n, char *value, int len) {
+    wxListItem item;
+    item.SetId(n);
+    item.SetColumn(1);
+    item.SetMask(wxLIST_MASK_TEXT);
+    GETLB(id)->GetItem(item);
+    strncpy(value, wx2stc(item.GetText()), len);
     value[len-1] = '\0';
 }
 
-void ListBox::Sort() {
-    // wxWindows keeps sorted so no need to sort
+void ListBoxImpl::Sort() {
+}
+
+
+void ListBoxImpl::RegisterImage(int type, const char *xpm_data) {
+    wxMemoryInputStream stream(xpm_data, strlen(xpm_data)+1);
+    wxBitmap bmp(wxImage(stream, wxBITMAP_TYPE_XPM));
+
+    if (! imgList) {
+        // assumes all images are the same size
+        imgList = new wxImageList(bmp.GetWidth(), bmp.GetHeight(), TRUE);
+        imgTypeMap = new wxArrayInt;
+    }
+
+    int idx = imgList->Add(bmp);
+
+    // do we need to extend the mapping array?
+    wxArrayInt& itm = *imgTypeMap;
+    if ( itm.GetCount() < (size_t)type+1)
+        itm.Add(-1, type - itm.GetCount() + 1);
+
+    // Add an item that maps type to the image index
+    itm[type] = idx;
+}
+
+void ListBoxImpl::ClearRegisteredImages() {
+    if (imgList) {
+        delete imgList;
+        imgList = NULL;
+    }
+    if (imgTypeMap) {
+        delete imgTypeMap;
+        imgTypeMap = NULL;
+    }
+    if (id)
+        GETLB(id)->SetImageList(NULL, wxIMAGE_LIST_SMALL);
+}
+
+
+void ListBoxImpl::SetDoubleClickAction(CallBackAction action, void *data) {
+    GETLBW(id)->SetDoubleClickAction(action, data);
+}
+
+
+
+ListBox::ListBox() {
+}
+
+ListBox::~ListBox() {
+}
+
+ListBox *ListBox::Allocate() {
+    return new ListBoxImpl();
 }
 
+//----------------------------------------------------------------------
 
 Menu::Menu() : id(0) {
 }
@@ -489,42 +1058,48 @@ void Menu::CreatePopUp() {
 
 void Menu::Destroy() {
     if (id)
-        delete id;
+        delete (wxMenu*)id;
     id = 0;
 }
 
 void Menu::Show(Point pt, Window &w) {
-    w.GetID()->PopupMenu(id, pt.x - 4, pt.y);
+    GETWIN(w.GetID())->PopupMenu((wxMenu*)id, pt.x - 4, pt.y);
     Destroy();
 }
 
+//----------------------------------------------------------------------
 
-Colour Platform::Chrome() {
+ColourDesired Platform::Chrome() {
     wxColour c;
-    c = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
-    return Colour(c.Red(), c.Green(), c.Blue());
+    c = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
+    return ColourDesired(c.Red(), c.Green(), c.Blue());
 }
 
-Colour Platform::ChromeHighlight() {
+ColourDesired Platform::ChromeHighlight() {
     wxColour c;
-    c = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT);
-    return Colour(c.Red(), c.Green(), c.Blue());
+    c = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT);
+    return ColourDesired(c.Red(), c.Green(), c.Blue());
 }
 
 const char *Platform::DefaultFont() {
-    return wxNORMAL_FONT->GetFaceName();
+    static char buf[128];
+    strcpy(buf, wxNORMAL_FONT->GetFaceName().mbc_str());
+    return buf;
 }
 
 int Platform::DefaultFontSize() {
-    return 8;
+    return wxNORMAL_FONT->GetPointSize();
 }
 
 unsigned int Platform::DoubleClickTime() {
     return 500;   // **** ::GetDoubleClickTime();
 }
 
+bool Platform::MouseButtonBounce() {
+       return FALSE;
+}
 void Platform::DebugDisplay(const char *s) {
-    wxLogDebug(s);
+    wxLogDebug(stc2wx(s));
 }
 
 bool Platform::IsKeyDown(int key) {
@@ -540,6 +1115,15 @@ long Platform::SendScintilla(WindowID w,
     return stc->SendMsg(msg, wParam, lParam);
 }
 
+long Platform::SendScintillaPointer(WindowID w,
+                                    unsigned int msg,
+                                    unsigned long wParam,
+                                    void *lParam) {
+
+    wxStyledTextCtrl* stc = (wxStyledTextCtrl*)w;
+    return stc->SendMsg(msg, wParam, (long)lParam);
+}
+
 
 // These are utility functions not really tied to a platform
 
@@ -570,6 +1154,38 @@ void Platform::DebugPrintf(const char *format, ...) {
 #endif
 }
 
+
+static bool assertionPopUps = true;
+
+bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
+       bool ret = assertionPopUps;
+       assertionPopUps = assertionPopUps_;
+       return ret;
+}
+
+void Platform::Assert(const char *c, const char *file, int line) {
+       char buffer[2000];
+       sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
+       if (assertionPopUps) {
+            /*int idButton = */
+            wxMessageBox(stc2wx(buffer),
+                         wxT("Assertion failure"),
+                         wxICON_HAND | wxOK);
+//             if (idButton == IDRETRY) {
+//                     ::DebugBreak();
+//             } else if (idButton == IDIGNORE) {
+//                     // all OK
+//             } else {
+//                     abort();
+//             }
+       } else {
+               strcat(buffer, "\r\n");
+               Platform::DebugDisplay(buffer);
+               abort();
+       }
+}
+
+
 int Platform::Clamp(int val, int minVal, int maxVal) {
     if (val > maxVal)
         val = maxVal;
@@ -579,6 +1195,33 @@ int Platform::Clamp(int val, int minVal, int maxVal) {
 }
 
 
+bool Platform::IsDBCSLeadByte(int codePage, char ch) {
+    return false;
+}
+
+int Platform::DBCSCharLength(int codePage, const char *s) {
+    return 0;
+}
+
+int Platform::DBCSCharMaxLength() {
+    return 0;
+}
+
+
+//----------------------------------------------------------------------
+
+ElapsedTime::ElapsedTime() {
+    wxStartTimer();
+}
+
+double ElapsedTime::Duration(bool reset) {
+    double result = wxGetElapsedTime(reset);
+    result /= 1000.0;
+    return result;
+}
+
+
+//----------------------------------------------------------------------