<commit_before>/***************************************************************************
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <cfloat>
# include "InventorAll.h"
# include <QAction>
# include <QActionGroup>
# include <QApplication>
# include <QByteArray>
# include <QCursor>
# include <QList>
# include <QMenu>
# include <QMetaObject>
# include <QRegExp>
#endif

#include <Inventor/sensors/SoTimerSensor.h>

#include <App/Application.h>
#include "NavigationStyle.h"
#include "View3DInventorViewer.h"
#include "Application.h"
#include "MenuManager.h"
#include "MouseSelection.h"

using namespace Gui;

// ----------------------------------------------------------------------------------

/* TRANSLATOR Gui::BlenderNavigationStyle */

TYPESYSTEM_SOURCE(Gui::BlenderNavigationStyle, Gui::UserNavigationStyle);

BlenderNavigationStyle::BlenderNavigationStyle() : lockButton1(false)
{
}

BlenderNavigationStyle::~BlenderNavigationStyle()
{
}

const char* BlenderNavigationStyle::mouseButtons(ViewerMode mode)
{
    switch (mode) {
    case NavigationStyle::SELECTION:
        return QT_TR_NOOP("Press left mouse button");
    case NavigationStyle::PANNING:
        return QT_TR_NOOP("Press SHIFT and middle mouse button");
    case NavigationStyle::DRAGGING:
        return QT_TR_NOOP("Press middle mouse button");
    case NavigationStyle::ZOOMING:
        return QT_TR_NOOP("Scroll middle mouse button");
    default:
        return "No description";
    }
}

SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
{
    // Events when in "ready-to-seek" mode are ignored, except those
    // which influence the seek mode itself -- these are handled further
    // up the inheritance hierarchy.
    if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
    // Switch off viewing mode (Bug #0000911)
    if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
        this->setViewing(false); // by default disable viewing mode to render the scene

    const SoType type(ev->getTypeId());

    const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
    const SbVec2s size(vp.getViewportSizePixels());
    const SbVec2f prevnormalized = this->lastmouseposition;
    const SbVec2s pos(ev->getPosition());
    const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1),
                       (float) pos[1] / (float) std::max((int)(size[1] - 1), 1));

    this->lastmouseposition = posn;

    // Set to true if any event processing happened. Note that it is not
    // necessary to restrict ourselves to only do one "action" for an
    // event, we only need this flag to see if any processing happened
    // at all.
    SbBool processed = false;

    const ViewerMode curmode = this->currentmode;
    ViewerMode newmode = curmode;

    // Mismatches in state of the modifier keys happens if the user
    // presses or releases them outside the viewer window.
    if (this->ctrldown != ev->wasCtrlDown()) {
        this->ctrldown = ev->wasCtrlDown();
    }
    if (this->shiftdown != ev->wasShiftDown()) {
        this->shiftdown = ev->wasShiftDown();
    }
    if (this->altdown != ev->wasAltDown()) {
        this->altdown = ev->wasAltDown();
    }

    // give the nodes in the foreground root the chance to handle events (e.g color bar)
    if (!processed && !viewer->isEditing()) {
        processed = handleEventInForeground(ev);
        if (processed)
            return true;
    }

    // Keyboard handling
    if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
        const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
        switch (event->getKey()) {
        case SoKeyboardEvent::LEFT_CONTROL:
        case SoKeyboardEvent::RIGHT_CONTROL:
            this->ctrldown = press;
            break;
        case SoKeyboardEvent::LEFT_SHIFT:
        case SoKeyboardEvent::RIGHT_SHIFT:
            this->shiftdown = press;
            break;
        case SoKeyboardEvent::LEFT_ALT:
        case SoKeyboardEvent::RIGHT_ALT:
            this->altdown = press;
            break;
        case SoKeyboardEvent::H:
            processed = true;
            viewer->saveHomePosition();
            break;
        case SoKeyboardEvent::S:
        case SoKeyboardEvent::HOME:
        case SoKeyboardEvent::LEFT_ARROW:
        case SoKeyboardEvent::UP_ARROW:
        case SoKeyboardEvent::RIGHT_ARROW:
        case SoKeyboardEvent::DOWN_ARROW:
            if (!this->isViewing())
                this->setViewing(true);
            break;
        default:
            break;
        }
    }

    // Mouse Button / Spaceball Button handling
    if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
        const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
        const int button = event->getButton();
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;

        //SoDebugError::postInfo("processSoEvent", "button = %d", button);
        switch (button) {
        case SoMouseButtonEvent::BUTTON1:
            this->lockrecenter = true;
            this->button1down = press;
            if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
                newmode = NavigationStyle::SEEK_MODE;
                this->seekToPoint(pos); // implicitly calls interactiveCountInc()
                processed = true;
            }
            //else if (press && (this->currentmode == NavigationStyle::IDLE)) {
            //    this->setViewing(true);
            //    processed = true;
            //}
            else if (press && (this->currentmode == NavigationStyle::PANNING ||
                               this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
                processed = true;
            }
            // issue #0002433: avoid to swallow the UP event if down the
            // scene graph somewhere a dialog gets opened
            else if (press) {
                SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime());
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // a double-click?
                if (tmp.getValue() < dci) {
                    mouseDownConsumedEvent = *event;
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    processed = true;
                }
                else {
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    // 'ANY' is used to mark that we don't know yet if it will
                    // be a double-click event.
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            else if (!press) {
                if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) {
                    // now handle the postponed event
                    inherited::processSoEvent(&mouseDownConsumedEvent);
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            break;
        case SoMouseButtonEvent::BUTTON2:
            // If we are in edit mode then simply ignore the RMB events
            // to pass the event to the base class.
            this->lockrecenter = true;
            if (!viewer->isEditing()) {
                // If we are in zoom or pan mode ignore RMB events otherwise
                // the canvas doesn't get any release events
                if (this->currentmode != NavigationStyle::ZOOMING &&
                    this->currentmode != NavigationStyle::PANNING &&
                    this->currentmode != NavigationStyle::DRAGGING) {
                    if (this->isPopupMenuEnabled()) {
                        if (!press) { // release right mouse button
                            this->openPopupMenu(event->getPosition());
                        }
                    }
                }
            }
            // Alternative way of rotating & zooming
            if (press && (this->currentmode == NavigationStyle::PANNING ||
                          this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            this->button2down = press;
            break;
        case SoMouseButtonEvent::BUTTON3:
            if (press) {
                this->centerTime = ev->getTime();
                float ratio = vp.getViewportAspectRatio();
                SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
                this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
                this->lockrecenter = false;
            }
            else {
                SbTime tmp = (ev->getTime() - this->centerTime);
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // is it just a middle click?
                if (tmp.getValue() < dci && !this->lockrecenter) {
                    if (!this->lookAtPoint(pos)) {
                        panToCenter(panningplane, posn);
                        this->interactiveCountDec();
                    }
                    processed = true;
                }
            }
            this->button3down = press;
            break;
        case SoMouseButtonEvent::BUTTON4:
            doZoom(viewer->getSoRenderManager()->getCamera(), true, posn);
            processed = true;
            break;
        case SoMouseButtonEvent::BUTTON5:
            doZoom(viewer->getSoRenderManager()->getCamera(), false, posn);
            processed = true;
            break;
        default:
            break;
        }
    }

    // Mouse Movement handling
    if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
        this->lockrecenter = true;
        const SoLocation2Event * const event = (const SoLocation2Event *) ev;
        if (this->currentmode == NavigationStyle::ZOOMING) {
            this->zoomByCursor(posn, prevnormalized);
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::PANNING) {
            float ratio = vp.getViewportAspectRatio();
            panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::DRAGGING) {
            this->addToLog(event->getPosition(), event->getTime());
            this->spin(posn);
            moveCursorPosition();
            processed = true;
        }
    }

    // Spaceball & Joystick handling
    if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
        const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev);
        if (event)
            this->processMotionEvent(event);
        processed = true;
    }

    enum {
        BUTTON1DOWN = 1 << 0,
        BUTTON3DOWN = 1 << 1,
        CTRLDOWN =    1 << 2,
        SHIFTDOWN =   1 << 3,
        BUTTON2DOWN = 1 << 4
    };
    unsigned int combo =
        (this->button1down ? BUTTON1DOWN : 0) |
        (this->button2down ? BUTTON2DOWN : 0) |
        (this->button3down ? BUTTON3DOWN : 0) |
        (this->ctrldown ? CTRLDOWN : 0) |
        (this->shiftdown ? SHIFTDOWN : 0);

    switch (combo) {
    case 0:
        if (curmode == NavigationStyle::SPINNING) { break; }
        newmode = NavigationStyle::IDLE;
        // The left mouse button has been released right now but
        // we want to avoid that the event is procesed elsewhere
        if (this->lockButton1) {
            this->lockButton1 = false;
            processed = true;
        }

        //if (curmode == NavigationStyle::DRAGGING) {
        //    if (doSpin())
        //        newmode = NavigationStyle::SPINNING;
        //}
        break;
    case BUTTON1DOWN:
        // make sure not to change the selection when stopping spinning
        if (curmode == NavigationStyle::SPINNING || this->lockButton1)
            newmode = NavigationStyle::IDLE;
        else
            newmode = NavigationStyle::SELECTION;
        break;
    case BUTTON1DOWN|BUTTON2DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case SHIFTDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case BUTTON3DOWN:
        if (newmode != NavigationStyle::DRAGGING) {
            saveCursorPosition(ev);
        }
        newmode = NavigationStyle::DRAGGING;
        break;
    //case BUTTON1DOWN|BUTTON2DOWN|BUTTON3DOWN:
    //    newmode = NavigationStyle::ZOOMING;
    //    break;
    case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
    case CTRLDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::ZOOMING;
        break;

    default:
        break;
    }

    if (newmode != curmode) {
        this->setViewingMode(newmode);
    }

    // If for dragging the buttons 1 and 3 are pressed
    // but then button 3 is relaesed we shouldn't switch
    // into selection mode.
    if (this->button1down && this->button3down)
        this->lockButton1 = true;

    // If not handled in this class, pass on upwards in the inheritance
    // hierarchy.
    if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed)
        processed = inherited::processSoEvent(ev);
    else
        return true;

    return processed;
}
<commit_msg>show cursor for selection in Blender style when Ctrl is pressed while left-clicking<commit_after>/***************************************************************************
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <cfloat>
# include "InventorAll.h"
# include <QAction>
# include <QActionGroup>
# include <QApplication>
# include <QByteArray>
# include <QCursor>
# include <QList>
# include <QMenu>
# include <QMetaObject>
# include <QRegExp>
#endif

#include <Inventor/sensors/SoTimerSensor.h>

#include <App/Application.h>
#include "NavigationStyle.h"
#include "View3DInventorViewer.h"
#include "Application.h"
#include "MenuManager.h"
#include "MouseSelection.h"

using namespace Gui;

// ----------------------------------------------------------------------------------

/* TRANSLATOR Gui::BlenderNavigationStyle */

