void WatcherData::updatePaths()
{
    // printf("updating paths...\n");
    {
        std::lock_guard<std::mutex> updateLocker(updateMutex);
        handleToPath.clear();
        pathToHandle.clear();
        pathData.clear();
    }
    for (HANDLE& h : changes) {
        //printf("closing %d\n", h);
        FindCloseChangeNotification(h);
    }
    changes.clear();

    std::lock_guard<std::mutex> locker(changeMutex);
    for(const Path& path : paths) {
#ifdef HAVE_CYGWIN
        const ssize_t len = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path.constData(), 0, 0);
        //printf("win path size %d\n", len);
        String winPath(len, '\0');
        cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path.constData(), winPath.data(), winPath.size());
        //printf("hello %s\n", winPath.constData());
        const HANDLE h = FindFirstChangeNotification(winPath.constData(), TRUE,
                                                     FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE);
#else
        const HANDLE h = FindFirstChangeNotification(path.constData(), TRUE,
                                                     FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE);
#endif
        if (h == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "Unable to watch: %lu (%s)\n",
                    static_cast<unsigned long>(GetLastError()), path.constData());
        } else {
            changes.push_back(h);

            std::lock_guard<std::mutex> updateLocker(updateMutex);
            handleToPath[h] = path;
            pathToHandle[path] = h;
            PathData& data = pathData[path];
            path.visit([&data](const Path &p) {
                    if (p.isFile()) {
                        data.modified[p] = p.lastModifiedMs();
                        return Path::Continue;
                    }
                    return Path::Recurse;
                });
        }
    }
}
Esempio n. 2
0
/**
 *  \brief Set the delay between each image in an animation
 */
void MythUIImage::SetDelay(int delayms)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_Delay = delayms;
    m_LastDisplay = QTime::currentTime();
    m_CurPos = 0;
}
Esempio n. 3
0
/**
 *  \brief Set the image filename pattern and integer range for an animated
 *         image, does not load the image. See Load()
 */
void MythUIImage::SetFilepattern(const QString &filepattern, int low,
                                 int high)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_Filename = filepattern;
    m_LowNum = low;
    m_HighNum = high;
}
Esempio n. 4
0
/**
 *  \brief Set the image filename, does not load the image. See Load()
 */
void MythUIImage::SetFilename(const QString &filename)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_imageProperties.isThemeImage = false;
    m_imageProperties.filename = filename;
    if (filename == m_OrigFilename)
        emit DependChanged(true);
    else
        emit DependChanged(false);
}
Esempio n. 5
0
/**
 *  \brief Set the image filename pattern and integer range for an animated
 *         image, does not load the image. See Load()
 */
void MythUIImage::SetFilepattern(const QString &filepattern, int low,
                                 int high)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_imageProperties.isThemeImage = false;
    m_imageProperties.filename = filepattern;
    m_LowNum = low;
    m_HighNum = high;
    if (filepattern == m_OrigFilename)
        emit DependChanged(true);
    else
        emit DependChanged(false);
}
Esempio n. 6
0
/**
 *  \brief Assign a set of MythImages to the widget for animation.
 *         Use is strongly discouraged, use SetFilepattern() instead.
 *
 */
void MythUIImage::SetImages(QVector<MythImage *> &images)
{
    Clear();

    QWriteLocker updateLocker(&d->m_UpdateLock);
    QSize aSize = GetArea().size();

    QVector<MythImage *>::iterator it;
    for (it = images.begin(); it != images.end(); ++it)
    {
        MythImage *im = (*it);
        if (!im)
        {
            QMutexLocker locker(&m_ImagesLock);
            m_Images[m_Images.size()] = im;
            continue;
        }

        im->UpRef();

        if (!m_ForceSize.isNull())
        {
            int w = (m_ForceSize.width() <= 0) ? im->width() : m_ForceSize.width();
            int h = (m_ForceSize.height() <= 0) ? im->height() : m_ForceSize.height();

            im->Resize(QSize(w, h), m_preserveAspect);
        }

        if (m_isReflected && !im->IsReflected())
            im->Reflect(m_reflectAxis, m_reflectShear, m_reflectScale,
                         m_reflectLength, m_reflectSpacing);

        if (m_isGreyscale && !im->isGrayscale())
            im->ToGreyscale();

        m_ImagesLock.lock();
        m_Images[m_Images.size()] = im;
        m_ImagesLock.unlock();

        aSize = aSize.expandedTo(im->size());
    }

    SetImageCount(1, m_Images.size());

    if (m_ForceSize.isNull())
        SetSize(aSize);

    m_CurPos = 0;
    SetRedraw();
}
Esempio n. 7
0
/**
 *  \brief Sets the delays between each image in an animation
 */
