Example #1
1
wxCoord
wxGridCellAutoWrapStringRenderer::BreakWord(wxDC& dc,
                                            const wxString& word,
                                            wxCoord maxWidth,
                                            wxArrayString& lines,
                                            wxString& line)
{
    wxArrayInt widths;
    dc.GetPartialTextExtents(word, widths);

    // TODO: Use binary search to find the first element > maxWidth.
    const unsigned count = widths.size();
    unsigned n;
    for ( n = 0; n < count; n++ )
    {
        if ( widths[n] > maxWidth )
            break;
    }

    if ( n == 0 )
    {
        // This is a degenerate case: the first character of the word is
        // already wider than the available space, so we just can't show it
        // completely and have to put the first character in this line.
        n = 1;
    }

    lines.push_back(word.substr(0, n));

    // Check if the remainder of the string fits in one line.
    //
    // Unfortunately we can't use the existing partial text extents as the
    // extent of the remainder may be different when it's rendered in a
    // separate line instead of as part of the same one, so we have to
    // recompute it.
    const wxString rest = word.substr(n);
    const wxCoord restWidth = dc.GetTextExtent(rest).x;
    if ( restWidth <= maxWidth )
    {
        line = rest;
        return restWidth;
    }

    // Break the rest of the word into lines.
    //
    // TODO: Perhaps avoid recursion? The code is simpler like this but using a
    // loop in this function would probably be more efficient.
    return BreakWord(dc, rest, maxWidth, lines, line);
}
Example #2
0
void SurfaceImpl::MeasureWidths(Font &font, const char *s, int len, XYPOSITION *positions) {

    wxString   str = stc2wx(s, len);
    wxArrayInt tpos;

    SetFont(font);

    hdc->GetPartialTextExtents(str, tpos);

#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!
    size_t i = 0;
    size_t ui = 0;
    while ((int)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 // !wxUSE_UNICODE
    // If not unicode then just use the widths we have
    for (int i = 0; i < len; i++) {
        positions[i] = tpos[i];
    }
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
}
Example #3
0
// -----------------------------------------------------------------------------
// Draws function description text [desc] at [left,top].
// Returns a rect of the bounds of the drawn text
// -----------------------------------------------------------------------------
wxRect SCallTip::drawFunctionDescription(wxDC& dc, const wxString& desc, int left, int top) const
{
	auto   italic = font_.Italic();
	wxRect rect(left, top, 0, 0);
	dc.SetFont(italic);
	int max_right = 0;
	if (dc.GetTextExtent(desc).x > MAX_WIDTH)
	{
		// Description is too long, split into multiple lines
		vector<wxString> desc_lines;
		wxString         line = desc;
		wxArrayInt       extents;
		while (true)
		{
			dc.GetPartialTextExtents(line, extents);
			bool split = false;
			for (unsigned a = 0; a < extents.size(); a++)
			{
				if (extents[a] > MAX_WIDTH)
				{
					// Try to split in phrases first.
					size_t eol = (size_t)line.SubString(0, a).Last('.') + 1;
					eol        = line[eol] == ' ' ? eol : -1;
					if (eol <= 0 || eol > MAX_WIDTH)
						eol = (size_t)line.SubString(0, a).Last(',') + 1;
					if (eol <= 0 || eol > MAX_WIDTH)
						eol = (size_t)line.SubString(0, a).Last(' ');
					desc_lines.push_back(line.SubString(0, eol));
					line  = line.SubString(eol + 1, line.Length());
					split = true;
					break;
				}
			}

			if (!split)
			{
				desc_lines.push_back(line);
				break;
			}
		}

		int bottom = rect.GetBottom() + UI::scalePx(font_.GetPixelSize().GetHeight());
		for (const auto& desc_line : desc_lines)
		{
			drawText(dc, desc_line, 0, bottom, &rect);
			bottom = rect.GetBottom();
			if (rect.GetRight() > max_right)
				max_right = rect.GetRight();
		}
	}
	else
	{
		drawText(dc, desc, 0, rect.GetBottom() + UI::scalePx(font_.GetPixelSize().GetHeight()), &rect);
		if (rect.GetRight() > max_right)
			max_right = rect.GetRight();
	}

	return { left, top, max_right - left, rect.GetBottom() - top };
}
Example #4
0
/* static and protected */
wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxDC& dc,
                                              wxEllipsizeMode mode, int maxFinalWidth,
                                              int replacementWidth, int marginWidth)
{
    wxASSERT_MSG(replacementWidth > 0 && marginWidth > 0,
                 "Invalid parameters");
    wxASSERT_MSG(!curLine.Contains('\n'),
                 "Use Ellipsize() instead!");

    // NOTE: this function assumes that any mnemonic/tab character has already
    //       been handled if it was necessary to handle them (see Ellipsize())

    if (maxFinalWidth <= 0)
        return wxEmptyString;

    wxArrayInt charOffsets;
    size_t len = curLine.length();
    if (len == 0 ||
        !dc.GetPartialTextExtents(curLine, charOffsets))
        return curLine;

    wxASSERT(charOffsets.GetCount() == len);

    size_t totalWidth = charOffsets.Last();
    if ( totalWidth <= (size_t)maxFinalWidth )
        return curLine;     // we don't need to do any ellipsization!

    int excessPixels = totalWidth - maxFinalWidth +
                       replacementWidth +
                       marginWidth;     // security margin (NEEDED!)
    wxASSERT(excessPixels>0);

    // remove characters in excess
    size_t initialChar,     // index of first char to erase
           nChars;          // how many chars do we need to erase?

    switch (mode)
    {
        case wxELLIPSIZE_START:
            initialChar = 0;
            for ( nChars=0;
                  nChars < len && charOffsets[nChars] < excessPixels;
                  nChars++ )
                ;
            break;

        case wxELLIPSIZE_MIDDLE:
            {
                // the start & end of the removed span of chars
                initialChar = len/2;
                size_t endChar = len/2;

                int removed = 0;
                for ( ; removed < excessPixels; )
                {
                    if (initialChar > 0)
                    {
                        // width of the initialChar-th character
                        int width = charOffsets[initialChar] -
                                    charOffsets[initialChar-1];

                        // remove the initialChar-th character
                        removed += width;
                        initialChar--;
                    }

                    if (endChar < len - 1 &&
                        removed < excessPixels)
                    {
                        // width of the (endChar+1)-th character
                        int width = charOffsets[endChar+1] -
                                    charOffsets[endChar];

                        // remove the endChar-th character
                        removed += width;
                        endChar++;
                    }

                    if (initialChar == 0 && endChar == len-1)
                    {
                        nChars = len+1;
                        break;
                    }
                }

                initialChar++;
                nChars = endChar - initialChar + 1;
            }
            break;

        case wxELLIPSIZE_END:
            {
                wxASSERT(len > 0);

                int maxWidth = totalWidth - excessPixels;
                for ( initialChar = 0;
                      initialChar < len && charOffsets[initialChar] < maxWidth;
                      initialChar++ )
                    ;

                if (initialChar == 0)
                {
                    nChars = len;
                }
                else
                {
                    //initialChar--;      // go back one character
                    nChars = len - initialChar;
                }
            }
            break;

        default:
            wxFAIL_MSG("invalid ellipsize mode");
            return curLine;
    }

    wxString ret(curLine);
    if (nChars >= len)
    {
        // need to remove the entire row!
        ret.clear();
    }
    else
    {
        // erase nChars characters after initialChar (included):
        ret.erase(initialChar, nChars+1);

        // if there is space for the replacement dots, add them
        if (maxFinalWidth > replacementWidth)
            ret.insert(initialChar, wxELLIPSE_REPLACEMENT);
    }

    // if everything was ok, we should have shortened this line
    // enough to make it fit in maxFinalWidth:
    wxASSERT(dc.GetTextExtent(ret).GetWidth() < maxFinalWidth);

    return ret;
}
Example #5
0
/* static and protected */
wxString wxControlBase::DoEllipsizeSingleLine(const wxString& curLine, const wxDC& dc,
                                              wxEllipsizeMode mode, int maxFinalWidthPx,
                                              int replacementWidthPx, int marginWidthPx)
{
    wxASSERT_MSG(replacementWidthPx > 0 && marginWidthPx > 0,
                 "Invalid parameters");
    wxASSERT_LEVEL_2_MSG(!curLine.Contains('\n'),
                         "Use Ellipsize() instead!");

    wxASSERT_MSG( mode != wxELLIPSIZE_NONE, "shouldn't be called at all then" );

    // NOTE: this function assumes that any mnemonic/tab character has already
    //       been handled if it was necessary to handle them (see Ellipsize())

    if (maxFinalWidthPx <= 0)
        return wxEmptyString;

    wxArrayInt charOffsetsPx;
    size_t len = curLine.length();
    if (len == 0 ||
        !dc.GetPartialTextExtents(curLine, charOffsetsPx))
        return curLine;

    wxASSERT(charOffsetsPx.GetCount() == len);

    // NOTE: charOffsetsPx[n] is the width in pixels of the first n characters (with the last one INCLUDED)
    //       thus charOffsetsPx[len-1] is the total width of the string
    size_t totalWidthPx = charOffsetsPx.Last();
    if ( totalWidthPx <= (size_t)maxFinalWidthPx )
        return curLine;     // we don't need to do any ellipsization!

    int excessPx = wxMin(totalWidthPx - maxFinalWidthPx +
                         replacementWidthPx +
                         marginWidthPx,     // security margin
                         totalWidthPx);
    wxASSERT(excessPx>0);       // excessPx should be in the [1;totalWidthPx] range

    // REMEMBER: indexes inside the string have a valid range of [0;len-1] if not otherwise constrained
    //           lengths/counts of characters (e.g. nCharsToRemove) have a valid range of [0;len] if not otherwise constrained
    // NOTE: since this point we know we have for sure a non-empty string from which we need
    //       to remove _at least_ one character (thus nCharsToRemove below is constrained to be >= 1)

    size_t initialCharToRemove,     // index of first character to erase, valid range is [0;len-1]
           nCharsToRemove;          // how many chars do we need to erase? valid range is [1;len-initialCharToRemove]

    // let's compute the range of characters to remove depending on the ellipsization mode:
    switch (mode)
    {
        case wxELLIPSIZE_START:
            initialCharToRemove = 0;
            for ( nCharsToRemove = 1;
                  nCharsToRemove < len && charOffsetsPx[nCharsToRemove-1] < excessPx;
                  nCharsToRemove++ )
                ;
            break;

        case wxELLIPSIZE_MIDDLE:
            {
                // NOTE: the following piece of code works also when len == 1

                // start the removal process from the middle of the string
                // i.e. separe the string in three parts: 
                // - the first one to preserve, valid range [0;initialCharToRemove-1] or the empty range if initialCharToRemove==0
                // - the second one to remove, valid range [initialCharToRemove;endCharToRemove]
                // - the third one to preserve, valid range [endCharToRemove+1;len-1] or the empty range if endCharToRemove==len-1
                // NOTE: empty range != range [0;0] since the range [0;0] contains 1 character (the zero-th one)!
                initialCharToRemove = len/2;
                size_t endCharToRemove = len/2;     // index of the last character to remove; valid range is [0;len-1]

                int removedPx = 0;
                for ( ; removedPx < excessPx; )
                {
                    // try to remove the last character of the first part of the string
                    if (initialCharToRemove > 0)
                    {
                        // width of the (initialCharToRemove-1)-th character
                        int widthPx;
                        if (initialCharToRemove >= 2)
                            widthPx = charOffsetsPx[initialCharToRemove-1] - charOffsetsPx[initialCharToRemove-2];
                        else
                            widthPx = charOffsetsPx[initialCharToRemove-1];     
                                // the (initialCharToRemove-1)-th character is the first char of the string
                        
                        wxASSERT(widthPx >= 0);     // widthPx is zero for e.g. tab characters

                        // mark the (initialCharToRemove-1)-th character as removable
                        initialCharToRemove--;
                        removedPx += widthPx;
                    }

                    // try to remove the first character of the last part of the string
                    if (endCharToRemove < len - 1 &&
                        removedPx < excessPx)
                    {
                        // width of the (endCharToRemove+1)-th character
                        int widthPx = charOffsetsPx[endCharToRemove+1] -
                                      charOffsetsPx[endCharToRemove];

                        wxASSERT(widthPx >= 0);     // widthPx is zero for e.g. tab characters

                        // mark the (endCharToRemove+1)-th character as removable
                        endCharToRemove++;
                        removedPx += widthPx;
                    }

                    if (initialCharToRemove == 0 && endCharToRemove == len-1)
                    {
                        // we need to remove all the characters of the string!
                        break;
                    }
                }

                nCharsToRemove = endCharToRemove - initialCharToRemove + 1;
            }
            break;

        case wxELLIPSIZE_END:
            {
                int maxWidthPx = totalWidthPx - excessPx;

                // go backward from the end of the string toward the start
                for ( initialCharToRemove = len-1;
                      initialCharToRemove > 0 && charOffsetsPx[initialCharToRemove-1] > maxWidthPx;
                      initialCharToRemove-- )
                    ;
                nCharsToRemove = len - initialCharToRemove;
            }
            break;

        case wxELLIPSIZE_NONE:
        default:
            wxFAIL_MSG("invalid ellipsize mode");
            return curLine;
    }

#ifdef __VMS
#pragma message disable unscomzer
   // suppress warnings on comparison of unsigned numbers
#endif
   wxASSERT(initialCharToRemove >= 0 && initialCharToRemove <= len-1);  // see valid range for initialCharToRemove above
#ifdef __VMS
#pragma message enable unscomzer
   // suppress warnings on comparison of unsigned numbers
#endif
    wxASSERT(nCharsToRemove >= 1 && nCharsToRemove <= len-initialCharToRemove);  // see valid range for nCharsToRemove above

    // erase nCharsToRemove characters after initialCharToRemove (included);
    // e.g. if we have the string "foobar" (len = 6)
    //                               ^
    //                               \--- initialCharToRemove = 2
    //      and nCharsToRemove = 2, then we get "foar"
    wxString ret(curLine);
    ret.erase(initialCharToRemove, nCharsToRemove);

    int removedPx;
    if (initialCharToRemove >= 1)
        removedPx = charOffsetsPx[initialCharToRemove+nCharsToRemove-1] - charOffsetsPx[initialCharToRemove-1];
    else 
        removedPx = charOffsetsPx[initialCharToRemove+nCharsToRemove-1];
    wxASSERT(removedPx >= excessPx);

    // if there is space for the replacement dots, add them
    if ((int)totalWidthPx-removedPx+replacementWidthPx < maxFinalWidthPx)
        ret.insert(initialCharToRemove, wxELLIPSE_REPLACEMENT);

    // if everything was ok, we should have shortened this line
    // enough to make it fit in maxFinalWidthPx:
    wxASSERT_LEVEL_2(dc.GetTextExtent(ret).GetWidth() <= maxFinalWidthPx);

    return ret;
}
// Splits m_Word into up to three parts according to selection, returns
// substring before, in and after selection and the points (in relative coords)
// where s2 and s3 start:
void wxHtmlWordCell::Split(const wxDC& dc,
                           const wxPoint& selFrom, const wxPoint& selTo,
                           unsigned& pos1, unsigned& pos2) const
{
    wxPoint pt1 = (selFrom == wxDefaultPosition) ?
                  wxDefaultPosition : selFrom - GetAbsPos();
    wxPoint pt2 = (selTo == wxDefaultPosition) ?
                  wxPoint(m_Width, wxDefaultCoord) : selTo - GetAbsPos();

    // if the selection is entirely within this cell, make sure pt1 < pt2 in
    // order to make the rest of this function simpler:
    if ( selFrom != wxDefaultPosition && selTo != wxDefaultPosition &&
            selFrom.x > selTo.x )
    {
        wxPoint tmp = pt1;
        pt1 = pt2;
        pt2 = tmp;
    }

    unsigned len = m_Word.length();
    unsigned i = 0;
    pos1 = 0;

    // adjust for cases when the start/end position is completely
    // outside the cell:
    if ( pt1.y < 0 )
        pt1.x = 0;
    if ( pt2.y >= m_Height )
        pt2.x = m_Width;

    // before selection:
    // (include character under caret only if in first half of width)
#ifdef __WXMAC__
    // implementation using PartialExtents to support fractional widths
    wxArrayInt widths ;
    dc.GetPartialTextExtents(m_Word,widths) ;
    while( i < len && pt1.x >= widths[i] )
        i++ ;
    if ( i < len )
    {
        int charW = (i > 0) ? widths[i] - widths[i-1] : widths[i];
        if ( widths[i] - pt1.x < charW/2 )
            i++;
    }
#else // !__WXMAC__
    wxCoord charW, charH;
    while ( pt1.x > 0 && i < len )
    {
        dc.GetTextExtent(m_Word[i], &charW, &charH);
        pt1.x -= charW;
        if ( pt1.x >= -charW/2 )
        {
            pos1 += charW;
            i++;
        }
    }
#endif // __WXMAC__/!__WXMAC__

    // in selection:
    // (include character under caret only if in first half of width)
    unsigned j = i;
#ifdef __WXMAC__
    while( j < len && pt2.x >= widths[j] )
        j++ ;
    if ( j < len )
    {
        int charW = (j > 0) ? widths[j] - widths[j-1] : widths[j];
        if ( widths[j] - pt2.x < charW/2 )
            j++;
    }
#else // !__WXMAC__
    pos2 = pos1;
    pt2.x -= pos2;
    while ( pt2.x > 0 && j < len )
    {
        dc.GetTextExtent(m_Word[j], &charW, &charH);
        pt2.x -= charW;
        if ( pt2.x >= -charW/2 )
        {
            pos2 += charW;
            j++;
        }
    }
#endif // __WXMAC__/!__WXMAC__

    pos1 = i;
    pos2 = j;

    wxASSERT( pos2 >= pos1 );
}
Example #7
0
void SurfaceImpl::MeasureWidths(Font &font, const char *s, int len, int *positions) {

    wxString str = sci2wx(s, len);
    SetFont(font);

#if !wxCHECK_VERSION(2, 5, 0)
#ifndef __WXMAC__
    // Calculate the position of each character based on the widths of
    // the previous characters
    int* tpos = new int[len+1];
    int totalWidth = 0;
    size_t i;
    for (i=0; i<str.Length(); i++) {
        int w, h;
        hdc->GetTextExtent(str[i], &w, &h);
        totalWidth += w;
        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+1];
    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
#else
    wxArrayInt tpos;
    hdc->GetPartialTextExtents(str, tpos);
#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!
    int j = 0;
    size_t ui = 0;
    while ((int)j < len) {
        unsigned char uch = (unsigned char)s[j];
        positions[j++] = tpos[ui];
        if (uch >= 0x80) {
            if (uch < (0x80 + 0x40 + 0x20)) {
                positions[j++] = tpos[ui];
            } else {
                positions[j++] = tpos[ui];
                positions[j++] = tpos[ui];
            }
        }
        ui++;
    }
#else

    // If not unicode then just use the widths we have
#if !wxCHECK_VERSION(2, 5, 0)
    memcpy(positions, tpos, len * sizeof(*tpos));
#else
#if wxUSE_STL
    std::copy(tpos.begin(), tpos.end(), positions);
#else
    memcpy(positions, tpos.begin(), len * sizeof(int));
#endif
#endif
#endif

#if !wxCHECK_VERSION(2, 5, 0)
    delete [] tpos;
#endif
}