TYPESYSTEM_SOURCE(Gui::BlenderNavigationStyle, Gui::UserNavigationStyle);

BlenderNavigationStyle::BlenderNavigationStyle() : lockButton1(false)
{
}

BlenderNavigationStyle::~BlenderNavigationStyle()
{
}

const char* BlenderNavigationStyle::mouseButtons(ViewerMode mode)
{
    switch (mode) {
    case NavigationStyle::SELECTION:
        return QT_TR_NOOP("Press left mouse button");
    case NavigationStyle::PANNING:
        return QT_TR_NOOP("Press SHIFT and middle mouse button");
    case NavigationStyle::DRAGGING:
        return QT_TR_NOOP("Press middle mouse button");
    case NavigationStyle::ZOOMING:
        return QT_TR_NOOP("Scroll middle mouse button");
    default:
        return "No description";
    }
}

SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
{
    // Events when in "ready-to-seek" mode are ignored, except those
    // which influence the seek mode itself -- these are handled further
    // up the inheritance hierarchy.
    if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
    // Switch off viewing mode (Bug #0000911)
    if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
        this->setViewing(false); // by default disable viewing mode to render the scene

    const SoType type(ev->getTypeId());

    const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
    const SbVec2s size(vp.getViewportSizePixels());
    const SbVec2f prevnormalized = this->lastmouseposition;
    const SbVec2s pos(ev->getPosition());
    const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1),
                       (float) pos[1] / (float) std::max((int)(size[1] - 1), 1));

    this->lastmouseposition = posn;

    // Set to true if any event processing happened. Note that it is not
    // necessary to restrict ourselves to only do one "action" for an
    // event, we only need this flag to see if any processing happened
    // at all.
    SbBool processed = false;

    const ViewerMode curmode = this->currentmode;
    ViewerMode newmode = curmode;

    // Mismatches in state of the modifier keys happens if the user
    // presses or releases them outside the viewer window.
    if (this->ctrldown != ev->wasCtrlDown()) {
        this->ctrldown = ev->wasCtrlDown();
    }
    if (this->shiftdown != ev->wasShiftDown()) {
        this->shiftdown = ev->wasShiftDown();
    }
    if (this->altdown != ev->wasAltDown()) {
        this->altdown = ev->wasAltDown();
    }

    // give the nodes in the foreground root the chance to handle events (e.g color bar)
    if (!processed && !viewer->isEditing()) {
        processed = handleEventInForeground(ev);
        if (processed)
            return true;
    }

    // Keyboard handling
    if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
        const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
        switch (event->getKey()) {
        case SoKeyboardEvent::LEFT_CONTROL:
        case SoKeyboardEvent::RIGHT_CONTROL:
            this->ctrldown = press;
            break;
        case SoKeyboardEvent::LEFT_SHIFT:
        case SoKeyboardEvent::RIGHT_SHIFT:
            this->shiftdown = press;
            break;
        case SoKeyboardEvent::LEFT_ALT:
        case SoKeyboardEvent::RIGHT_ALT:
            this->altdown = press;
            break;
        case SoKeyboardEvent::H:
            processed = true;
            viewer->saveHomePosition();
            break;
        case SoKeyboardEvent::S:
        case SoKeyboardEvent::HOME:
        case SoKeyboardEvent::LEFT_ARROW:
        case SoKeyboardEvent::UP_ARROW:
        case SoKeyboardEvent::RIGHT_ARROW:
        case SoKeyboardEvent::DOWN_ARROW:
            if (!this->isViewing())
                this->setViewing(true);
            break;
        default:
            break;
        }
    }

    // Mouse Button / Spaceball Button handling
    if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
        const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
        const int button = event->getButton();
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;

        //SoDebugError::postInfo("processSoEvent", "button = %d", button);
        switch (button) {
        case SoMouseButtonEvent::BUTTON1:
            this->lockrecenter = true;
            this->button1down = press;
            if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
                newmode = NavigationStyle::SEEK_MODE;
                this->seekToPoint(pos); // implicitly calls interactiveCountInc()
                processed = true;
            }
            //else if (press && (this->currentmode == NavigationStyle::IDLE)) {
            //    this->setViewing(true);
            //    processed = true;
            //}
            else if (press && (this->currentmode == NavigationStyle::PANNING ||
                               this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
                processed = true;
            }
            // issue #0002433: avoid to swallow the UP event if down the
            // scene graph somewhere a dialog gets opened
            else if (press) {
                SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime());
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // a double-click?
                if (tmp.getValue() < dci) {
                    mouseDownConsumedEvent = *event;
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    processed = true;
                }
                else {
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    // 'ANY' is used to mark that we don't know yet if it will
                    // be a double-click event.
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            else if (!press) {
                if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) {
                    // now handle the postponed event
                    inherited::processSoEvent(&mouseDownConsumedEvent);
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            break;
        case SoMouseButtonEvent::BUTTON2:
            // If we are in edit mode then simply ignore the RMB events
            // to pass the event to the base class.
            this->lockrecenter = true;
            if (!viewer->isEditing()) {
                // If we are in zoom or pan mode ignore RMB events otherwise
                // the canvas doesn't get any release events
                if (this->currentmode != NavigationStyle::ZOOMING &&
                    this->currentmode != NavigationStyle::PANNING &&
                    this->currentmode != NavigationStyle::DRAGGING) {
                    if (this->isPopupMenuEnabled()) {
                        if (!press) { // release right mouse button
                            this->openPopupMenu(event->getPosition());
                        }
                    }
                }
            }
            // Alternative way of rotating & zooming
            if (press && (this->currentmode == NavigationStyle::PANNING ||
                          this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            this->button2down = press;
            break;
        case SoMouseButtonEvent::BUTTON3:
            if (press) {
                this->centerTime = ev->getTime();
                float ratio = vp.getViewportAspectRatio();
                SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
                this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
                this->lockrecenter = false;
            }
            else {
                SbTime tmp = (ev->getTime() - this->centerTime);
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // is it just a middle click?
                if (tmp.getValue() < dci && !this->lockrecenter) {
                    if (!this->lookAtPoint(pos)) {
                        panToCenter(panningplane, posn);
                        this->interactiveCountDec();
                    }
                    processed = true;
                }
            }
            this->button3down = press;
            break;
        case SoMouseButtonEvent::BUTTON4:
            doZoom(viewer->getSoRenderManager()->getCamera(), true, posn);
            processed = true;
            break;
        case SoMouseButtonEvent::BUTTON5:
            doZoom(viewer->getSoRenderManager()->getCamera(), false, posn);
            processed = true;
            break;
        default:
            break;
        }
    }

    // Mouse Movement handling
    if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
        this->lockrecenter = true;
        const SoLocation2Event * const event = (const SoLocation2Event *) ev;
        if (this->currentmode == NavigationStyle::ZOOMING) {
            this->zoomByCursor(posn, prevnormalized);
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::PANNING) {
            float ratio = vp.getViewportAspectRatio();
            panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::DRAGGING) {
            this->addToLog(event->getPosition(), event->getTime());
            this->spin(posn);
            moveCursorPosition();
            processed = true;
        }
    }

    // Spaceball & Joystick handling
    if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
        const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev);
        if (event)
            this->processMotionEvent(event);
        processed = true;
    }

    enum {
        BUTTON1DOWN = 1 << 0,
        BUTTON3DOWN = 1 << 1,
        CTRLDOWN =    1 << 2,
        SHIFTDOWN =   1 << 3,
        BUTTON2DOWN = 1 << 4
    };
    unsigned int combo =
        (this->button1down ? BUTTON1DOWN : 0) |
        (this->button2down ? BUTTON2DOWN : 0) |
        (this->button3down ? BUTTON3DOWN : 0) |
        (this->ctrldown ? CTRLDOWN : 0) |
        (this->shiftdown ? SHIFTDOWN : 0);

    switch (combo) {
    case 0:
        if (curmode == NavigationStyle::SPINNING) { break; }
        newmode = NavigationStyle::IDLE;
        // The left mouse button has been released right now but
        // we want to avoid that the event is procesed elsewhere
        if (this->lockButton1) {
            this->lockButton1 = false;
            processed = true;
        }

        //if (curmode == NavigationStyle::DRAGGING) {
        //    if (doSpin())
        //        newmode = NavigationStyle::SPINNING;
        //}
        break;
    case BUTTON1DOWN:
    case CTRLDOWN|BUTTON1DOWN:
        // make sure not to change the selection when stopping spinning
        if (curmode == NavigationStyle::SPINNING || this->lockButton1)
            newmode = NavigationStyle::IDLE;
        else
            newmode = NavigationStyle::SELECTION;
        break;
    case BUTTON1DOWN|BUTTON2DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case SHIFTDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case BUTTON3DOWN:
        if (newmode != NavigationStyle::DRAGGING) {
            saveCursorPosition(ev);
        }
        newmode = NavigationStyle::DRAGGING;
        break;
    //case BUTTON1DOWN|BUTTON2DOWN|BUTTON3DOWN:
    //    newmode = NavigationStyle::ZOOMING;
    //    break;
    case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
    case CTRLDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::ZOOMING;
        break;

    default:
        break;
    }

    if (newmode != curmode) {
        this->setViewingMode(newmode);
    }

    // If for dragging the buttons 1 and 3 are pressed
    // but then button 3 is relaesed we shouldn't switch
    // into selection mode.
    if (this->button1down && this->button3down)
        this->lockButton1 = true;

    // If not handled in this class, pass on upwards in the inheritance
    // hierarchy.
    if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed)
        processed = inherited::processSoEvent(ev);
    else
        return true;

    return processed;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include "database.h"
#include "config.h"
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <mongo.h>
#include <cerrno>
#include <cassert>

// #define DEBUG

#define M (mongo_sync_connection*)m_

/**
 * @brief Constructor.
 */
Database::Database( const std::string &hostname, uint16_t port, const std::string &database, const std::string &username, const std::string &password )
: m_(0)
{
	hostName_ = hostname;
	port_ = port;
	databaseName_ = database;
	username_ = username;
	password_ = password;
}

/**
 * @brief Destructor.
 */
Database::~Database()
{
	if(m_)
		mongo_sync_disconnect(M);
}

/**
 * @brief Returns the last error in the QSqlDatabase object.
 */
std::string Database::lastError() const
{
	return lastError_;
}

bool Database::open()
{
	m_ = (void*)mongo_sync_connect(hostName_.c_str(), port_, TRUE);
	if(!m_) {
		lastError_ = strerror(errno);
		return false;
	}
	if(!mongo_sync_conn_set_auto_reconnect(M, TRUE)) {
		lastError_ = strerror(errno);
		mongo_sync_disconnect(M);
		return false;
	}
#warning TODO: db.properties.ensureIndex({'network':1,'receiver':1,'sender':1})
	return true;
}

/**
 * @brief Retrieve all properties under a certain namespace.
 *
 * All properties whose names start with the given namespace name, then a
 * single dot, and that match the given scope values, are returned from this
 * method.
 *
 * This method guarantees that if it returns a certain key, property() will
 * return the correct value of that key given that network, receiver and
 * sender scope are the same.
 */