void MythUIImage::SetDelays(QVector<int> delays)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    QMutexLocker imageLocker(&m_ImagesLock);
    QVector<int>::iterator it;

    for (it = delays.begin(); it != delays.end(); ++it)
        m_Delays[m_Delays.size()] = *it;

    if (m_Delay == -1)
        m_Delay = m_Delays[0];

    m_LastDisplay = QTime::currentTime();
    m_CurPos = 0;
}
Esempio n. 8
0
/**
 *  \copydoc MythUIType::Pulse()
 */
void MythUIImage::Pulse(void)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);

    int delay = -1;
    if (m_Delays.contains(m_CurPos))
        delay = m_Delays[m_CurPos];
    else if (m_Delay > 0)
        delay = m_Delay;

    if (delay > 0 &&
        abs(m_LastDisplay.msecsTo(QTime::currentTime())) > delay)
    {
        m_ImagesLock.lock();

        if (m_animationCycle == kCycleStart)
        {
            ++m_CurPos;
            if (m_CurPos >= (uint)m_Images.size())
                m_CurPos = 0;
        }
        else if (m_animationCycle == kCycleReverse)
        {
            if ((m_CurPos + 1) >= (uint)m_Images.size())
            {
                m_animationReverse = true;
            }
            else if (m_CurPos == 0)
            {
                m_animationReverse = false;
            }

            if (m_animationReverse)
                --m_CurPos;
            else
                ++m_CurPos;
        }

        m_ImagesLock.unlock();

        SetRedraw();
        m_LastDisplay = QTime::currentTime();
    }

    MythUIType::Pulse();
}
Esempio n. 9
0
/**
 *  \brief Remove all images from the widget
 */
void MythUIImage::Clear(void)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    QMutexLocker locker(&m_ImagesLock);
    while (!m_Images.isEmpty())
    {
        QHash<int, MythImage*>::iterator it = m_Images.begin();
        if (*it)
            (*it)->DownRef();
        m_Images.remove(it.key());
    }
    m_Delays.clear();
    if (m_animatedImage)
    {
        m_LowNum = 0;
        m_HighNum = 0;
        m_animatedImage = false;
    }
}
Esempio n. 10
0
/**
 *  \brief Assign a MythImage to the widget. Use is strongly discouraged, use
 *         SetFilename() instead.
 */
void MythUIImage::SetImage(MythImage *img)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    if (!img)
    {
        Reset();
        return;
    }

    m_Filename = img->GetFileName();
    Clear();
    m_Delay = -1;

    img->UpRef();

    if (!m_ForceSize.isNull())
    {
        int w = (m_ForceSize.width() <= 0) ? img->width() : m_ForceSize.width();
        int h = (m_ForceSize.height() <= 0) ? img->height() : m_ForceSize.height();
        img->Resize(QSize(w, h), m_preserveAspect);
    }

    if (m_isReflected && !img->IsReflected())
        img->Reflect(m_reflectAxis, m_reflectShear, m_reflectScale,
                        m_reflectLength, m_reflectSpacing);

    if (m_isGreyscale && !img->isGrayscale())
        img->ToGreyscale();

    if (m_ForceSize.isNull())
        SetSize(img->size());

    m_ImagesLock.lock();
    m_Images[0] = img;
    m_Delays.clear();
    m_ImagesLock.unlock();

    m_CurPos = 0;
    SetRedraw();
}
Esempio n. 11
0
/**
 *  \brief Generates a unique identifying string for this image which is used
 *         as a key in the image cache.
 */
