Пример #1
0
// Return the colour, looking up in the palette if necessary.  Used by the sub-classes
MHRgba MHVisible::GetColour(const MHColour &colour)
{
    int red = 0, green = 0, blue = 0, alpha = 0;
    int cSize = colour.m_ColStr.Size();

    if (cSize != 4)
    {
        MHLOG(MHLogWarning, QString("Colour string has length %1 not 4.").arg(cSize));
    }

    // Just in case the length is short we handle those properly.
    if (cSize > 0)
    {
        red = colour.m_ColStr.GetAt(0);
    }

    if (cSize > 1)
    {
        green = colour.m_ColStr.GetAt(1);
    }

    if (cSize > 2)
    {
        blue = colour.m_ColStr.GetAt(2);
    }

    if (cSize > 3)
    {
        alpha = 255 - colour.m_ColStr.GetAt(3);    // Convert transparency to alpha
    }

    return MHRgba(red, green, blue, alpha);
}
Пример #2
0
MHTextItem::MHTextItem()
{
    m_nUnicode = 0;
    m_Width = 0; // Size of this block
    m_Colour = MHRgba(0, 0, 0, 255);
    m_nTabCount = 0;
}
Пример #3
0
// Fill in the background.  This is only called if there is some area of
// the screen that is not covered with other visibles.
void MHIContext::DrawBackground(const QRegion &reg)
{
    if (reg.isEmpty())
        return;

    QRect bounds = reg.boundingRect();
    DrawRect(bounds.x(), bounds.y(), bounds.width(), bounds.height(),
             MHRgba(0, 0, 0, 255)/* black. */);
}
Пример #4
0
// Reset the drawing.
void MHIDLA::Clear()
{
    if (m_width == 0 || m_height == 0)
    {
        m_image = QImage();
        return;
    }
    m_image = QImage(m_width, m_height, QImage::Format_ARGB32);
    // Fill the image with "transparent colour".
    DrawRect(0, 0, m_width, m_height, MHRgba(0, 0, 0, 0));
}
Пример #5
0
// Recreate the image.
void MHText::Redraw()
{
    if (! m_fRunning || !m_pDisplay)
    {
        return;
    }

    if (m_nBoxWidth == 0 || m_nBoxHeight == 0)
    {
        return;    // Can't draw zero sized boxes.
    }

    m_pDisplay->SetSize(m_nBoxWidth, m_nBoxHeight);
    m_pDisplay->Clear();

    MHRgba textColour = GetColour(m_textColour);
    // Process any escapes in the text and construct the text arrays.
    MHSequence <MHTextLine *> theText;
    // Set up the first item on the first line.
    MHTextItem *pCurrItem = new MHTextItem;
    MHTextLine *pCurrLine = new MHTextLine;
    pCurrLine->m_Items.Append(pCurrItem);
    theText.Append(pCurrLine);
    MHStack <MHRgba> m_ColourStack; // Stack to handle nested colour codes.
    m_ColourStack.Push(textColour);
    pCurrItem->m_Colour = textColour;

//  FILE *fd=stdout; fprintf(fd, "Redraw Text "); m_Content.PrintMe(fd, 0); fprintf(fd, "\n");
    int i = 0;

    while (i < m_Content.Size())
    {
        unsigned char ch = m_Content.GetAt(i++);

        if (ch == 0x09) // Tab - start a new item if we have any text in the existing one.
        {
            if (pCurrItem->m_Text.Size() != 0)
            {
                pCurrItem = pCurrItem->NewItem();
                pCurrLine->m_Items.Append(pCurrItem);
            }
            if (m_HorizJ == Start)
                pCurrItem->m_nTabCount++;
        }

        else if (ch == 0x0d)    // CR - line break.
        {
            // TODO: Two CRs next to one another are treated as </P> rather than <BR><BR>
            // This should also include the sequence CRLFCRLF.
            pCurrLine = new MHTextLine;
            theText.Append(pCurrLine);
            pCurrItem = pCurrItem->NewItem();
            pCurrLine->m_Items.Append(pCurrItem);
        }

        else if (ch == 0x1b)   // Escape - special codes.
        {
            if (i == m_Content.Size())
            {
                break;
            }

            unsigned char code = m_Content.GetAt(i);
            // The only codes we are interested in are the start and end of colour.
            // TODO: We may also need "bold" and some hypertext colours.

            if (code >= 0x40 && code <= 0x5e)   // Start code
            {
                // Start codes are followed by a parameter count and a number of parameter bytes.
                if (++i == m_Content.Size())
                {
                    break;
                }

                unsigned char paramCount = m_Content.GetAt(i);
                i++;

                if (code == 0x43 && paramCount == 4 && i + paramCount <= m_Content.Size())
                {
                    // Start of colour.
                    if (pCurrItem->m_Text.Size() != 0)
                    {
                        pCurrItem = pCurrItem->NewItem();
                        pCurrLine->m_Items.Append(pCurrItem);
                    }

                    pCurrItem->m_Colour = MHRgba(m_Content.GetAt(i), m_Content.GetAt(i + 1),
                                                 m_Content.GetAt(i + 2), 255 - m_Content.GetAt(i + 3));
                    // Push this colour onto the colour stack.
                    m_ColourStack.Push(pCurrItem->m_Colour);
                }
                else
                {
                    MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code, 2, 16));
                }

                i += paramCount; // Skip the parameters
            }
            else if (code >= 0x60 && code <= 0x7e)   // End code.
            {
                i++;

                if (code == 0x63)
                {
                    if (m_ColourStack.Size() > 1)
                    {
                        m_ColourStack.Pop();

                        // Start a new item since we're using a new colour.
                        if (pCurrItem->m_Text.Size() != 0)
                        {
                            pCurrItem = pCurrItem->NewItem();
                            pCurrLine->m_Items.Append(pCurrItem);
                        }

                        // Set the subsequent text in the colour we're using now.
                        pCurrItem->m_Colour = m_ColourStack.Top();
                    }
                }
                else MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code,2,16));
            }
            else MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code,2,16));
        }

        else if (ch <= 0x1f)
        {
            // Certain characters including LF and the marker codes between 0x1c and 0x1f are
            // explicitly intended to be ignored.  Include all the other codes.
        }

        else   // Add to the current text.
        {
            int nStart = i - 1;

            while (i < m_Content.Size() && m_Content.GetAt(i) >= 0x20)
            {
                i++;
            }

            pCurrItem->m_Text.Append(MHOctetString(m_Content, nStart, i - nStart));
        }
    }

    // Set up the initial attributes.
    int style, size, lineSpace, letterSpace;
    InterpretAttributes(m_fontAttrs, style, size, lineSpace, letterSpace);
    // Create a font with this information.
    m_pDisplay->SetFont(size, (style & 2) != 0, (style & 1) != 0);

    // Calculate the layout of each section.
    for (i = 0; i < theText.Size(); i++)
    {
        MHTextLine *pLine = theText.GetAt(i);
        pLine->m_nLineWidth = 0;

        for (int j = 0; j < pLine->m_Items.Size(); j++)
        {
            MHTextItem *pItem = pLine->m_Items.GetAt(j);

            // Set any tabs.
            pLine->m_nLineWidth = Tabs(pLine->m_nLineWidth, pItem->m_nTabCount);

            if (pItem->m_Unicode.isEmpty())   // Convert UTF-8 to Unicode.
            {
                int s = pItem->m_Text.Size();
                pItem->m_Unicode = QString::fromUtf8((const char *)pItem->m_Text.Bytes(), s);
                pItem->m_nUnicode = pItem->m_Unicode.length();
            }

            // Fit the text onto the line.
            int nFullText = pItem->m_nUnicode;
            // Get the box size and update pItem->m_nUnicode to the number that will fit.
            QRect rect = m_pDisplay->GetBounds(pItem->m_Unicode, pItem->m_nUnicode, m_nBoxWidth - pLine->m_nLineWidth);

            if (nFullText != pItem->m_nUnicode && m_fTextWrap)   // Doesn't fit, we have to word-wrap.
            {
                int nTruncated = pItem->m_nUnicode; // Just in case.
                // Now remove characters until we find a word-break character.
                while (pItem->m_nUnicode > 0 && pItem->m_Unicode[pItem->m_nUnicode] != ' ')
                {
                    pItem->m_nUnicode--;
                }

                // If there are now word-break characters we truncate the text.
                if (pItem->m_nUnicode == 0)
                {
                    pItem->m_nUnicode = nTruncated;
                }

                // Special case to avoid infinite loop if the box is very narrow.
                if (pItem->m_nUnicode == 0)
                {
                    pItem->m_nUnicode = 1;
                }

                // We need to move the text we've cut off this line into a new line.
                int nNewWidth = nFullText - pItem->m_nUnicode;
                int nNewStart = pItem->m_nUnicode;

                // Remove any spaces at the start of the new section.
                while (nNewWidth != 0 && pItem->m_Unicode[nNewStart] == ' ')
                {
                    nNewStart++;
                    nNewWidth--;
                }

                if (nNewWidth != 0)
                {
                    // Create a new line from the extra text.
                    MHTextLine *pNewLine = new MHTextLine;
                    theText.InsertAt(pNewLine, i + 1);
                    // The first item on the new line is the rest of the text.
                    MHTextItem *pNewItem = pItem->NewItem();
                    pNewLine->m_Items.Append(pNewItem);
                    pNewItem->m_Unicode = pItem->m_Unicode.mid(nNewStart, nNewWidth);
                    pNewItem->m_nUnicode = nNewWidth;

                    // Move any remaining items, e.g. in a different colour, from this line onto the new line.
                    while (pLine->m_Items.Size() > j + 1)
                    {
                        pNewLine->m_Items.Append(pLine->m_Items.GetAt(j + 1));
                        pLine->m_Items.RemoveAt(j + 1);
                    }
                }

                // Remove any spaces at the end of the old section.  If we don't do that and
                // we are centering or right aligning the text we'll get it wrong.
                while (pItem->m_nUnicode > 1 && pItem->m_Unicode[pItem->m_nUnicode-1] == ' ')
                {
                    pItem->m_nUnicode--;
                }

                rect = m_pDisplay->GetBounds(pItem->m_Unicode, pItem->m_nUnicode);
            }

            pItem->m_Width = rect.width();
            pLine->m_nLineWidth += rect.width();

            if (rect.height() > pLine->m_nLineHeight)
            {
                pLine->m_nLineHeight = rect.height();
            }

            if (rect.bottom() > pLine->m_nDescent)
            {
                pLine->m_nDescent = rect.bottom();
            }
        }
    }

    // Now output the text.
    int yOffset = 0;
    // If there isn't space for all the lines we should drop extra lines.
    int nNumLines = theText.Size();

    do
    {
        if (m_VertJ == End)
        {
            yOffset = m_nBoxHeight - nNumLines * lineSpace;
        }
        else if (m_VertJ == Centre)
        {
            yOffset = (m_nBoxHeight - nNumLines * lineSpace) / 2;
        }

        if (yOffset < 0)
        {
            nNumLines--;
        }
    }
    while (yOffset < 0);

    for (i = 0; i < nNumLines; i++)
    {
        MHTextLine *pLine = theText.GetAt(i);
        int xOffset = 0;

        if (m_HorizJ == End)
        {
            xOffset = m_nBoxWidth - pLine->m_nLineWidth;
        }
        else if (m_HorizJ == Centre)
        {
            xOffset = (m_nBoxWidth - pLine->m_nLineWidth) / 2;
        }

        for (int j = 0; j < pLine->m_Items.Size(); j++)
        {
            MHTextItem *pItem = pLine->m_Items.GetAt(j);

            // Tab across if necessary.
            xOffset = Tabs(xOffset, pItem->m_nTabCount);

            if (! pItem->m_Unicode.isEmpty())   // We may have blank lines.
            {
                m_pDisplay->AddText(xOffset, yOffset + (pLine->m_nLineHeight + lineSpace) / 2 - pLine->m_nDescent,
                                    pItem->m_Unicode.left(pItem->m_nUnicode), pItem->m_Colour);
            }

            xOffset += pItem->m_Width;
        }

        yOffset += lineSpace;

        if (yOffset + lineSpace > m_nBoxHeight)
        {
            break;
        }
    }

    // Clean up.
    for (int k = 0; k < theText.Size(); k++)
    {
        delete(theText.GetAt(k));
    }
}