QStringList Database::propertyKeys( const QString &ns, const QString &networkScope,
 const QString &receiverScope, const QString &senderScope )
{
  checkDatabaseConnection();

  QString nsQuery = ns + ".%";
  QSqlQuery data(db_);
  data.prepare(QLatin1String("SELECT variable,network,receiver,sender"
    " FROM properties WHERE variable LIKE ?"));
  data.addBindValue(nsQuery);

  QStringList k;
  if( !data.exec() )
  {
    qWarning() << "Property retrieve keys failed: " << data.lastError();
    return k;
  }

  // index the results
  while( data.next() )
  {
    // Check if the name really matches
    QString actualName = data.value(0).toString();
    if( !actualName.startsWith(ns + '.') )
       continue;
    actualName = actualName.mid(ns.length() + 1);

    if( data.value(3).isNull() )
    {
      if( data.value(2).isNull() )
      {
        if( data.value(1).isNull() )
          k.append(actualName);
        else if( data.value(1).toString() == networkScope )
          k.append(actualName);
      }
      else if( data.value(1).toString() == networkScope
            && data.value(2).toString() == receiverScope )
        k.append(actualName);
    }
    else if( data.value(1).toString() == networkScope
          && data.value(2).toString() == receiverScope
          && data.value(3).toString() == senderScope )
      k.append(actualName);
  }

  return k;
}

/**
 * @brief Retrieve property from database.
 *
 * The most specific scope will be selected first, i.e. user-specific scope.
 * If that yields no results, channel-specific scope will be returned, then
 * network-specific scope, then global scope.
 *
 * Variable should be formatted using reverse-domain format, i.e. for the
 * plugin MyFirstPlugin created by John Doe, to save a 'foo' variable one
 * could use:
 * net.jondoe.myfirstplugin.foo
 */
QVariant Database::property( const QString &variable,
 const QString &networkScope, const QString &receiverScope,
 const QString &senderScope )
{
	// variable, [networkScope, [receiverScope, [senderScope]]]
	// (empty if not given)

	// db.c.
	//   find() // for everything
	//   find({network:{$in: ['NETWORKNAME',null]}}) // for network scope
	//   find({network:{$in: ['NETWORKNAME',null]}, receiver:{$in: ['RECEIVER',null]}}) // for receiver scope
	//   find({network:..., receiver:..., sender:{$in: ['SENDER',null]}}) // for sender scope
	// .sort({'a':-1,'b':-1,'c':-1}).limit(1)
	// Reverse sort and limit(1) will make sure we only receive the most
	// specific result. This works, as long as the assumption is true that
	// no specific fields are set without their less specific fields also
	// being set (i.e. receiver can't be empty if sender is non-empty).

	bson *query = bson_build_full(
		BSON_TYPE_DOCUMENT, "$orderby", TRUE,
		bson_build(BSON_TYPE_INT32, "network", -1, BSON_TYPE_INT32, "receiver", -1, BSON_TYPE_INT32, "sender", -1, BSON_TYPE_NONE),
		BSON_TYPE_NONE
	);

	/*
		'$query':{
			'variable':'foo',
			'network':{'$in':['bla',null]},
			'receiver':{'$in':['moo', null]},
		}
	*/

	bson *selector = bson_new();
	bson *network = 0, *receiver = 0, *sender = 0;
	bson_append_string(selector, "variable", variable.toUtf8().constData(), -1);
	if(networkScope.length() > 0) {
		network = bson_build_full(
			BSON_TYPE_ARRAY, "$in", TRUE,
			bson_build(BSON_TYPE_STRING, "1", networkScope.toUtf8().constData(), -1,
			           BSON_TYPE_NULL, "2", BSON_TYPE_NONE),
			BSON_TYPE_NONE );
		bson_finish(network);
		bson_append_document(selector, "network", network);
		if(receiverScope.length() > 0) {
			receiver = bson_build_full(
				BSON_TYPE_ARRAY, "$in", TRUE,
				bson_build(BSON_TYPE_STRING, "1", receiverScope.toUtf8().constData(), -1,
				           BSON_TYPE_NULL, "2", BSON_TYPE_NONE),
				BSON_TYPE_NONE );
			bson_finish(receiver);
			bson_append_document(selector, "receiver", receiver);
			if(senderScope.length() > 0) {
				sender = bson_build_full(
					BSON_TYPE_ARRAY, "$in", TRUE,
					bson_build(BSON_TYPE_STRING, "1", senderScope.toUtf8().constData(), -1,
						   BSON_TYPE_NULL, "2", BSON_TYPE_NONE),
					BSON_TYPE_NONE );
				bson_finish(sender);
				bson_append_document(selector, "sender", sender);
			}
		}
	}
	bson_finish(selector);
	bson_append_document(query, "$query", selector);
	bson_finish(query);

	mongo_packet *p = mongo_sync_cmd_query(M, std::string(databaseName_ + ".properties").c_str(), 0, 0, 1, query, NULL /* TODO: value only? */);

	bson_free(query);
	bson_free(selector);
	if(network) bson_free(network);
	if(receiver) bson_free(receiver);
	if(sender) bson_free(sender);

	if(!p) {
		lastError_ = strerror(errno);
		return QVariant();
	}

	mongo_sync_cursor *cursor = mongo_sync_cursor_new(M, std::string(databaseName_ + ".properties").c_str(), p);
	if(!cursor) {
		lastError_ = strerror(errno);
		return QVariant();
	}

	if(!mongo_sync_cursor_next(cursor)) {
#ifdef DEBUG
		fprintf(stderr, "Variable %s not found within given scope.\n", variable.toUtf8().constData());
#endif
	}

	bson *result = mongo_sync_cursor_get_data(cursor);
	if(!result) {
		lastError_ = strerror(errno);
		mongo_sync_cursor_free(cursor);
		return QVariant();
	}

	bson_cursor *c = bson_find(result, "value");
	const char *value;
	if(!bson_cursor_get_string(c, &value)) {
		lastError_ = strerror(errno);
#ifdef DEBUG
		fprintf(stderr, "Database error: %s\n", lastError_.c_str());
#endif
		mongo_sync_cursor_free(cursor);
		bson_cursor_free(c);
		return QVariant();
	}

	bson_free(result);
	bson_cursor_free(c);

	// only one result
	assert(!mongo_sync_cursor_next(cursor));

	mongo_sync_cursor_free(cursor);
	return QVariant(value);
}

void Database::setProperty( const QString &variable,
 const QVariant &value, const QString &networkScope,
 const QString &receiverScope, const QString &senderScope )
{
	/**
		selector: {network:'foo',receiver:'bar',sender:null,variable:'bla.blob'}
		object:   {'$set':{ 'value': 'bla'}}
	*/
	bson *object = bson_build_full(
		BSON_TYPE_DOCUMENT, "$set", TRUE,
		bson_build(
			BSON_TYPE_STRING, "value", value.toString().toUtf8().constData(), -1,
			BSON_TYPE_NONE),
		BSON_TYPE_NONE);
	bson_finish(object);
	bson *selector = bson_build(
		BSON_TYPE_STRING, "variable", variable.toUtf8().constData(), -1,
		BSON_TYPE_NONE);
	if(networkScope.length() > 0) {
		bson_append_string(selector, "network", networkScope.toUtf8().constData(), -1);

		if(receiverScope.length() > 0) {
			bson_append_string(selector, "receiver", receiverScope.toUtf8().constData(), -1);

			if(senderScope.length() > 0) {
				bson_append_string(selector, "sender", senderScope.toUtf8().constData(), -1);
			} else {
				bson_append_null(selector, "sender");
			}
		} else {
			bson_append_null(selector, "receiver");
			bson_append_null(selector, "sender");
		}
	} else {
		bson_append_null(selector, "network");
		bson_append_null(selector, "receiver");
		bson_append_null(selector, "sender");
	}
	bson_finish(selector);

	// if the value length is zero, run a delete instead
	if(value.toString().length() == 0) {
		if(!mongo_sync_cmd_delete(M,
			std::string(databaseName_ + ".properties").c_str(),
			0, selector))
		{
			lastError_ = strerror(errno);
#ifdef DEBUG
			fprintf(stderr, "Error: %s\n", lastError_.c_str());
#endif
		}
	} else if(!mongo_sync_cmd_update(M,
		std::string(databaseName_ + ".properties").c_str(),
		MONGO_WIRE_FLAG_UPDATE_UPSERT, selector, object))
	{
		lastError_ = strerror(errno);
#ifdef DEBUG
		fprintf(stderr, "Error: %s\n", lastError_.c_str());
#endif
	}
	bson_free(object);
	bson_free(selector);
}
<commit_msg>Fix use of value after free.<commit_after>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include "database.h"
#include "config.h"
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <mongo.h>
#include <cerrno>
#include <cassert>

// #define DEBUG

#define M (mongo_sync_connection*)m_

/**
 * @brief Constructor.
 */
Database::Database( const std::string &hostname, uint16_t port, const std::string &database, const std::string &username, const std::string &password )
: m_(0)
{
	hostName_ = hostname;
	port_ = port;
	databaseName_ = database;
	username_ = username;
	password_ = password;
}

/**
 * @brief Destructor.
 */
Database::~Database()
{
	if(m_)
		mongo_sync_disconnect(M);
}

/**
 * @brief Returns the last error in the QSqlDatabase object.
 */
std::string Database::lastError() const
{
	return lastError_;
}

bool Database::open()
{
	m_ = (void*)mongo_sync_connect(hostName_.c_str(), port_, TRUE);
	if(!m_) {
		lastError_ = strerror(errno);
		return false;
	}
	if(!mongo_sync_conn_set_auto_reconnect(M, TRUE)) {
		lastError_ = strerror(errno);
		mongo_sync_disconnect(M);
		return false;
	}
#warning TODO: db.properties.ensureIndex({'network':1,'receiver':1,'sender':1})
	return true;
}

/**
 * @brief Retrieve all properties under a certain namespace.
 *
 * All properties whose names start with the given namespace name, then a
 * single dot, and that match the given scope values, are returned from this
 * method.
 *
 * This method guarantees that if it returns a certain key, property() will
 * return the correct value of that key given that network, receiver and
 * sender scope are the same.
 */