QString MythUIImage::GenImageLabel(const QString &filename, int w, int h) const
{
    QReadLocker updateLocker(&d->m_UpdateLock);
    QString imagelabel;
    QString s_Attrib;

    if (m_isMasked)
        s_Attrib = "masked";

    if (m_isReflected)
        s_Attrib += "reflected";

    if (m_isGreyscale)
        s_Attrib += "greyscale";

    imagelabel  = QString("%1-%2-%3x%4.png")
                          .arg(filename)
                          .arg(s_Attrib)
                          .arg(w)
                          .arg(h);
    imagelabel.replace('/','-');

    return imagelabel;
}
Esempio n. 12
0
/**
 *  \brief Set the integer range for an animated image pattern
 */
void MythUIImage::SetImageCount(int low, int high)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_LowNum = low;
    m_HighNum = high;
}
Esempio n. 13
0
/**
 *  \copydoc MythUIType::CreateCopy()
 */
void MythUIImage::CreateCopy(MythUIType *parent)
{
    QReadLocker updateLocker(&d->m_UpdateLock);
    MythUIImage *im = new MythUIImage(parent, objectName());
    im->CopyFrom(this);
}
Esempio n. 14
0
/**
 *  \copydoc MythUIType::ParseElement()
 */
bool MythUIImage::ParseElement(
    const QString &filename, QDomElement &element, bool showWarnings)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);

    if (element.tagName() == "filename")
    {
        m_imageProperties.isThemeImage = true; // This is an image distributed with the them
        m_OrigFilename = m_imageProperties.filename = getFirstText(element);

        if (m_imageProperties.filename.endsWith('/'))
        {
            m_showingRandomImage = true;
            m_imageDirectory = m_imageProperties.filename;

            FindRandomImage();
        }
    }
    else if (element.tagName() == "filepattern")
    {
        m_imageProperties.isThemeImage = true; // This is an image distributed with the theme
        m_OrigFilename = m_imageProperties.filename = getFirstText(element);
        QString tmp = element.attribute("low");

        if (!tmp.isEmpty())
            m_LowNum = tmp.toInt();

        tmp = element.attribute("high");

        if (!tmp.isEmpty())
            m_HighNum = tmp.toInt();

        tmp = element.attribute("cycle", "start");

        if (tmp == "reverse")
            m_animationCycle = kCycleReverse;
    }
    else if (element.tagName() == "area")
    {
        SetArea(parseRect(element));
        m_imageProperties.forceSize = m_Area.size();
    }
    else if (element.tagName() == "preserveaspect")
        m_imageProperties.preserveAspect = parseBool(element);
    else if (element.tagName() == "crop")
        m_imageProperties.cropRect = parseRect(element);
    else if (element.tagName() == "delay")
    {
        QString value = getFirstText(element);

        if (value.contains(","))
        {
            QVector<int> delays;
            QStringList tokens = value.split(",");
            QStringList::iterator it = tokens.begin();

            for (; it != tokens.end(); ++it)
            {
                if ((*it).isEmpty())
                {
                    if (delays.size())
                        delays.append(delays[delays.size()-1]);
                    else
                        delays.append(0); // Default 0ms delay before first image
                }
                else
                {
                    delays.append((*it).toInt());
                }
            }

            if (delays.size())
            {
                m_Delay = delays[0];
                SetDelays(delays);
            }
        }
        else
        {
            m_Delay = value.toInt();
        }
    }
    else if (element.tagName() == "reflection")
    {
        m_imageProperties.isReflected = true;
        QString tmp = element.attribute("axis");

        if (!tmp.isEmpty())
        {
            if (tmp.toLower() == "horizontal")
                m_imageProperties.reflectAxis = ReflectHorizontal;
            else
                m_imageProperties.reflectAxis = ReflectVertical;
        }

        tmp = element.attribute("shear");

        if (!tmp.isEmpty())
            m_imageProperties.reflectShear = tmp.toInt();

        tmp = element.attribute("scale");

        if (!tmp.isEmpty())
            m_imageProperties.reflectScale = tmp.toInt();

        tmp = element.attribute("length");

        if (!tmp.isEmpty())
            m_imageProperties.reflectLength = tmp.toInt();

        tmp = element.attribute("spacing");

        if (!tmp.isEmpty())
            m_imageProperties.reflectSpacing = tmp.toInt();
    }
    else if (element.tagName() == "mask")
    {
        QString maskfile = getFirstText(element);

        MythImage *newMaskImage = GetPainter()->GetFormatImage();
        if (newMaskImage->Load(maskfile))
        {
            float wmult; // Width multipler
            float hmult; // Height multipler
            GetMythUI()->GetScreenSettings(wmult, hmult);
            if (wmult != 1.0f || hmult != 1.0f)
            {
                int width = newMaskImage->size().width() * wmult;
                int height = newMaskImage->size().height() * hmult;
                newMaskImage->Resize(QSize(width, height));
            }

            m_imageProperties.SetMaskImage(newMaskImage);
        }
        else
            m_imageProperties.SetMaskImage(NULL);
        newMaskImage->DecrRef();
    }
    else if (element.tagName() == "grayscale" ||
             element.tagName() == "greyscale")
    {
        m_imageProperties.isGreyscale = parseBool(element);
    }
    else
    {
        return MythUIType::ParseElement(filename, element, showWarnings);
    }

    m_NeedLoad = true;

    if (m_Parent && m_Parent->IsDeferredLoading(true))
        m_NeedLoad = false;

    return true;
}
Esempio n. 15
0
/**
 *  \brief Set the size of the widget
 */
