diff --git a/src/stc/PlatWX.cpp b/src/stc/PlatWX.cpp index ce4e7e2bff..5bc0f60436 100644 --- a/src/stc/PlatWX.cpp +++ b/src/stc/PlatWX.cpp @@ -2330,6 +2330,8 @@ public: // Image data const wxBitmap* GetImage(int i) const; + int GetImageAreaWidth() const; + int GetImageAreaHeight() const; // Colour data void ComputeColours(); @@ -2358,6 +2360,7 @@ private: int m_desiredVisibleRows; ImgList m_imgList; + wxSize m_imgAreaSize; wxColour m_borderColour; wxColour m_bgColour; @@ -2414,10 +2417,33 @@ void wxSTCListBoxVisualData::RegisterImage(int type, const wxBitmap& bmp) return; ImgList::iterator it=m_imgList.find(type); + bool preExistingWithDifferentSize = false; if ( it != m_imgList.end() ) + { + if ( it->second.GetSize() != bmp.GetSize() ) + { + preExistingWithDifferentSize = true; + } + m_imgList.erase(it); + } m_imgList[type] = bmp; + + if ( preExistingWithDifferentSize ) + { + m_imgAreaSize.Set(0,0); + + for ( ImgList::iterator imgIt = m_imgList.begin() ; + imgIt != m_imgList.end() ; ++imgIt ) + { + m_imgAreaSize.IncTo(it->second.GetSize()); + } + } + else + { + m_imgAreaSize.IncTo(bmp.GetSize()); + } } void wxSTCListBoxVisualData::RegisterImage(int type, const char *xpm_data) @@ -2451,6 +2477,7 @@ void wxSTCListBoxVisualData::RegisterRGBAImage(int type, int width, int height, void wxSTCListBoxVisualData::ClearRegisteredImages() { m_imgList.clear(); + m_imgAreaSize.Set(0,0); } const wxBitmap* wxSTCListBoxVisualData::GetImage(int i) const @@ -2463,6 +2490,16 @@ const wxBitmap* wxSTCListBoxVisualData::GetImage(int i) const return NULL; } +int wxSTCListBoxVisualData::GetImageAreaWidth() const +{ + return m_imgAreaSize.GetWidth(); +} + +int wxSTCListBoxVisualData::GetImageAreaHeight() const +{ + return m_imgAreaSize.GetHeight(); +} + void wxSTCListBoxVisualData::ComputeColours() { // wxSYS_COLOUR_BTNSHADOW seems to be the closest match with most themes. @@ -2624,7 +2661,7 @@ public: void SetContainerBorderSize(int); // ListBoxImpl implementation - void SetListBoxFont(Font &font); + virtual void SetListBoxFont(Font &font); void SetAverageCharWidth(int width); PRectangle GetDesiredRect() const; int CaretFromEdge() const; @@ -2640,9 +2677,10 @@ protected: // Helpers void AppendHelper(const wxString& text, int type); void SelectHelper(int i); - void AccountForBitmap(int type, bool recalculateItemHeight); void RecalculateItemHeight(); int TextBoxFromClientEdge() const; + virtual void OnDrawItemText(wxDC&, const wxRect&, + const wxString&, const wxColour&) const; // Event handlers void OnSelection(wxCommandEvent&); @@ -2657,9 +2695,6 @@ protected: virtual void OnDrawItem(wxDC& , const wxRect &, size_t) const wxOVERRIDE; virtual void OnDrawBackground(wxDC&, const wxRect&,size_t) const wxOVERRIDE; -private: - WX_DECLARE_HASH_SET(int, wxIntegerHash, wxIntegerEqual, SetOfInts); - wxSTCListBoxVisualData* m_visualData; wxVector m_labels; wxVector m_imageNos; @@ -2675,8 +2710,6 @@ private: int m_textHeight; int m_itemHeight; int m_textTopGap; - int m_imageAreaWidth; - int m_imageAreaHeight; // These drawing parameters are set internally and can be changed if needed // to better match the appearance of a list box on a specific platform. @@ -2690,7 +2723,7 @@ wxSTCListBox::wxSTCListBox(wxWindow* parent, wxSTCListBoxVisualData* v, int ht) m_visualData(v), m_maxStrWidth(0), m_currentRow(wxNOT_FOUND), m_doubleClickAction(NULL), m_doubleClickActionData(NULL), m_aveCharWidth(8), m_textHeight(ht), m_itemHeight(ht), - m_textTopGap(0), m_imageAreaWidth(0), m_imageAreaHeight(0) + m_textTopGap(0) { wxVListBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE, "AutoCompListBox"); @@ -2796,8 +2829,6 @@ int wxSTCListBox::CaretFromEdge() const void wxSTCListBox::Clear() { - m_imageAreaWidth = 0; - m_imageAreaHeight = 0; m_labels.clear(); m_imageNos.clear(); } @@ -2805,7 +2836,7 @@ void wxSTCListBox::Clear() void wxSTCListBox::Append(char *s, int type) { AppendHelper(stc2wx(s), type); - AccountForBitmap(type, true); + RecalculateItemHeight(); } int wxSTCListBox::Length() const @@ -2835,7 +2866,6 @@ void wxSTCListBox::SetList(const char* list, char separator, char typesep) { wxWindowUpdateLocker noUpdates(this); Clear(); - SetOfInts bitmapNos; wxStringTokenizer tkzr(stc2wx(list), (wxChar)separator); while ( tkzr.HasMoreTokens() ) { wxString token = tkzr.GetNextToken(); @@ -2846,14 +2876,9 @@ void wxSTCListBox::SetList(const char* list, char separator, char typesep) token.Truncate(pos); } AppendHelper(token, (int)type); - bitmapNos.insert(static_cast(type)); } - for ( SetOfInts::iterator it=bitmapNos.begin(); it!=bitmapNos.end(); ++it ) - AccountForBitmap(*it, false); - - if ( m_imageAreaHeight > 0 ) - RecalculateItemHeight(); + RecalculateItemHeight(); } void wxSTCListBox::AppendHelper(const wxString& text, int type) @@ -2895,34 +2920,17 @@ void wxSTCListBox::SelectHelper(int i) } } -void wxSTCListBox::AccountForBitmap(int type, bool recalculateItemHeight) -{ - const int oldHeight = m_imageAreaHeight; - const wxBitmap* bmp = m_visualData->GetImage(type); - - if ( bmp ) - { - if ( bmp->GetWidth() > m_imageAreaWidth ) - m_imageAreaWidth = bmp->GetWidth(); - - if ( bmp->GetHeight() > m_imageAreaHeight ) - m_imageAreaHeight = bmp->GetHeight(); - } - - if ( recalculateItemHeight && m_imageAreaHeight != oldHeight ) - RecalculateItemHeight(); -} - void wxSTCListBox::RecalculateItemHeight() { m_itemHeight = wxMax(m_textHeight + 2 * m_textExtraVerticalPadding, - m_imageAreaHeight + 2 * m_imagePadding); + m_visualData->GetImageAreaHeight() + 2 * m_imagePadding); m_textTopGap = (m_itemHeight - m_textHeight)/2; } int wxSTCListBox::TextBoxFromClientEdge() const { - return (m_imageAreaWidth == 0 ? 0 : m_imageAreaWidth + 2 * m_imagePadding); + const int width = m_visualData->GetImageAreaWidth(); + return (width == 0 ? 0 : width + 2 * m_imagePadding); } void wxSTCListBox::OnSelection(wxCommandEvent& event) @@ -2993,7 +3001,7 @@ wxCoord wxSTCListBox::OnMeasureItem(size_t WXUNUSED(n)) const // // +++++++++++++++++++++++++ =====ITEM TEXT================ // | | | | -// | m_imageAreaWidth | | +// | imageAreaWidth | | // | | | // m_imagePadding | m_textBoxToTextGap // | @@ -3002,8 +3010,8 @@ wxCoord wxSTCListBox::OnMeasureItem(size_t WXUNUSED(n)) const // // m_imagePadding : Used to give a little extra space between the // client edge and an item's bitmap. -// m_imageAreaWidth : Computed as the width of the largest registered -// bitmap. +// imageAreaWidth : Computed as the width of the largest registered +// bitmap (part of wxSTCListBoxVisualData). // m_textBoxToTextGap : Used so that item text does not begin immediately // at the edge of the highlight box. // @@ -3013,6 +3021,17 @@ wxCoord wxSTCListBox::OnMeasureItem(size_t WXUNUSED(n)) const // x = m_imagePadding + m_imageAreaWidth + m_imagePadding. // Text is drawn at x + m_textBoxToTextGap and centered vertically. +void wxSTCListBox::OnDrawItemText(wxDC& dc, const wxRect& rect, + const wxString& label, + const wxColour& textCol) const +{ + wxDCTextColourChanger tcc(dc, textCol); + + wxString ellipsizedlabel = wxControl::Ellipsize(label, dc, wxELLIPSIZE_END, + rect.GetWidth()); + dc.DrawText(ellipsizedlabel, rect.GetLeft(), rect.GetTop()); +} + void wxSTCListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const { wxString label; @@ -3026,24 +3045,26 @@ void wxSTCListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const int topGap = m_textTopGap; int leftGap = TextBoxFromClientEdge() + m_textBoxToTextGap; - wxDCTextColourChanger tcc(dc); + wxColour textCol; if ( IsSelected(n) ) - tcc.Set(m_visualData->GetHighlightTextColour()); + textCol = m_visualData->GetHighlightTextColour(); else if ( static_cast(n) == m_currentRow ) - tcc.Set(m_visualData->GetCurrentTextColour()); + textCol = m_visualData->GetCurrentTextColour(); else - tcc.Set(m_visualData->GetTextColour()); + textCol = m_visualData->GetTextColour(); - label = wxControl::Ellipsize(label, dc, wxELLIPSIZE_END, - rect.GetWidth() - leftGap); - dc.DrawText(label, rect.GetLeft() + leftGap, rect.GetTop() + topGap); + wxRect rect2(rect.GetLeft() + leftGap, rect.GetTop() + topGap, + rect.GetWidth() - leftGap, m_textHeight); + + OnDrawItemText(dc, rect2, label, textCol); const wxBitmap* b = m_visualData->GetImage(imageNo); if ( b ) { + const int width = m_visualData->GetImageAreaWidth(); topGap = (m_itemHeight - b->GetHeight())/2; - leftGap = m_imagePadding + (m_imageAreaWidth - b->GetWidth())/2; + leftGap = m_imagePadding + (width - b->GetWidth())/2; dc.DrawBitmap(*b, rect.GetLeft()+leftGap, rect.GetTop()+topGap, true); } } @@ -3104,11 +3125,107 @@ void wxSTCListBox::OnDrawBackground(wxDC &dc, const wxRect &rect,size_t n) const } +#ifdef HAVE_DIRECTWRITE_TECHNOLOGY + +// This class will use SurfaceD2D methods to measure and draw items in the popup +// listbox. This is needed to ensure that the text in the listbox matches the +// text in the editor window as closely as possible. + +class wxSTCListBoxD2D : public wxSTCListBox +{ +public: + wxSTCListBoxD2D(wxWindow* parent, wxSTCListBoxVisualData* v, int ht) + : wxSTCListBox(parent, v, ht) + , m_surfaceFontData(NULL) + { + } + + ~wxSTCListBoxD2D() + { + delete m_surfaceFontData; + } + + void SetListBoxFont(Font& font) wxOVERRIDE + { + // Retrieve the SurfaceFontDataD2D from font and store a copy of it. + wxFontWithAscent* fwa = wxFontWithAscent::FromFID(font.GetID()); + + SurfaceData* data = fwa->GetSurfaceFontData(); + SurfaceFontDataD2D* d2dft = static_cast(data); + m_surfaceFontData = new SurfaceFontDataD2D(*d2dft); + + // Create a SurfaceD2D object to measure text height for the font. + SurfaceD2D surface; + wxClientDC dc(this); + surface.Init(&dc, GetGrandParent()); + m_textHeight = surface.Height(font); + surface.Release(); + + RecalculateItemHeight(); + } + + void OnDrawItemText(wxDC& dc, const wxRect& rect, const wxString& label, + const wxColour& textCol) const wxOVERRIDE + { + // Create a font and a surface object. + wxFontWithAscent* fontCopy = new wxFontWithAscent(wxFont()); + SurfaceFontDataD2D* sfd = new SurfaceFontDataD2D(*m_surfaceFontData); + fontCopy->SetSurfaceFontData(sfd); + Font tempFont; + tempFont.SetID(fontCopy); + + SurfaceD2D surface; + surface.Init(&dc, GetGrandParent()); + + // Ellipsize the label if necessary. This is done by manually removing + // characters from the end of the label until it's short enough. + wxString ellipsizedLabel = label; + + wxCharBuffer buffer = wx2stc(ellipsizedLabel); + int ellipsizedLen = wx2stclen(ellipsizedLabel, buffer); + int curWidth = surface.WidthText(tempFont, buffer.data(),ellipsizedLen); + + for ( int i = label.length(); curWidth > rect.GetWidth() && i; --i ) + { + ellipsizedLabel = label.Left(i); + #if wxUSE_UNICODE + // Add the "Horizontal Ellipsis" character (U+2026). + ellipsizedLabel << wxUniChar(0x2026); + #else + ellipsizedLabel << "..."; + #endif + + buffer = wx2stc(ellipsizedLabel); + ellipsizedLen = wx2stclen(ellipsizedLabel, buffer); + curWidth = surface.WidthText(tempFont, buffer.data(),ellipsizedLen); + } + + // Construct the necessary Scintilla objects and then draw the label. + PRectangle prect = PRectangleFromwxRect(rect); + ColourDesired fore(textCol.Red(), textCol.Green(), textCol.Blue()); + + XYPOSITION ybase = rect.GetTop() + m_surfaceFontData->GetAscent(); + + surface.DrawTextTransparent(prect, tempFont, ybase, buffer.data(), + ellipsizedLen, fore); + + // Clean up. + tempFont.Release(); + surface.Release(); + } + +private: + SurfaceFontDataD2D* m_surfaceFontData; +}; +#endif // HAVE_DIRECTWRITE_TECHNOLOGY + + // A popup window to place the wxSTCListBox upon class wxSTCListBoxWin : public wxSTCPopupWindow { public: - wxSTCListBoxWin(wxWindow*, wxSTCListBox**, wxSTCListBoxVisualData*, int); + wxSTCListBoxWin(wxWindow*, wxSTCListBox**, wxSTCListBoxVisualData*, + int, int); protected: void OnPaint(wxPaintEvent&); @@ -3118,10 +3235,21 @@ private: }; wxSTCListBoxWin::wxSTCListBoxWin(wxWindow* parent, wxSTCListBox** lb, - wxSTCListBoxVisualData* v, int h) + wxSTCListBoxVisualData* v, int h, int tech) :wxSTCPopupWindow(parent) { - *lb = new wxSTCListBox(this, v, h); + switch ( tech ) + { +#ifdef HAVE_DIRECTWRITE_TECHNOLOGY + case wxSTC_TECHNOLOGY_DIRECTWRITE: + *lb = new wxSTCListBoxD2D(this, v, h); + break; +#endif + case wxSTC_TECHNOLOGY_DEFAULT: + wxFALLTHROUGH; + default: + *lb = new wxSTCListBox(this, v, h); + } // Use the background of this window to form a frame around the listbox // except on macos where the native Scintilla popup has no frame. @@ -3171,10 +3299,9 @@ void ListBoxImpl::SetFont(Font &font) { void ListBoxImpl::Create(Window &parent, int WXUNUSED(ctrlID), Point WXUNUSED(location_), int lineHeight_, - bool WXUNUSED(unicodeMode_), - int WXUNUSED(technology_)) { + bool WXUNUSED(unicodeMode_), int technology_) { wid = new wxSTCListBoxWin(GETWIN(parent.GetID()), &m_listBox, m_visualData, - lineHeight_); + lineHeight_, technology_); } diff --git a/src/stc/ScintillaWX.cpp b/src/stc/ScintillaWX.cpp index 7b7a7ef033..23c5453fd5 100644 --- a/src/stc/ScintillaWX.cpp +++ b/src/stc/ScintillaWX.cpp @@ -1510,13 +1510,8 @@ void ScintillaWX::ImeStartComposition() { int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER; if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1 sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER; - AutoSurface surface(this); - int deviceHeight = sizeZoomed; - if (surface) { - deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72; - } // The negative is to allow for leading - lf.lfHeight = -(std::abs(deviceHeight / SC_FONT_SIZE_MULTIPLIER)); + lf.lfHeight = -::MulDiv(sizeZoomed, stc->GetDPI().y, 72 * SC_FONT_SIZE_MULTIPLIER); lf.lfWeight = vs.styles[styleHere].weight; lf.lfItalic = static_cast(vs.styles[styleHere].italic ? 1 : 0); lf.lfCharSet = DEFAULT_CHARSET;