QStringList Database::propertyKeys( const QString &ns, const QString &networkScope,
 const QString &receiverScope, const QString &senderScope )
{
  checkDatabaseConnection();

  QString nsQuery = ns + ".%";
  QSqlQuery data(db_);
  data.prepare(QLatin1String("SELECT variable,network,receiver,sender"
    " FROM properties WHERE variable LIKE ?"));
  data.addBindValue(nsQuery);

  QStringList k;
  if( !data.exec() )
  {
    qWarning() << "Property retrieve keys failed: " << data.lastError();
    return k;
  }

  // index the results
  while( data.next() )
  {
    // Check if the name really matches
    QString actualName = data.value(0).toString();
    if( !actualName.startsWith(ns + '.') )
       continue;
    actualName = actualName.mid(ns.length() + 1);

    if( data.value(3).isNull() )
    {
      if( data.value(2).isNull() )
      {
        if( data.value(1).isNull() )
          k.append(actualName);
        else if( data.value(1).toString() == networkScope )
          k.append(actualName);
      }
      else if( data.value(1).toString() == networkScope
            && data.value(2).toString() == receiverScope )
        k.append(actualName);
    }
    else if( data.value(1).toString() == networkScope
          && data.value(2).toString() == receiverScope
          && data.value(3).toString() == senderScope )
      k.append(actualName);
  }

  return k;
}

/**
 * @brief Retrieve property from database.
 *
 * The most specific scope will be selected first, i.e. user-specific scope.
 * If that yields no results, channel-specific scope will be returned, then
 * network-specific scope, then global scope.
 *
 * Variable should be formatted using reverse-domain format, i.e. for the
 * plugin MyFirstPlugin created by John Doe, to save a 'foo' variable one
 * could use:
 * net.jondoe.myfirstplugin.foo
 */
QVariant Database::property( const QString &variable,
 const QString &networkScope, const QString &receiverScope,
 const QString &senderScope )
{
	// variable, [networkScope, [receiverScope, [senderScope]]]
	// (empty if not given)

	// db.c.
	//   find() // for everything
	//   find({network:{$in: ['NETWORKNAME',null]}}) // for network scope
	//   find({network:{$in: ['NETWORKNAME',null]}, receiver:{$in: ['RECEIVER',null]}}) // for receiver scope
	//   find({network:..., receiver:..., sender:{$in: ['SENDER',null]}}) // for sender scope
	// .sort({'a':-1,'b':-1,'c':-1}).limit(1)
	// Reverse sort and limit(1) will make sure we only receive the most
	// specific result. This works, as long as the assumption is true that
	// no specific fields are set without their less specific fields also
	// being set (i.e. receiver can't be empty if sender is non-empty).

	bson *query = bson_build_full(
		BSON_TYPE_DOCUMENT, "$orderby", TRUE,
		bson_build(BSON_TYPE_INT32, "network", -1, BSON_TYPE_INT32, "receiver", -1, BSON_TYPE_INT32, "sender", -1, BSON_TYPE_NONE),
		BSON_TYPE_NONE
	);

	/*
		'$query':{
			'variable':'foo',
			'network':{'$in':['bla',null]},
			'receiver':{'$in':['moo', null]},
		}
	*/

	bson *selector = bson_new();
	bson *network = 0, *receiver = 0, *sender = 0;
	bson_append_string(selector, "variable", variable.toUtf8().constData(), -1);
	if(networkScope.length() > 0) {
		network = bson_build_full(
			BSON_TYPE_ARRAY, "$in", TRUE,
			bson_build(BSON_TYPE_STRING, "1", networkScope.toUtf8().constData(), -1,
			           BSON_TYPE_NULL, "2", BSON_TYPE_NONE),
			BSON_TYPE_NONE );
		bson_finish(network);
		bson_append_document(selector, "network", network);
		if(receiverScope.length() > 0) {
			receiver = bson_build_full(
				BSON_TYPE_ARRAY, "$in", TRUE,
				bson_build(BSON_TYPE_STRING, "1", receiverScope.toUtf8().constData(), -1,
				           BSON_TYPE_NULL, "2", BSON_TYPE_NONE),
				BSON_TYPE_NONE );
			bson_finish(receiver);
			bson_append_document(selector, "receiver", receiver);
			if(senderScope.length() > 0) {
				sender = bson_build_full(
					BSON_TYPE_ARRAY, "$in", TRUE,
					bson_build(BSON_TYPE_STRING, "1", senderScope.toUtf8().constData(), -1,
						   BSON_TYPE_NULL, "2", BSON_TYPE_NONE),
					BSON_TYPE_NONE );
				bson_finish(sender);
				bson_append_document(selector, "sender", sender);
			}
		}
	}
	bson_finish(selector);
	bson_append_document(query, "$query", selector);
	bson_finish(query);

	mongo_packet *p = mongo_sync_cmd_query(M, std::string(databaseName_ + ".properties").c_str(), 0, 0, 1, query, NULL /* TODO: value only? */);

	bson_free(query);
	bson_free(selector);
	if(network) bson_free(network);
	if(receiver) bson_free(receiver);
	if(sender) bson_free(sender);

	if(!p) {
		lastError_ = strerror(errno);
		return QVariant();
	}

	mongo_sync_cursor *cursor = mongo_sync_cursor_new(M, std::string(databaseName_ + ".properties").c_str(), p);
	if(!cursor) {
		lastError_ = strerror(errno);
		return QVariant();
	}

	if(!mongo_sync_cursor_next(cursor)) {
#ifdef DEBUG
		fprintf(stderr, "Variable %s not found within given scope.\n", variable.toUtf8().constData());
#endif
	}

	bson *result = mongo_sync_cursor_get_data(cursor);
	if(!result) {
		lastError_ = strerror(errno);
		mongo_sync_cursor_free(cursor);
		return QVariant();
	}

	bson_cursor *c = bson_find(result, "value");
	const char *value;
	if(!bson_cursor_get_string(c, &value)) {
		lastError_ = strerror(errno);
#ifdef DEBUG
		fprintf(stderr, "Database error: %s\n", lastError_.c_str());
#endif
		mongo_sync_cursor_free(cursor);
		bson_cursor_free(c);
		return QVariant();
	}

	QVariant res(value);

	bson_free(result);
	bson_cursor_free(c);

	// only one result
	assert(!mongo_sync_cursor_next(cursor));

	mongo_sync_cursor_free(cursor);
	return res;
}

void Database::setProperty( const QString &variable,
 const QVariant &value, const QString &networkScope,
 const QString &receiverScope, const QString &senderScope )
{
	/**
		selector: {network:'foo',receiver:'bar',sender:null,variable:'bla.blob'}
		object:   {'$set':{ 'value': 'bla'}}
	*/
	bson *object = bson_build_full(
		BSON_TYPE_DOCUMENT, "$set", TRUE,
		bson_build(
			BSON_TYPE_STRING, "value", value.toString().toUtf8().constData(), -1,
			BSON_TYPE_NONE),
		BSON_TYPE_NONE);
	bson_finish(object);
	bson *selector = bson_build(
		BSON_TYPE_STRING, "variable", variable.toUtf8().constData(), -1,
		BSON_TYPE_NONE);
	if(networkScope.length() > 0) {
		bson_append_string(selector, "network", networkScope.toUtf8().constData(), -1);

		if(receiverScope.length() > 0) {
			bson_append_string(selector, "receiver", receiverScope.toUtf8().constData(), -1);

			if(senderScope.length() > 0) {
				bson_append_string(selector, "sender", senderScope.toUtf8().constData(), -1);
			} else {
				bson_append_null(selector, "sender");
			}
		} else {
			bson_append_null(selector, "receiver");
			bson_append_null(selector, "sender");
		}
	} else {
		bson_append_null(selector, "network");
		bson_append_null(selector, "receiver");
		bson_append_null(selector, "sender");
	}
	bson_finish(selector);

	// if the value length is zero, run a delete instead
	if(value.toString().length() == 0) {
		if(!mongo_sync_cmd_delete(M,
			std::string(databaseName_ + ".properties").c_str(),
			0, selector))
		{
			lastError_ = strerror(errno);
#ifdef DEBUG
			fprintf(stderr, "Error: %s\n", lastError_.c_str());
#endif
		}
	} else if(!mongo_sync_cmd_update(M,
		std::string(databaseName_ + ".properties").c_str(),
		MONGO_WIRE_FLAG_UPDATE_UPSERT, selector, object))
	{
		lastError_ = strerror(errno);
#ifdef DEBUG
		fprintf(stderr, "Error: %s\n", lastError_.c_str());
#endif
	}
	bson_free(object);
	bson_free(selector);
}
<|endoftext|>


<commit_before>#include <config.h>
#include <davixuri.hpp>
#include <ne_uri.h>
#include <malloc.h>
#include <cassert>
#include <cstring>

namespace Davix {

/**
 * @cond HIDDEN_SYMBOLS
 */

static std::string void_str;

struct UriPrivate{
    UriPrivate() :
        my_uri(),
        code(StatusCode::UriParsingError),
        proto(),
        path(),
        host(),
        query(),
        query_and_path(),
        _uri_string(){

        memset(&my_uri, 0, sizeof(my_uri));
    }

    UriPrivate(const UriPrivate & orig):
        my_uri(),
        code(orig.code),
        proto(orig.proto),
        path(orig.path),
        host(orig.host),
        query(orig.query),
        query_and_path(orig.query_and_path),
        _uri_string(orig._uri_string){
        ne_uri_copy(&my_uri, &(orig.my_uri));

    }

    ~UriPrivate() {
        ne_uri_free(&my_uri);
    }

    void parsing(const std::string & uri_string){
        _uri_string = uri_string;
        if(ne_uri_parse(uri_string.c_str(), &(my_uri)) == 0){
            if(my_uri.scheme == NULL
               || my_uri.path == NULL
               || my_uri.host ==NULL)
                return;

            if(my_uri.port == UINT_MAX)
                return;

            code = StatusCode::OK;
            proto = my_uri.scheme;
            path = my_uri.path;
            host = my_uri.host;
            if(my_uri.query){
                query = my_uri.query;
                query_and_path= path + "?" + query;
            }else{
                query_and_path = path;
            }
        }
    }

    ne_uri my_uri;
    StatusCode::Code code;
    std::string proto;
    std::string path;
    std::string host;
    std::string query;
    std::string query_and_path;
    std::string _uri_string;

};

Uri::Uri() :
    d_ptr(new UriPrivate()){
}

Uri::Uri(const std::string & uri) :
    d_ptr(new UriPrivate()){
    d_ptr->parsing(uri);
}

Uri::Uri(const Uri & uri) :
    d_ptr(new UriPrivate(*(uri.d_ptr))){
}

Uri::~Uri(){
    ne_uri_free(&(d_ptr->my_uri));
    delete d_ptr;
}

int Uri::getPort() const{
    if(d_ptr->code != StatusCode::OK)
        return -1;
    return d_ptr->my_uri.port;
}

const std::string & Uri::getHost() const{
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->host;
}

const std::string & Uri::getString() const{
    return d_ptr->_uri_string;
}

const std::string & Uri::getProtocol() const {
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->proto;
}

const std::string & Uri::getPath() const {
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->path;
}

const std::string & Uri::getPathAndQuery() const {
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->query_and_path;
}

const std::string & Uri::getQuery() const{
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->query;
}

Uri & Uri::operator =(const Uri & orig){
    if (d_ptr) delete d_ptr;
    d_ptr = new UriPrivate(*(orig.d_ptr));
    return *this;
}

StatusCode::Code Uri::getStatus() const{
    return d_ptr->code;
}

bool Uri::equal(const Uri &u2) const{
    if(this->getStatus() != Davix::StatusCode::OK || u2.getStatus() != Davix::StatusCode::OK)
        return false;
    return ne_uri_cmp(&this->d_ptr->my_uri, &u2.d_ptr->my_uri) ==0;
}

bool Uri::operator ==(const Uri & u2) const{
    return this->equal(u2);
}

std::string Uri::escapeString(const std::string & str){
    char* p = ne_path_escape(str.c_str());
    std::string  res(p);
    free(p);
    return res;
}

std::string Uri::unescapeString(const std::string & str){
    char* p = ne_path_unescape(str.c_str());
    std::string res(p);
    free(p);
    return res;
}

bool uriCheckError(const Uri &uri, DavixError **err){
    if(uri.getStatus() == StatusCode::OK)
        return true;
    DavixError::setupError(err, davix_scope_uri_parser(), uri.getStatus(), std::string("Uri syntax Invalid : ").append(uri.getString()));
    return false;
}

unsigned int httpUriGetPort(const Uri & uri){
    int port = uri.getPort();
    if( port ==0){
        const std::string & scheme = uri.getProtocol();
        if(*scheme.rbegin() == 's') // davs, https or s3s
            port = 443;
        else
            port =80;
    }
    return port;
}

} // namespace Davix