void MythUIImage::SetSize(const QSize &size)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    MythUIType::SetSize(size);
    m_NeedLoad = true;
}
Esempio n. 16
0
/**
 *  \brief Generates a unique identifying string for this image which is used
 *         as a key in the image cache.
 */
QString MythUIImage::GenImageLabel(int w, int h) const
{
    QReadLocker updateLocker(&d->m_UpdateLock);
    return GenImageLabel(m_Filename, w, h);
}
Esempio n. 17
0
/**
 *  \brief Set the image filename, does not load the image. See Load()
 */
void MythUIImage::SetFilename(const QString &filename)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_Filename = filename;
}
Esempio n. 18
0
/**
 *  \brief Assign a set of MythImages to the widget for animation.
 *         Use is strongly discouraged, use SetFilepattern() instead.
 *
 */
void MythUIImage::SetImages(QVector<MythImage *> *images)
{
    Clear();

    QWriteLocker updateLocker(&d->m_UpdateLock);
    QSize aSize = GetFullArea().size();

    m_imageProperties.isThemeImage = false;

    QVector<MythImage *>::iterator it;

    for (it = images->begin(); it != images->end(); ++it)
    {
        MythImage *im = (*it);

        if (!im)
        {
            QMutexLocker locker(&m_ImagesLock);
            m_Images[m_Images.size()] = im;
            continue;
        }

        im->IncrRef();


        QSize forceSize = m_imageProperties.forceSize;
        if (!forceSize.isNull())
        {
            int w = (forceSize.width() <= 0) ? im->width() : forceSize.width();
            int h = (forceSize.height() <= 0) ? im->height() : forceSize.height();
            im->Resize(QSize(w, h), m_imageProperties.preserveAspect);
        }

        if (m_imageProperties.isReflected && !im->IsReflected())
            im->Reflect(m_imageProperties.reflectAxis,
                        m_imageProperties.reflectShear,
                        m_imageProperties.reflectScale,
                        m_imageProperties.reflectLength,
                        m_imageProperties.reflectSpacing);

        if (m_imageProperties.isGreyscale && !im->isGrayscale())
            im->ToGreyscale();

        if (m_imageProperties.isOriented && !im->IsOriented() &&
            (m_imageProperties.orientation >= 1 &&
             m_imageProperties.orientation <= 8))
            im->Orientation(m_imageProperties.orientation);

        m_ImagesLock.lock();
        m_Images[m_Images.size()] = im;
        m_ImagesLock.unlock();

        aSize = aSize.expandedTo(im->size());
    }

    SetImageCount(1, m_Images.size());

    if (m_imageProperties.forceSize.isNull())
        SetSize(aSize);

    MythRect rect(GetFullArea());
    rect.setSize(aSize);
    SetMinArea(rect);

    m_CurPos = 0;
    m_animatedImage = true;
    m_Initiator = m_EnableInitiator;
    SetRedraw();
}
Esempio n. 19
0
void WatcherData::run()
{
    for (;;) {
        if (hasChanged()) {
            slices.clear();
            updatePaths();

            auto where = changes.begin();
            const auto end = changes.end();
            while (where != end) {
                auto to = where + MAXIMUM_WAIT_OBJECTS - 1; // - 1 since we want a wakeup event as well
                if (to > end)
                    to = end;
                slices.push_back(std::unique_ptr<WatcherSlice>(new WatcherSlice(where, to,
                                                                                std::bind(&WatcherData::updated, this,
                                                                                          std::placeholders::_1),
                                                                                handleToPath)));
                where = to;
            }
        }
        const DWORD res = WaitForSingleObject(wakeupHandle, INFINITE);
        if (res == WAIT_FAILED) {
            fprintf(stderr, "Wait failed in WatcherData::run() %lu\n",
                    static_cast<unsigned long>(GetLastError()));
            break;
        }
        assert(res - WAIT_OBJECT_0 == 0);
        // woken up
        //printf("!!!Woken up\n");
        std::lock_guard<std::mutex> changeLocker(changeMutex);
        if (stopped) {
            //printf("!!!! Stopped?\n");
            break;
        }
        std::lock_guard<std::mutex> updateLocker(updateMutex);
        if (!changedPaths.empty()) {
            for (const Path& p : changedPaths) {
                //printf("path was modified... %s\n", p.constData());
                PathData& data = pathData[p];
                p.visit([&data](const Path &pp) {
                        if (pp.isFile()) {
                            //printf("updateDir %s\n", p.constData());
                            const auto modif = data.modified.find(pp);
                            if (modif == data.modified.end()) {
                                //printf("added\n");
                                // new file
                                data.added.insert(pp);
                                return Path::Continue;
                            }
                            data.seen.insert(pp);
                            // possibly modified file
                            if (pp.lastModifiedMs() != modif->second) {
                                //printf("modified\n");
                                // really modified
                                data.changed.insert(pp);
                            }
                            return Path::Continue;
                        }
                        return Path::Recurse;
                    });

                Set<Path> removed;
                // calculate the removed files (modified - seen)
                const auto send = data.seen.end();
                for (const std::pair<Path, uint64_t>& mod : data.modified) {
                    if (data.seen.find(mod.first) == send) {
                        removed.insert(mod.first);
                    } else {
                        // update to our new time
                        data.modified[mod.first] = mod.first.lastModifiedMs();
                    }
                }

                // update the modified structure
                for (const Path& ap : data.added) {
                    data.modified[ap] = ap.lastModifiedMs();
                }
                for (const Path& rp : removed) {
                    data.modified.erase(rp);
                }

                //printf("hei, removed %u, added %u, changed %u\n", removed.size(), data.added.size(), data.changed.size());
                if (!removed.empty())
                    EventLoop::mainEventLoop()->callLaterMove(std::bind(&FileSystemWatcher::pathsRemoved, watcher, std::placeholders::_1), std::move(removed));
                if (!data.added.empty())
                    EventLoop::mainEventLoop()->callLaterMove(std::bind(&FileSystemWatcher::pathsAdded, watcher, std::placeholders::_1), std::move(data.added));
                if (!data.changed.empty())
                    EventLoop::mainEventLoop()->callLaterMove(std::bind(&FileSystemWatcher::pathsModified, watcher, std::placeholders::_1), std::move(data.changed));

                data.added.clear();
                data.changed.clear();
                data.seen.clear();
            }
            changedPaths.clear();
        }
    }
    slices.clear();
}
Esempio n. 20
0
/**
 *  \brief Crop the image using the given rectangle, useful for removing
 *         unsightly edges from imported images or zoom effects
 */
void MythUIImage::SetCropRect(const MythRect &rect)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    m_imageProperties.cropRect = rect;
    SetRedraw();
}
Esempio n. 21
0
/**
 *  \copydoc MythUIType::ParseElement()
 */
bool MythUIImage::ParseElement(
    const QString &filename, QDomElement &element, bool showWarnings)
{
    QWriteLocker updateLocker(&d->m_UpdateLock);
    if (element.tagName() == "filename")
    {
        m_OrigFilename = m_Filename = getFirstText(element);
        if (m_Filename.endsWith('/'))
        {
            QDir imageDir(m_Filename);
            if (!imageDir.exists())
            {
                QString themeDir = GetMythUI()->GetThemeDir() + '/';
                imageDir = themeDir + m_Filename;
            }
            QStringList imageTypes;

            QList< QByteArray > exts = QImageReader::supportedImageFormats();
            QList< QByteArray >::Iterator it = exts.begin();
            for (;it != exts.end();++it)
            {
                imageTypes.append( QString("*.").append(*it) );
            }

            imageDir.setNameFilters(imageTypes);

            QStringList imageList = imageDir.entryList();
            srand(time(NULL));
            QString randFile;
            if (imageList.size())
                randFile = QString("%1%2").arg(m_Filename)
                           .arg(imageList.takeAt(rand() % imageList.size()));
            m_OrigFilename = m_Filename = randFile;
        }
    }
    else if (element.tagName() == "filepattern")
    {
        m_OrigFilename = m_Filename = getFirstText(element);
        QString tmp = element.attribute("low");
        if (!tmp.isEmpty())
            m_LowNum = tmp.toInt();
        tmp = element.attribute("high");
        if (!tmp.isEmpty())
            m_HighNum = tmp.toInt();
        tmp = element.attribute("cycle", "start");
        if (tmp == "reverse")
            m_animationCycle = kCycleReverse;
    }
    else if (element.tagName() == "area")
    {
        SetArea(parseRect(element));
        m_ForceSize = m_Area.size();
    }
    else if (element.tagName() == "preserveaspect")
        m_preserveAspect = parseBool(element);
    else if (element.tagName() == "crop")
        m_cropRect = parseRect(element);
    else if (element.tagName() == "delay")
    {
        QString value = getFirstText(element);
        if (value.contains(","))
        {
            QVector<int> delays;
            QStringList tokens = value.split(",");
            QStringList::iterator it = tokens.begin();
            for (; it != tokens.end(); ++it)
            {
                if ((*it).isEmpty())
                {
                    if (delays.size())
                        delays.append(delays[delays.size()-1]);
                    else
                        delays.append(0); // Default 0ms delay before first image
                }
                else
                {
                    delays.append((*it).toInt());
                }
            }

            if (delays.size())
            {
                m_Delay = delays[0];
                SetDelays(delays);
            }
        }
        else
        {
            m_Delay = value.toInt();
        }
    }
    else if (element.tagName() == "reflection")
    {
        m_isReflected = true;
        QString tmp = element.attribute("axis");
        if (!tmp.isEmpty())
        {
            if (tmp.toLower() == "horizontal")
                m_reflectAxis = ReflectHorizontal;
            else
                m_reflectAxis = ReflectVertical;
        }
        tmp = element.attribute("shear");
        if (!tmp.isEmpty())
            m_reflectShear = tmp.toInt();
        tmp = element.attribute("scale");
        if (!tmp.isEmpty())
            m_reflectScale = tmp.toInt();
        tmp = element.attribute("length");
        if (!tmp.isEmpty())
            m_reflectLength = tmp.toInt();
        tmp = element.attribute("spacing");
        if (!tmp.isEmpty())
            m_reflectSpacing = tmp.toInt();
    }
    else if (element.tagName() == "mask")
    {
        QString maskfile = getFirstText(element);
        if (m_maskImage)
        {
            m_maskImage->DownRef();
            m_maskImage = NULL;
        }

        m_maskImage = GetPainter()->GetFormatImage();
        m_maskImage->UpRef();
        if (m_maskImage->Load(maskfile))
            m_isMasked = true;
        else
        {
            m_maskImage->DownRef();
            m_maskImage = NULL;
            m_isMasked = false;
        }
    }
    else if (element.tagName() == "grayscale" ||
             element.tagName() == "greyscale")
    {
        m_isGreyscale = parseBool(element);
    }
    else
    {
        return MythUIType::ParseElement(filename, element, showWarnings);
    }

    m_NeedLoad = true;

    if (m_Parent && m_Parent->IsDeferredLoading(true))
        m_NeedLoad = false;

    return true;
}