std::ostream& operator<< (std::ostream& stream, const Davix::Uri & _u){
	stream << _u.getString();
	return stream;
}

<commit_msg>- remove non deepded include fix ( OSX LCGUTIL-244 )<commit_after>#include <config.h>
#include <davixuri.hpp>
#include <ne_uri.h>
#include <cassert>
#include <cstring>

namespace Davix {

/**
 * @cond HIDDEN_SYMBOLS
 */

static std::string void_str;

struct UriPrivate{
    UriPrivate() :
        my_uri(),
        code(StatusCode::UriParsingError),
        proto(),
        path(),
        host(),
        query(),
        query_and_path(),
        _uri_string(){

        memset(&my_uri, 0, sizeof(my_uri));
    }

    UriPrivate(const UriPrivate & orig):
        my_uri(),
        code(orig.code),
        proto(orig.proto),
        path(orig.path),
        host(orig.host),
        query(orig.query),
        query_and_path(orig.query_and_path),
        _uri_string(orig._uri_string){
        ne_uri_copy(&my_uri, &(orig.my_uri));

    }

    ~UriPrivate() {
        ne_uri_free(&my_uri);
    }

    void parsing(const std::string & uri_string){
        _uri_string = uri_string;
        if(ne_uri_parse(uri_string.c_str(), &(my_uri)) == 0){
            if(my_uri.scheme == NULL
               || my_uri.path == NULL
               || my_uri.host ==NULL)
                return;

            if(my_uri.port == UINT_MAX)
                return;

            code = StatusCode::OK;
            proto = my_uri.scheme;
            path = my_uri.path;
            host = my_uri.host;
            if(my_uri.query){
                query = my_uri.query;
                query_and_path= path + "?" + query;
            }else{
                query_and_path = path;
            }
        }
    }

    ne_uri my_uri;
    StatusCode::Code code;
    std::string proto;
    std::string path;
    std::string host;
    std::string query;
    std::string query_and_path;
    std::string _uri_string;

};

Uri::Uri() :
    d_ptr(new UriPrivate()){
}

Uri::Uri(const std::string & uri) :
    d_ptr(new UriPrivate()){
    d_ptr->parsing(uri);
}

Uri::Uri(const Uri & uri) :
    d_ptr(new UriPrivate(*(uri.d_ptr))){
}

Uri::~Uri(){
    ne_uri_free(&(d_ptr->my_uri));
    delete d_ptr;
}

int Uri::getPort() const{
    if(d_ptr->code != StatusCode::OK)
        return -1;
    return d_ptr->my_uri.port;
}

const std::string & Uri::getHost() const{
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->host;
}

const std::string & Uri::getString() const{
    return d_ptr->_uri_string;
}

const std::string & Uri::getProtocol() const {
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->proto;
}

const std::string & Uri::getPath() const {
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->path;
}

const std::string & Uri::getPathAndQuery() const {
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->query_and_path;
}

const std::string & Uri::getQuery() const{
    if(d_ptr->code != StatusCode::OK)
        return void_str;
    return d_ptr->query;
}

Uri & Uri::operator =(const Uri & orig){
    if (d_ptr) delete d_ptr;
    d_ptr = new UriPrivate(*(orig.d_ptr));
    return *this;
}

StatusCode::Code Uri::getStatus() const{
    return d_ptr->code;
}

bool Uri::equal(const Uri &u2) const{
    if(this->getStatus() != Davix::StatusCode::OK || u2.getStatus() != Davix::StatusCode::OK)
        return false;
    return ne_uri_cmp(&this->d_ptr->my_uri, &u2.d_ptr->my_uri) ==0;
}

bool Uri::operator ==(const Uri & u2) const{
    return this->equal(u2);
}

std::string Uri::escapeString(const std::string & str){
    char* p = ne_path_escape(str.c_str());
    std::string  res(p);
    free(p);
    return res;
}

std::string Uri::unescapeString(const std::string & str){
    char* p = ne_path_unescape(str.c_str());
    std::string res(p);
    free(p);
    return res;
}

bool uriCheckError(const Uri &uri, DavixError **err){
    if(uri.getStatus() == StatusCode::OK)
        return true;
    DavixError::setupError(err, davix_scope_uri_parser(), uri.getStatus(), std::string("Uri syntax Invalid : ").append(uri.getString()));
    return false;
}

unsigned int httpUriGetPort(const Uri & uri){
    int port = uri.getPort();
    if( port ==0){
        const std::string & scheme = uri.getProtocol();
        if(*scheme.rbegin() == 's') // davs, https or s3s
            port = 443;
        else
            port =80;
    }
    return port;
}

} // namespace Davix

std::ostream& operator<< (std::ostream& stream, const Davix::Uri & _u){
	stream << _u.getString();
	return stream;
}

<|endoftext|>


<commit_before>#include <onut/ContentManager.h>
#include <onut/Files.h>
#include <onut/onut.h>
#include <onut/Settings.h>
#include <onut/Strings.h>

#include <fstream>

void initSettings()
{
    std::string path = ".";
    if (!OArguments.empty()) path = OArguments[0];

    if (path.back() != '\\' && path.back() != '/')
    {
        path += '/';
    }
    auto workingDirectory = onut::getPath(path);

    // Set content manager path
    oContentManager = OContentManager::create();
    oContentManager->clearSearchPaths();
    oContentManager->addSearchPath(workingDirectory);

    // Load settings
    auto settingsFile = onut::findFile("settings.txt", workingDirectory);
    if (!settingsFile.empty())
    {
        std::ifstream fic(settingsFile);
        std::string line;
        while (!fic.eof())
        {
            std::getline(fic, line);
            if (line.empty()) continue;
            auto split = onut::splitString(line, '=', false);
            if (split.size() != 2) continue;
            auto what = onut::toUpper(onut::trim(split[0]));
            auto value = onut::trim(split[1]);
            if (what == "RESOLUTION")
            {
                auto split2 = onut::splitString(value, ",x \t\n\r");
                if (split2.size() != 2) continue;
                Point res;
                try
                {
                    res.x = std::stoi(split2[0]);
                    res.y = std::stoi(split2[1]);
                    oSettings->setResolution(res);
                }
                catch (...) {}
            }
            else if (what == "RETRORESOLUTION")
            {
                auto split2 = onut::splitString(value, ",x \t\n\r");
                if (split2.size() != 2) continue;
                Point res;
                try
                {
                    res.x = std::stoi(split2[0]);
                    res.y = std::stoi(split2[1]);
                    oSettings->setRetroResolution(res);
                }
                catch (...) {}
            }
            else if (what == "RETROMODE")
            {
                value = onut::toUpper(value);
                oSettings->setIsRetroMode(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "GAMENAME")
            {
                oSettings->setGameName(value);
            }
            else if (what == "RESIZABLEWINDOW")
            {
                value = onut::toUpper(value);
                oSettings->setIsResizableWindow(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "FULLSCREEN")
            {
                value = onut::toUpper(value);
                oSettings->setBorderlessFullscreen(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "FIXEDSTEP")
            {
                value = onut::toUpper(value);
                oSettings->setIsFixedStep(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "APPID")
            {
                oSettings->setAppId(value);
            }
            else if (what == "APPSECRET")
            {
                oSettings->setAppSecret(value);
            }
            else if (what == "ONSCREENLOG")
            {
                value = onut::toUpper(value);
                oSettings->setShowOnScreenLog(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "EDITORMODE")
            {
                value = onut::toUpper(value);
                oSettings->setIsEditorMode(value == "TRUE" || value == "1" || value == "ON");
            }
        }
        fic.close();
    }
}

void init()
{
}

void update()
{
}

void render()
{
}

void postRender()
{
}
<commit_msg>parametable update FPS<commit_after>#include <onut/ContentManager.h>
#include <onut/Files.h>
#include <onut/onut.h>
#include <onut/Settings.h>
#include <onut/Strings.h>
#include <onut/Timing.h>

#include <fstream>

void initSettings()
{
    std::string path = ".";
    if (!OArguments.empty()) path = OArguments[0];

    if (path.back() != '\\' && path.back() != '/')
    {
        path += '/';
    }
    auto workingDirectory = onut::getPath(path);

    // Set content manager path
    oContentManager = OContentManager::create();
    oContentManager->clearSearchPaths();
    oContentManager->addSearchPath(workingDirectory);

    // Load settings
    auto settingsFile = onut::findFile("settings.txt", workingDirectory);
    if (!settingsFile.empty())
    {
        std::ifstream fic(settingsFile);
        std::string line;
        while (!fic.eof())
        {
            std::getline(fic, line);
            if (line.empty()) continue;
            auto split = onut::splitString(line, '=', false);
            if (split.size() != 2) continue;
            auto what = onut::toUpper(onut::trim(split[0]));
            auto value = onut::trim(split[1]);
            if (what == "RESOLUTION")
            {
                auto split2 = onut::splitString(value, ",x \t\n\r");
                if (split2.size() != 2) continue;
                Point res;
                try
                {
                    res.x = std::stoi(split2[0]);
                    res.y = std::stoi(split2[1]);
                    oSettings->setResolution(res);
                }
                catch (...) {}
            }
            else if (what == "RETRORESOLUTION")
            {
                auto split2 = onut::splitString(value, ",x \t\n\r");
                if (split2.size() != 2) continue;
                Point res;
                try
                {
                    res.x = std::stoi(split2[0]);
                    res.y = std::stoi(split2[1]);
                    oSettings->setRetroResolution(res);
                }
                catch (...) {}
            }
            else if (what == "RETROMODE")
            {
                value = onut::toUpper(value);
                oSettings->setIsRetroMode(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "GAMENAME")
            {
                oSettings->setGameName(value);
            }
            else if (what == "RESIZABLEWINDOW")
            {
                value = onut::toUpper(value);
                oSettings->setIsResizableWindow(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "FULLSCREEN")
            {
                value = onut::toUpper(value);
                oSettings->setBorderlessFullscreen(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "FIXEDSTEP")
            {
                value = onut::toUpper(value);
                oSettings->setIsFixedStep(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "UPDATEFPS")
            {
                try
                {
                    auto fps = std::stoi(value);
                    oTiming = OTiming::create((uint32_t)fps);
                }
                catch (...) {}
            }
            else if (what == "APPID")
            {
                oSettings->setAppId(value);
            }
            else if (what == "APPSECRET")
            {
                oSettings->setAppSecret(value);
            }
            else if (what == "ONSCREENLOG")
            {
                value = onut::toUpper(value);
                oSettings->setShowOnScreenLog(value == "TRUE" || value == "1" || value == "ON");
            }
            else if (what == "EDITORMODE")
            {
                value = onut::toUpper(value);
                oSettings->setIsEditorMode(value == "TRUE" || value == "1" || value == "ON");
            }
        }
        fic.close();
    }
}

void init()
{
}

void update()
{
}

void render()
{
}

void postRender()
{
}
<|endoftext|>


<commit_before>// Author: Enrico Guiraud, Danilo Piparo CERN  12/2016

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TDFUTILS
#define ROOT_TDFUTILS

#include "ROOT/RArrayView.hxx"
#include "TH1.h"
#include "TTreeReaderArray.h"
#include "TTreeReaderValue.h"

#include <array>
#include <cstddef> // std::size_t
#include <functional>
#include <memory>
#include <string>
#include <type_traits> // std::decay
#include <vector>
class TTree;
class TTreeReader;

/// \cond HIDDEN_SYMBOLS

namespace ROOT {

namespace Detail {
namespace TDF {
using ColumnNames_t = std::vector<std::string>;
class TCustomColumnBase; // fwd decl for ColumnName2ColumnTypeName
struct TInferType {
};
} // end ns Detail
} // end ns TDF

namespace Internal {
namespace TDF {
using namespace ROOT::Detail::TDF;

template <typename... Types>
struct TTypeList {
   static constexpr std::size_t fgSize = sizeof...(Types);
};

// extract parameter types from a callable object
template <typename T>
struct TFunctionTraits {
   using Args_t = typename TFunctionTraits<decltype(&T::operator())>::Args_t;
   using ArgsNoDecay_t = typename TFunctionTraits<decltype(&T::operator())>::ArgsNoDecay_t;
   using Ret_t = typename TFunctionTraits<decltype(&T::operator())>::Ret_t;
};

// lambdas and std::function
template <typename R, typename T, typename... Args>
struct TFunctionTraits<R (T::*)(Args...) const> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// mutable lambdas and functor classes
template <typename R, typename T, typename... Args>
struct TFunctionTraits<R (T::*)(Args...)> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// function pointers
template <typename R, typename... Args>
struct TFunctionTraits<R (*)(Args...)> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// free functions
template <typename R, typename... Args>
struct TFunctionTraits<R(Args...)> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// remove first type from TTypeList
template <typename>
struct TRemoveFirst {
};

template <typename T, typename... Args>
struct TRemoveFirst<TTypeList<T, Args...>> {
   using Types_t = TTypeList<Args...>;
};

// return wrapper around f that prepends an `unsigned int slot` parameter
template <typename R, typename F, typename... Args>
std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TTypeList<Args...>)
{
   return [f](unsigned int, Args... a) -> R { return f(a...); };
}

// compile-time integer sequence generator
// e.g. calling TGenStaticSeq<3>::type() instantiates a TStaticSeq<0,1,2>
template <int...>
struct TStaticSeq {
};

template <int N, int... S>
struct TGenStaticSeq : TGenStaticSeq<N - 1, N - 1, S...> {
};

template <int... S>
struct TGenStaticSeq<0, S...> {
   using Type_t = TStaticSeq<S...>;
};

template <typename T>
struct TIsContainer {
   using Test_t = typename std::decay<T>::type;

   template <typename A>
   static constexpr bool Test(A *pt, A const *cpt = nullptr, decltype(pt->begin()) * = nullptr,
                              decltype(pt->end()) * = nullptr, decltype(cpt->begin()) * = nullptr,
                              decltype(cpt->end()) * = nullptr, typename A::iterator *pi = nullptr,
                              typename A::const_iterator *pci = nullptr)
   {
      using It_t = typename A::iterator;
      using CIt_t = typename A::const_iterator;
      using V_t = typename A::value_type;
      return std::is_same<Test_t, std::vector<bool>>::value ||
             (std::is_same<decltype(pt->begin()), It_t>::value && std::is_same<decltype(pt->end()), It_t>::value &&
              std::is_same<decltype(cpt->begin()), CIt_t>::value && std::is_same<decltype(cpt->end()), CIt_t>::value &&
              std::is_same<decltype(**pi), V_t &>::value && std::is_same<decltype(**pci), V_t const &>::value);
   }

   template <typename A>
   static constexpr bool Test(...)
   {
      return false;
   }

   static const bool fgValue = Test<Test_t>(nullptr);
};

// Extract first of possibly many template parameters. For non-template types, the result is the type itself
template <typename T>
struct TExtractType {
   using type = T;
};

template <typename T, template <typename...> class U, typename... Extras>
struct TExtractType<U<T, Extras...>> {
   using type = T;
};

template <typename T>
using ExtractType_t = typename TExtractType<T>::type;

template <typename BranchType, typename... Rest>
struct TNeedJitting {
   static constexpr bool value = TNeedJitting<Rest...>::value;
};

template <typename... Rest>
struct TNeedJitting<TInferType, Rest...> {
   static constexpr bool value = true;
};

template <typename T>
struct TNeedJitting<T> {
   static constexpr bool value = false;
};

template <>
struct TNeedJitting<TInferType> {
   static constexpr bool value = true;
};

using TVBPtr_t = std::shared_ptr<TTreeReaderValueBase>;
using TVBVec_t = std::vector<TVBPtr_t>;

std::string ColumnName2ColumnTypeName(const std::string &colName, TTree &, TCustomColumnBase *);

const char *ToConstCharPtr(const char *s);
const char *ToConstCharPtr(const std::string s);
unsigned int GetNSlots();

/// Choose between TTreeReader{Array,Value} depending on whether the branch type
/// T is a `std::array_view<T>` or any other type (respectively).
template <typename T>
struct TReaderValueOrArray {
   using Proxy_t = TTreeReaderValue<T>;
};

template <typename T>
struct TReaderValueOrArray<std::array_view<T>> {
   using Proxy_t = TTreeReaderArray<T>;
};

template <typename T>
using ReaderValueOrArray_t = typename TReaderValueOrArray<T>::Proxy_t;

/// Initialize a tuple of TColumnValues.
/// For real TTree branches a TTreeReader{Array,Value} is built and passed to the
/// TColumnValue. For temporary columns a pointer to the corresponding variable
/// is passed instead.
template <typename TDFValueTuple, int... S>
void InitTDFValues(unsigned int slot, TDFValueTuple &valueTuple, TTreeReader *r, const ColumnNames_t &bn,
                   const ColumnNames_t &tmpbn,
                   const std::map<std::string, std::shared_ptr<TCustomColumnBase>> &tmpBranches, TStaticSeq<S...>)
{
   // isTmpBranch has length bn.size(). Elements are true if the corresponding
   // branch is a temporary branch created with Define, false if they are
   // actual branches present in the TTree.
   std::array<bool, sizeof...(S)> isTmpColumn;
   for (auto i = 0u; i < isTmpColumn.size(); ++i)
      isTmpColumn[i] = std::find(tmpbn.begin(), tmpbn.end(), bn.at(i)) != tmpbn.end();

   // hack to expand a parameter pack without c++17 fold expressions.
   // The statement defines a variable with type std::initializer_list<int>, containing all zeroes, and SetTmpColumn or
   // SetProxy are conditionally executed as the braced init list is expanded. The final ... expands S.
   std::initializer_list<int> expander{(isTmpColumn[S]
                                           ? std::get<S>(valueTuple).SetTmpColumn(slot, tmpBranches.at(bn.at(S)).get())
                                           : std::get<S>(valueTuple).MakeProxy(r, bn.at(S)),
                                        0)...};
   (void)expander; // avoid "unused variable" warnings for expander on gcc4.9
   (void)slot;     // avoid _bogus_ "unused variable" warnings for slot on gcc 4.9
   (void)r;        // avoid "unused variable" warnings for r on gcc5.2
}

template <typename Filter>
void CheckFilter(Filter &)
{
   using FilterRet_t = typename TDF::TFunctionTraits<Filter>::Ret_t;
   static_assert(std::is_same<FilterRet_t, bool>::value, "filter functions must return a bool");
}

void CheckTmpBranch(std::string_view branchName, TTree *treePtr);

///////////////////////////////////////////////////////////////////////////////
/// Check that the callable passed to TInterface::Reduce:
/// - takes exactly two arguments of the same type
/// - has a return value of the same type as the arguments
template <typename F, typename T>
void CheckReduce(F &, TTypeList<T, T>)
{
   using Ret_t = typename TFunctionTraits<F>::Ret_t;
   static_assert(std::is_same<Ret_t, T>::value, "reduce function must have return type equal to argument type");
   return;
}

///////////////////////////////////////////////////////////////////////////////
/// This overload of CheckReduce is called if T is not a TTypeList<T,T>
template <typename F, typename T>
void CheckReduce(F &, T)
{
   static_assert(sizeof(F) == 0, "reduce function must take exactly two arguments of the same type");
}

/// Returns local BranchNames or default BranchNames according to which one should be used
const ColumnNames_t &PickBranchNames(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);

namespace ActionTypes {
struct Histo1D {
};
struct Histo2D {
};
struct Histo3D {
};
struct Profile1D {
};
struct Profile2D {
};
struct Min {
};
struct Max {
};
struct Mean {
};
struct Fill {
};
}

template <typename T, bool ISV7HISTO = !std::is_base_of<TH1, T>::value>
struct TIsV7Histo {
   const static bool fgValue = ISV7HISTO;
};

template <typename T, bool ISV7HISTO = TIsV7Histo<T>::fgValue>
struct HistoUtils {
   static void SetCanExtendAllAxes(T &h) { h.SetCanExtend(::TH1::kAllAxes); }
   static bool HasAxisLimits(T &h)
   {
      auto xaxis = h.GetXaxis();
      return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
   }
};

template <typename T>
struct HistoUtils<T, true> {
   static void SetCanExtendAllAxes(T &) {}
   static bool HasAxisLimits(T &) { return true; }
};

} // end NS TDF
} // end NS Internal
} // end NS ROOT

/// \endcond

#endif // TDFUTILS
<commit_msg>[TDF] String in this context is not a container<commit_after>// Author: Enrico Guiraud, Danilo Piparo CERN  12/2016

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TDFUTILS
#define ROOT_TDFUTILS

#include "ROOT/RArrayView.hxx"
#include "TH1.h"
#include "TTreeReaderArray.h"
#include "TTreeReaderValue.h"

#include <array>
#include <cstddef> // std::size_t
#include <functional>
#include <memory>
#include <string>
#include <type_traits> // std::decay
#include <vector>
class TTree;
class TTreeReader;

/// \cond HIDDEN_SYMBOLS

namespace ROOT {

namespace Detail {
namespace TDF {
using ColumnNames_t = std::vector<std::string>;
class TCustomColumnBase; // fwd decl for ColumnName2ColumnTypeName
struct TInferType {
};
} // end ns Detail
} // end ns TDF

namespace Internal {
namespace TDF {
using namespace ROOT::Detail::TDF;

template <typename... Types>
struct TTypeList {
   static constexpr std::size_t fgSize = sizeof...(Types);
};

// extract parameter types from a callable object
template <typename T>
struct TFunctionTraits {
   using Args_t = typename TFunctionTraits<decltype(&T::operator())>::Args_t;
   using ArgsNoDecay_t = typename TFunctionTraits<decltype(&T::operator())>::ArgsNoDecay_t;
   using Ret_t = typename TFunctionTraits<decltype(&T::operator())>::Ret_t;
};

// lambdas and std::function
template <typename R, typename T, typename... Args>
struct TFunctionTraits<R (T::*)(Args...) const> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// mutable lambdas and functor classes
template <typename R, typename T, typename... Args>
struct TFunctionTraits<R (T::*)(Args...)> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// function pointers
template <typename R, typename... Args>
struct TFunctionTraits<R (*)(Args...)> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// free functions
template <typename R, typename... Args>
struct TFunctionTraits<R(Args...)> {
   using Args_t = TTypeList<typename std::decay<Args>::type...>;
   using ArgsNoDecay_t = TTypeList<Args...>;
   using Ret_t = R;
};

// remove first type from TTypeList
template <typename>
struct TRemoveFirst {
};

template <typename T, typename... Args>
struct TRemoveFirst<TTypeList<T, Args...>> {
   using Types_t = TTypeList<Args...>;
};

// return wrapper around f that prepends an `unsigned int slot` parameter
template <typename R, typename F, typename... Args>
std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TTypeList<Args...>)
{
   return [f](unsigned int, Args... a) -> R { return f(a...); };
}

// compile-time integer sequence generator
// e.g. calling TGenStaticSeq<3>::type() instantiates a TStaticSeq<0,1,2>
template <int...>
struct TStaticSeq {
};

template <int N, int... S>
struct TGenStaticSeq : TGenStaticSeq<N - 1, N - 1, S...> {
};

template <int... S>
struct TGenStaticSeq<0, S...> {
   using Type_t = TStaticSeq<S...>;
};

template <typename T>
struct TIsContainer {
   using Test_t = typename std::decay<T>::type;

   template <typename A>
   static constexpr bool Test(A *pt, A const *cpt = nullptr, decltype(pt->begin()) * = nullptr,
                              decltype(pt->end()) * = nullptr, decltype(cpt->begin()) * = nullptr,
                              decltype(cpt->end()) * = nullptr, typename A::iterator *pi = nullptr,
                              typename A::const_iterator *pci = nullptr)
   {
      using It_t = typename A::iterator;
      using CIt_t = typename A::const_iterator;
      using V_t = typename A::value_type;
      return (!std::is_same<Test_t, std::string>::value) && (std::is_same<Test_t, std::vector<bool>>::value ||
             (std::is_same<decltype(pt->begin()), It_t>::value && std::is_same<decltype(pt->end()), It_t>::value &&
              std::is_same<decltype(cpt->begin()), CIt_t>::value && std::is_same<decltype(cpt->end()), CIt_t>::value &&
              std::is_same<decltype(**pi), V_t &>::value && std::is_same<decltype(**pci), V_t const &>::value));
   }

   template <typename A>
   static constexpr bool Test(...)
   {
      return false;
   }

   static const bool fgValue = Test<Test_t>(nullptr);
};

// Extract first of possibly many template parameters. For non-template types, the result is the type itself
template <typename T>
struct TExtractType {
   using type = T;
};

template <typename T, template <typename...> class U, typename... Extras>
struct TExtractType<U<T, Extras...>> {
   using type = T;
};

template <typename T>
using ExtractType_t = typename TExtractType<T>::type;

template <typename BranchType, typename... Rest>
struct TNeedJitting {
   static constexpr bool value = TNeedJitting<Rest...>::value;
};

template <typename... Rest>
struct TNeedJitting<TInferType, Rest...> {
   static constexpr bool value = true;
};

template <typename T>
struct TNeedJitting<T> {
   static constexpr bool value = false;
};

template <>
struct TNeedJitting<TInferType> {
   static constexpr bool value = true;
};

using TVBPtr_t = std::shared_ptr<TTreeReaderValueBase>;
using TVBVec_t = std::vector<TVBPtr_t>;

std::string ColumnName2ColumnTypeName(const std::string &colName, TTree &, TCustomColumnBase *);

const char *ToConstCharPtr(const char *s);
const char *ToConstCharPtr(const std::string s);
unsigned int GetNSlots();

/// Choose between TTreeReader{Array,Value} depending on whether the branch type
/// T is a `std::array_view<T>` or any other type (respectively).
template <typename T>
struct TReaderValueOrArray {
   using Proxy_t = TTreeReaderValue<T>;
};

template <typename T>
struct TReaderValueOrArray<std::array_view<T>> {
   using Proxy_t = TTreeReaderArray<T>;
};

template <typename T>
using ReaderValueOrArray_t = typename TReaderValueOrArray<T>::Proxy_t;

/// Initialize a tuple of TColumnValues.
/// For real TTree branches a TTreeReader{Array,Value} is built and passed to the
/// TColumnValue. For temporary columns a pointer to the corresponding variable
/// is passed instead.
template <typename TDFValueTuple, int... S>
void InitTDFValues(unsigned int slot, TDFValueTuple &valueTuple, TTreeReader *r, const ColumnNames_t &bn,
                   const ColumnNames_t &tmpbn,
                   const std::map<std::string, std::shared_ptr<TCustomColumnBase>> &tmpBranches, TStaticSeq<S...>)
{
   // isTmpBranch has length bn.size(). Elements are true if the corresponding
   // branch is a temporary branch created with Define, false if they are
   // actual branches present in the TTree.
   std::array<bool, sizeof...(S)> isTmpColumn;
   for (auto i = 0u; i < isTmpColumn.size(); ++i)
      isTmpColumn[i] = std::find(tmpbn.begin(), tmpbn.end(), bn.at(i)) != tmpbn.end();

   // hack to expand a parameter pack without c++17 fold expressions.
   // The statement defines a variable with type std::initializer_list<int>, containing all zeroes, and SetTmpColumn or
   // SetProxy are conditionally executed as the braced init list is expanded. The final ... expands S.
   std::initializer_list<int> expander{(isTmpColumn[S]
                                           ? std::get<S>(valueTuple).SetTmpColumn(slot, tmpBranches.at(bn.at(S)).get())
                                           : std::get<S>(valueTuple).MakeProxy(r, bn.at(S)),
                                        0)...};
   (void)expander; // avoid "unused variable" warnings for expander on gcc4.9
   (void)slot;     // avoid _bogus_ "unused variable" warnings for slot on gcc 4.9
   (void)r;        // avoid "unused variable" warnings for r on gcc5.2
}

template <typename Filter>
void CheckFilter(Filter &)
{
   using FilterRet_t = typename TDF::TFunctionTraits<Filter>::Ret_t;
   static_assert(std::is_same<FilterRet_t, bool>::value, "filter functions must return a bool");
}

void CheckTmpBranch(std::string_view branchName, TTree *treePtr);

///////////////////////////////////////////////////////////////////////////////
/// Check that the callable passed to TInterface::Reduce:
/// - takes exactly two arguments of the same type
/// - has a return value of the same type as the arguments
template <typename F, typename T>
void CheckReduce(F &, TTypeList<T, T>)
{
   using Ret_t = typename TFunctionTraits<F>::Ret_t;
   static_assert(std::is_same<Ret_t, T>::value, "reduce function must have return type equal to argument type");
   return;
}

///////////////////////////////////////////////////////////////////////////////
/// This overload of CheckReduce is called if T is not a TTypeList<T,T>
template <typename F, typename T>
void CheckReduce(F &, T)
{
   static_assert(sizeof(F) == 0, "reduce function must take exactly two arguments of the same type");
}

/// Returns local BranchNames or default BranchNames according to which one should be used
const ColumnNames_t &PickBranchNames(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);

namespace ActionTypes {
struct Histo1D {
};
struct Histo2D {
};
struct Histo3D {
};
struct Profile1D {
};
struct Profile2D {
};
struct Min {
};
struct Max {
};
struct Mean {
};
struct Fill {
};
}

template <typename T, bool ISV7HISTO = !std::is_base_of<TH1, T>::value>
struct TIsV7Histo {
   const static bool fgValue = ISV7HISTO;
};

template <typename T, bool ISV7HISTO = TIsV7Histo<T>::fgValue>
struct HistoUtils {
   static void SetCanExtendAllAxes(T &h) { h.SetCanExtend(::TH1::kAllAxes); }
   static bool HasAxisLimits(T &h)
   {
      auto xaxis = h.GetXaxis();
      return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
   }
};

template <typename T>
struct HistoUtils<T, true> {
   static void SetCanExtendAllAxes(T &) {}
   static bool HasAxisLimits(T &) { return true; }
};

} // end NS TDF
} // end NS Internal
} // end NS ROOT

/// \endcond

#endif // TDFUTILS
<|endoftext|>


<commit_before>#include "html.h"
#include "el_image.h"
#include "document.h"

litehtml::el_image::el_image( litehtml::document* doc ) : html_tag(doc)
{
	m_display = display_inline_block;
}

litehtml::el_image::~el_image( void )
{

}

void litehtml::el_image::get_content_size( size& sz, int max_width )
{
	m_doc->container()->get_image_size(m_src.c_str(), 0, sz);
}

int litehtml::el_image::line_height() const
{
	return height();
}

bool litehtml::el_image::is_replaced() const
{
	return true;
}

int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
{
	int parent_width = max_width;

	// restore margins after collapse
	m_margins.top		= m_doc->cvt_units(m_css_margins.top,		m_font_size);
	m_margins.bottom	= m_doc->cvt_units(m_css_margins.bottom,	m_font_size);

	m_pos.move_to(x, y);

	litehtml::size sz;
	m_doc->container()->get_image_size(m_src.c_str(), 0, sz);

	m_pos.width		= sz.width;
	m_pos.height	= sz.height;

	if(m_css_height.is_predefined() && m_css_width.is_predefined())
	{
		m_pos.height	= sz.height;
		m_pos.width		= sz.width;

		// check for max-height
		if(!m_css_max_width.is_predefined())
		{
			int max_width = m_doc->cvt_units(m_css_max_width, m_font_size, parent_width);
			if(m_pos.width > max_width)
			{
				m_pos.width = max_width;
			}
			if(sz.width)
			{
				m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
			} else
			{
				m_pos.height = sz.height;
			}
		}

		// check for max-height
		if(!m_css_max_height.is_predefined())
		{
			int max_height = m_doc->cvt_units(m_css_max_height, m_font_size);
			if(m_pos.height > max_height)
			{
				m_pos.height = max_height;
			}
			if(sz.height)
			{
				m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
			} else
			{
				m_pos.width = sz.width;
			}
		}
	} else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
	{
		m_pos.height = (int) m_css_height.val();

		// check for max-height
		if(!m_css_max_height.is_predefined())
		{
			int max_height = m_doc->cvt_units(m_css_max_height, m_font_size);
			if(m_pos.height > max_height)
			{
				m_pos.height = max_height;
			}
		}

		if(sz.height)
		{
			m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
		} else
		{
			m_pos.width = sz.width;
		}
	} else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
	{
		m_pos.width = (int) m_css_width.calc_percent(parent_width);

		// check for max-width
		if(!m_css_max_width.is_predefined())
		{
			int max_width = m_doc->cvt_units(m_css_max_width, m_font_size, parent_width);
			if(m_pos.width > max_width)
			{
				m_pos.width = max_width;
			}
		}

		if(sz.width)
		{
			m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
		} else
		{
			m_pos.height = sz.height;
		}
	} else
	{
		m_pos.width		= (int) m_css_width.calc_percent(parent_width);
		m_pos.height	= (int) m_css_height.val();

		// check for max-height
		if(!m_css_max_height.is_predefined())
		{
			int max_height = m_doc->cvt_units(m_css_max_height, m_font_size);
			if(m_pos.height > max_height)
			{
				m_pos.height = max_height;
			}
		}

		// check for max-height
		if(!m_css_max_width.is_predefined())
		{
			int max_width = m_doc->cvt_units(m_css_max_width, m_font_size, parent_width);
			if(m_pos.width > max_width)
			{
				m_pos.width = max_width;
			}
		}
	}

	calc_outlines(parent_width);

	m_pos.x	+= content_margins_left();
	m_pos.y += content_margins_top();

	return m_pos.width + content_margins_left() + content_margins_right();
}

void litehtml::el_image::parse_attributes()
{
	m_src = get_attr(_t("src"), _t(""));

	const tchar_t* attr_height = get_attr(_t("height"));
	if(attr_height)
	{
		m_style.add_property(_t("height"), attr_height, 0, false);
	}
	const tchar_t* attr_width = get_attr(_t("width"));
	if(attr_width)
	{
		m_style.add_property(_t("width"), attr_width, 0, false);
	}
}

void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
{
	position pos = m_pos;
	pos.x += x;
	pos.y += y;

	position el_pos = pos;
	el_pos += m_padding;
	el_pos += m_borders;

	// draw standard background here
	if (el_pos.does_intersect(clip))
	{
		background* bg = get_background();
		if (bg)
		{
			background_paint bg_paint;
			init_background_paint(pos, bg_paint, bg);

			m_doc->container()->draw_background(hdc, bg_paint);
		}
	}

	// draw image as background
	if(pos.does_intersect(clip))
	{
		background_paint bg;
		bg.image				= m_src;
		bg.clip_box				= pos;
		bg.origin_box			= pos;
		bg.border_box			= pos;
		bg.border_box			+= m_padding;
		bg.border_box			+= m_borders;
		bg.repeat				= background_repeat_no_repeat;
		bg.image_size.width		= pos.width;
		bg.image_size.height	= pos.height;
		bg.border_radius		= m_css_borders.radius;
		bg.position_x			= pos.x;
		bg.position_y			= pos.y;
		m_doc->container()->draw_background(hdc, bg);
	}

	// draw borders
	if (el_pos.does_intersect(clip))
	{
		position border_box = pos;
		border_box += m_padding;
		border_box += m_borders;

		css_borders bdr = m_css_borders;
		bdr.radius.calc_percents(border_box.width, border_box.height);

		m_doc->container()->draw_borders(hdc, bdr, border_box, parent() ? false : true);
	}
}

void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
{
	html_tag::parse_styles(is_reparse);

	if(!m_src.empty())
	{
		if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
		{
			m_doc->container()->load_image(m_src.c_str(), 0, true);
		} else
		{
			m_doc->container()->load_image(m_src.c_str(), 0, false);
		}
	}
}
<commit_msg>fixed border-radius conversion for images<commit_after>#include "html.h"
#include "el_image.h"
#include "document.h"

litehtml::el_image::el_image( litehtml::document* doc ) : html_tag(doc)
{
	m_display = display_inline_block;
}

litehtml::el_image::~el_image( void )
{

}

void litehtml::el_image::get_content_size( size& sz, int max_width )
{
	m_doc->container()->get_image_size(m_src.c_str(), 0, sz);
}

int litehtml::el_image::line_height() const
{
	return height();
}

bool litehtml::el_image::is_replaced() const
{
	return true;
}

int litehtml::el_image::render( int x, int y, int max_width, bool second_pass )
{
	int parent_width = max_width;

	// restore margins after collapse
	m_margins.top		= m_doc->cvt_units(m_css_margins.top,		m_font_size);
	m_margins.bottom	= m_doc->cvt_units(m_css_margins.bottom,	m_font_size);

	m_pos.move_to(x, y);

	litehtml::size sz;
	m_doc->container()->get_image_size(m_src.c_str(), 0, sz);

	m_pos.width		= sz.width;
	m_pos.height	= sz.height;

	if(m_css_height.is_predefined() && m_css_width.is_predefined())
	{
		m_pos.height	= sz.height;
		m_pos.width		= sz.width;

		// check for max-height
		if(!m_css_max_width.is_predefined())
		{
			int max_width = m_doc->cvt_units(m_css_max_width, m_font_size, parent_width);
			if(m_pos.width > max_width)
			{
				m_pos.width = max_width;
			}
			if(sz.width)
			{
				m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
			} else
			{
				m_pos.height = sz.height;
			}
		}

		// check for max-height
		if(!m_css_max_height.is_predefined())
		{
			int max_height = m_doc->cvt_units(m_css_max_height, m_font_size);
			if(m_pos.height > max_height)
			{
				m_pos.height = max_height;
			}
			if(sz.height)
			{
				m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
			} else
			{
				m_pos.width = sz.width;
			}
		}
	} else if(!m_css_height.is_predefined() && m_css_width.is_predefined())
	{
		m_pos.height = (int) m_css_height.val();

		// check for max-height
		if(!m_css_max_height.is_predefined())
		{
			int max_height = m_doc->cvt_units(m_css_max_height, m_font_size);
			if(m_pos.height > max_height)
			{
				m_pos.height = max_height;
			}
		}

		if(sz.height)
		{
			m_pos.width = (int) (m_pos.height * (float)sz.width / (float)sz.height);
		} else
		{
			m_pos.width = sz.width;
		}
	} else if(m_css_height.is_predefined() && !m_css_width.is_predefined())
	{
		m_pos.width = (int) m_css_width.calc_percent(parent_width);

		// check for max-width
		if(!m_css_max_width.is_predefined())
		{
			int max_width = m_doc->cvt_units(m_css_max_width, m_font_size, parent_width);
			if(m_pos.width > max_width)
			{
				m_pos.width = max_width;
			}
		}

		if(sz.width)
		{
			m_pos.height = (int) ((float) m_pos.width * (float) sz.height / (float)sz.width);
		} else
		{
			m_pos.height = sz.height;
		}
	} else
	{
		m_pos.width		= (int) m_css_width.calc_percent(parent_width);
		m_pos.height	= (int) m_css_height.val();

		// check for max-height
		if(!m_css_max_height.is_predefined())
		{
			int max_height = m_doc->cvt_units(m_css_max_height, m_font_size);
			if(m_pos.height > max_height)
			{
				m_pos.height = max_height;
			}
		}

		// check for max-height
		if(!m_css_max_width.is_predefined())
		{
			int max_width = m_doc->cvt_units(m_css_max_width, m_font_size, parent_width);
			if(m_pos.width > max_width)
			{
				m_pos.width = max_width;
			}
		}
	}

	calc_outlines(parent_width);

	m_pos.x	+= content_margins_left();
	m_pos.y += content_margins_top();

	return m_pos.width + content_margins_left() + content_margins_right();
}

void litehtml::el_image::parse_attributes()
{
	m_src = get_attr(_t("src"), _t(""));

	const tchar_t* attr_height = get_attr(_t("height"));
	if(attr_height)
	{
		m_style.add_property(_t("height"), attr_height, 0, false);
	}
	const tchar_t* attr_width = get_attr(_t("width"));
	if(attr_width)
	{
		m_style.add_property(_t("width"), attr_width, 0, false);
	}
}

void litehtml::el_image::draw( uint_ptr hdc, int x, int y, const position* clip )
{
	position pos = m_pos;
	pos.x += x;
	pos.y += y;

	position el_pos = pos;
	el_pos += m_padding;
	el_pos += m_borders;

	// draw standard background here
	if (el_pos.does_intersect(clip))
	{
		background* bg = get_background();
		if (bg)
		{
			background_paint bg_paint;
			init_background_paint(pos, bg_paint, bg);

			m_doc->container()->draw_background(hdc, bg_paint);
		}
	}

	// draw image as background
	if(pos.does_intersect(clip))
	{
		background_paint bg;
		bg.image				= m_src;
		bg.clip_box				= pos;
		bg.origin_box			= pos;
		bg.border_box			= pos;
		bg.border_box			+= m_padding;
		bg.border_box			+= m_borders;
		bg.repeat				= background_repeat_no_repeat;
		bg.image_size.width		= pos.width;
		bg.image_size.height	= pos.height;
		bg.border_radius		= m_css_borders.radius;
		bg.position_x			= pos.x;
		bg.position_y			= pos.y;
		bg.border_radius.calc_percents(bg.border_box.width, bg.border_box.height);
		m_doc->container()->draw_background(hdc, bg);
	}

	// draw borders
	if (el_pos.does_intersect(clip))
	{
		position border_box = pos;
		border_box += m_padding;
		border_box += m_borders;

		css_borders bdr = m_css_borders;
		bdr.radius.calc_percents(border_box.width, border_box.height);

		m_doc->container()->draw_borders(hdc, bdr, border_box, parent() ? false : true);
	}
}

void litehtml::el_image::parse_styles( bool is_reparse /*= false*/ )
{
	html_tag::parse_styles(is_reparse);

	if(!m_src.empty())
	{
		if(!m_css_height.is_predefined() && !m_css_width.is_predefined())
		{
			m_doc->container()->load_image(m_src.c_str(), 0, true);
		} else
		{
			m_doc->container()->load_image(m_src.c_str(), 0, false);
		}
	}
}
<|endoftext|>