<commit_before>#include <Core/Geometry/IndexedGeometry.hpp>
#include <iterator>

namespace Ra {
namespace Core {
namespace Geometry {

MultiIndexedGeometry::MultiIndexedGeometry( const MultiIndexedGeometry& other ) :
    AttribArrayGeometry( other ) {
    deepCopy( other );
}

MultiIndexedGeometry::MultiIndexedGeometry( MultiIndexedGeometry&& other ) :
    AttribArrayGeometry( std::move( other ) ), m_indices( std::move( other.m_indices ) ) {}

MultiIndexedGeometry::MultiIndexedGeometry( const AttribArrayGeometry& other ) :
    AttribArrayGeometry( other ) {}

MultiIndexedGeometry::MultiIndexedGeometry( AttribArrayGeometry&& other ) :
    AttribArrayGeometry( std::move( other ) ) {}

MultiIndexedGeometry& MultiIndexedGeometry::operator=( const MultiIndexedGeometry& other ) {
    AttribArrayGeometry::operator=( other );
    deepCopy( other );
    notify();
    invalidateAabb();
    return *this;
}

MultiIndexedGeometry& MultiIndexedGeometry::operator=( MultiIndexedGeometry&& other ) {
    AttribArrayGeometry::operator=( std::move( other ) );
    m_indices                    = std::move( other.m_indices );
    notify();
    invalidateAabb();
    return *this;
}

void MultiIndexedGeometry::clear() {
    AttribArrayGeometry::clear();
    deepClear();
    notify();
    invalidateAabb();
}

void MultiIndexedGeometry::copy( const MultiIndexedGeometry& other ) {
    AttribArrayGeometry::copyBaseGeometry( other );
    deepCopy( other );
    notify();
    invalidateAabb();
}

/// \todo Implement MultiIndexedGeometry::checkConsistency
void MultiIndexedGeometry::checkConsistency() const {
#ifdef CORE_DEBUG
#endif
}

bool
/// \todo Implement MultiIndexedGeometry::append
MultiIndexedGeometry::append( const MultiIndexedGeometry& other ) {
    bool isCopyComplete = true;
    for ( const auto& [key, value] : m_indices )
    {
        auto it = other.m_indices.find( key );
        if ( !( it == other.m_indices.end() && value.second->append( *( it->second.second ) ) ) )
            isCopyComplete = false;
    }

    notify();
    invalidateAabb();
    return isCopyComplete;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

bool MultiIndexedGeometry::containsLayer( const LayerSemantic& semanticName ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() ) return true;
    }
    return false;
}

bool MultiIndexedGeometry::containsLayer( const LayerSemanticCollection& semantics ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first == semantics ) return true;
    }
    return false;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

size_t MultiIndexedGeometry::countLayers( const LayerSemantic& semanticName ) const {
    size_t c = 0;
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() ) ++c;
    }
    return c;
}

size_t MultiIndexedGeometry::countLayers( const LayerSemanticCollection& semantics ) const {
    size_t c = 0;
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first == semantics ) ++c;
    }
    return c;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

std::pair<MultiIndexedGeometry::LayerKeyType, const GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrence( const LayerSemantic& semanticName ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() ) return {key, *( value.second )};
    }
    throw std::out_of_range( "Layer entry not found" );
}

std::pair<MultiIndexedGeometry::LayerKeyType, const GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrence( const LayerSemanticCollection& semantics ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first == semantics ) return {key, *( value.second )};
    }
    throw std::out_of_range( "Layer entry not found" );
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

std::pair<MultiIndexedGeometry::LayerKeyType, GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrenceWithLock( const LayerSemantic& semanticName ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() )
        {
            CORE_ASSERT( !value.first, "try to get already locked layer" );
            value.first = true;
            return {key, *( value.second )};
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

std::pair<MultiIndexedGeometry::LayerKeyType, GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrenceWithLock( const LayerSemanticCollection& semantics ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first == semantics )
        {
            CORE_ASSERT( !value.first, "try to get already locked layer" );
            value.first = true;
            return {key, *( value.second )};
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

GeometryIndexLayerBase& MultiIndexedGeometry::getLayerWithLock( const LayerKeyType& layerKey ) {
    auto& p = m_indices.at( layerKey );
    CORE_ASSERT( !p.first, "try to get already locked layer" );
    p.first = true;
    return *( p.second );
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

void MultiIndexedGeometry::unlockFirstLayerOccurrence( const LayerSemantic& semanticName ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() )
        {
            CORE_ASSERT( value.first, "try to release unlocked layer" );
            value.first = false;
            notify();
            return;
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

void MultiIndexedGeometry::unlockFirstLayerOccurrence( const LayerSemanticCollection& semantics ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first == semantics )
        {
            CORE_ASSERT( value.first, "try to release unlocked layer" );
            value.first = false;
            notify();
            return;
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

void MultiIndexedGeometry::unlockLayer( const LayerKeyType& layerKey ) {
    auto& p = m_indices.at( layerKey );
    CORE_ASSERT( p.first, "try to release unlocked layer" );
    p.first = true;
    notify();
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

bool MultiIndexedGeometry::addLayer( std::unique_ptr<GeometryIndexLayerBase>&& layer,
                                     const std::string& layerName ) {
    LayerKeyType key {layer->semantics(), layerName};
    if ( m_indices.find( key ) != m_indices.end() ) return false;

    m_indices.insert( {key, std::make_pair( false, layer.release() )} );

    notify();
    return true;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void MultiIndexedGeometry::deepCopy( const MultiIndexedGeometry& other ) {
    m_indices = other.m_indices;
    for ( auto& el : m_indices )
        el.second.second = el.second.second->duplicate(); // replace copied entries by duplicates
}
void MultiIndexedGeometry::deepClear() {
    for ( auto& el : m_indices )
        delete el.second.second;
    m_indices.clear();
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

std::size_t MultiIndexedGeometry::KeyHash::operator()( const LayerKeyType& k ) const {
    // Mix semantic collection into a single identifier string
    std::ostringstream stream;
    std::copy( k.first.begin(), k.first.end(), std::ostream_iterator<std::string>( stream, "" ) );
    std::string result = stream.str();
    std::sort( result.begin(), result.end() );

    // Combine with layer name hash
    return std::hash<std::string> {}( result ) ^ ( std::hash<std::string> {}( k.second ) << 1 );
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

void PointCloudIndexLayer::linearIndices( const AttribArrayGeometry& attr ) {
    auto nbVert = attr.vertices().size();
    collection().resize( nbVert );
    collection().getMap() = IndexContainerType::Matrix::LinSpaced( nbVert, 0, nbVert - 1 );
}

} // namespace Geometry
} // namespace Core
} // namespace Ra
<commit_msg>[core] fix from code review: invalidate aabb before notify<commit_after>#include <Core/Geometry/IndexedGeometry.hpp>
#include <iterator>

namespace Ra {
namespace Core {
namespace Geometry {

MultiIndexedGeometry::MultiIndexedGeometry( const MultiIndexedGeometry& other ) :
    AttribArrayGeometry( other ) {
    deepCopy( other );
}

MultiIndexedGeometry::MultiIndexedGeometry( MultiIndexedGeometry&& other ) :
    AttribArrayGeometry( std::move( other ) ), m_indices( std::move( other.m_indices ) ) {}

MultiIndexedGeometry::MultiIndexedGeometry( const AttribArrayGeometry& other ) :
    AttribArrayGeometry( other ) {}

MultiIndexedGeometry::MultiIndexedGeometry( AttribArrayGeometry&& other ) :
    AttribArrayGeometry( std::move( other ) ) {}

MultiIndexedGeometry& MultiIndexedGeometry::operator=( const MultiIndexedGeometry& other ) {
    invalidateAabb();
    AttribArrayGeometry::operator=( other );
    deepCopy( other );
    notify();
    return *this;
}

MultiIndexedGeometry& MultiIndexedGeometry::operator=( MultiIndexedGeometry&& other ) {
    invalidateAabb();
    AttribArrayGeometry::operator=( std::move( other ) );
    m_indices                    = std::move( other.m_indices );
    notify();
    return *this;
}

void MultiIndexedGeometry::clear() {
    invalidateAabb();
    AttribArrayGeometry::clear();
    deepClear();
    notify();
}

void MultiIndexedGeometry::copy( const MultiIndexedGeometry& other ) {
    invalidateAabb();
    AttribArrayGeometry::copyBaseGeometry( other );
    deepCopy( other );
    notify();
}

/// \todo Implement MultiIndexedGeometry::checkConsistency
void MultiIndexedGeometry::checkConsistency() const {
#ifdef CORE_DEBUG
#endif
}

bool
/// \todo Implement MultiIndexedGeometry::append
MultiIndexedGeometry::append( const MultiIndexedGeometry& other ) {
    invalidateAabb();
    bool isCopyComplete = true;
    for ( const auto& [key, value] : m_indices )
    {
        auto it = other.m_indices.find( key );
        if ( !( it == other.m_indices.end() && value.second->append( *( it->second.second ) ) ) )
            isCopyComplete = false;
    }

    notify();
    return isCopyComplete;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

bool MultiIndexedGeometry::containsLayer( const LayerSemantic& semanticName ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() ) return true;
    }
    return false;
}

bool MultiIndexedGeometry::containsLayer( const LayerSemanticCollection& semantics ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first == semantics ) return true;
    }
    return false;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

size_t MultiIndexedGeometry::countLayers( const LayerSemantic& semanticName ) const {
    size_t c = 0;
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() ) ++c;
    }
    return c;
}

size_t MultiIndexedGeometry::countLayers( const LayerSemanticCollection& semantics ) const {
    size_t c = 0;
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first == semantics ) ++c;
    }
    return c;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

std::pair<MultiIndexedGeometry::LayerKeyType, const GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrence( const LayerSemantic& semanticName ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() ) return {key, *( value.second )};
    }
    throw std::out_of_range( "Layer entry not found" );
}

std::pair<MultiIndexedGeometry::LayerKeyType, const GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrence( const LayerSemanticCollection& semantics ) const {
    for ( const auto& [key, value] : m_indices )
    {
        if ( key.first == semantics ) return {key, *( value.second )};
    }
    throw std::out_of_range( "Layer entry not found" );
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

std::pair<MultiIndexedGeometry::LayerKeyType, GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrenceWithLock( const LayerSemantic& semanticName ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() )
        {
            CORE_ASSERT( !value.first, "try to get already locked layer" );
            value.first = true;
            return {key, *( value.second )};
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

std::pair<MultiIndexedGeometry::LayerKeyType, GeometryIndexLayerBase&>
MultiIndexedGeometry::getFirstLayerOccurrenceWithLock( const LayerSemanticCollection& semantics ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first == semantics )
        {
            CORE_ASSERT( !value.first, "try to get already locked layer" );
            value.first = true;
            return {key, *( value.second )};
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

GeometryIndexLayerBase& MultiIndexedGeometry::getLayerWithLock( const LayerKeyType& layerKey ) {
    auto& p = m_indices.at( layerKey );
    CORE_ASSERT( !p.first, "try to get already locked layer" );
    p.first = true;
    return *( p.second );
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

void MultiIndexedGeometry::unlockFirstLayerOccurrence( const LayerSemantic& semanticName ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first.find( semanticName ) != key.first.end() )
        {
            CORE_ASSERT( value.first, "try to release unlocked layer" );
            value.first = false;
            notify();
            return;
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

void MultiIndexedGeometry::unlockFirstLayerOccurrence( const LayerSemanticCollection& semantics ) {
    for ( auto& [key, value] : m_indices )
    {
        if ( key.first == semantics )
        {
            CORE_ASSERT( value.first, "try to release unlocked layer" );
            value.first = false;
            notify();
            return;
        }
    }
    throw std::out_of_range( "Layer entry not found" );
}

void MultiIndexedGeometry::unlockLayer( const LayerKeyType& layerKey ) {
    auto& p = m_indices.at( layerKey );
    CORE_ASSERT( p.first, "try to release unlocked layer" );
    p.first = true;
    notify();
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

bool MultiIndexedGeometry::addLayer( std::unique_ptr<GeometryIndexLayerBase>&& layer,
                                     const std::string& layerName ) {
    LayerKeyType key {layer->semantics(), layerName};
    if ( m_indices.find( key ) != m_indices.end() ) return false;

    m_indices.insert( {key, std::make_pair( false, layer.release() )} );

    notify();
    return true;
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void MultiIndexedGeometry::deepCopy( const MultiIndexedGeometry& other ) {
    m_indices = other.m_indices;
    for ( auto& el : m_indices )
        el.second.second = el.second.second->duplicate(); // replace copied entries by duplicates
}
void MultiIndexedGeometry::deepClear() {
    for ( auto& el : m_indices )
        delete el.second.second;
    m_indices.clear();
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

std::size_t MultiIndexedGeometry::KeyHash::operator()( const LayerKeyType& k ) const {
    // Mix semantic collection into a single identifier string
    std::ostringstream stream;
    std::copy( k.first.begin(), k.first.end(), std::ostream_iterator<std::string>( stream, "" ) );
    std::string result = stream.str();
    std::sort( result.begin(), result.end() );

    // Combine with layer name hash
    return std::hash<std::string> {}( result ) ^ ( std::hash<std::string> {}( k.second ) << 1 );
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

void PointCloudIndexLayer::linearIndices( const AttribArrayGeometry& attr ) {
    auto nbVert = attr.vertices().size();
    collection().resize( nbVert );
    collection().getMap() = IndexContainerType::Matrix::LinSpaced( nbVert, 0, nbVert - 1 );
}

} // namespace Geometry
} // namespace Core
} // namespace Ra
<|endoftext|>


<commit_before>/*##############################################################################

    Copyright (C) 2011 HPCC Systems.

    All rights reserved. This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
############################################################################## */

#ifndef _THACTIVITYMASTER_HPP
#define _THACTIVITYMASTER_HPP

#ifdef _WIN32
 #ifdef ACTIVITYMASTERS_EXPORTS
  #define actmaster_decl __declspec(dllexport)
 #else
  #define actmaster_decl __declspec(dllimport)
 #endif
#else
 #define actmaster_decl
#endif

enum masterEvents { ev_unknown, ev_done };

#include "thmfilemanager.hpp"

interface IGetSlaveData : extends IInterface
{
    virtual bool getData(unsigned slave, unsigned part, MemoryBuffer &mb) = 0;
};

struct CSlaveMap : public IArrayOf<IPartDescriptor>, public CInterface
{
};

class CSlavePartMapping : public CSimpleInterface, implements IInterface
{
    CIArrayOf<CSlaveMap> maps;
    UnsignedArray partToNode;
    unsigned fileWidth;
    bool local;
    StringAttr logicalName;
    Linked<IFileDescriptor> fileDesc;
    Linked<IUserDescriptor> userDesc;
public:
    IMPLEMENT_IINTERFACE_USING(CSimpleInterface);

    CSlavePartMapping(const char *logicalName, IFileDescriptor &fileDesc, IUserDescriptor *userDesc, IGroup &localGroup, bool local, bool index, IHash *hash, IDistributedSuperFile *super);
    unsigned queryNode(unsigned part)
    {
        if (part > partToNode.ordinality()) return NotFound;
        return partToNode.item(part);
    }
    unsigned queryParts() { return partToNode.ordinality(); }
    unsigned queryNumMaps() { return maps.ordinality(); }
    unsigned queryMapWidth(unsigned map) { return maps.isItem(map)?maps.item(map).ordinality():0; }
    void serializeFileOffsetMap(MemoryBuffer &mb);
    void getParts(unsigned i, IArrayOf<IPartDescriptor> &parts);
    void serializeMap(unsigned map, MemoryBuffer &mb, IGetSlaveData *extra=NULL);
    static void serializeNullMap(MemoryBuffer &mb);
    static void serializeNullOffsetMap(MemoryBuffer &mb);
};
CSlavePartMapping *getFileSlaveMaps(const char *logicalName, IFileDescriptor &file, IUserDescriptor *userDesc, IGroup &localGroup, bool local=false, bool index=false, IHash *hash=NULL, IDistributedSuperFile *super=NULL);
void checkSuperFileOwnership(IDistributedFile &file);

actmaster_decl void loadMasters();
#endif
<commit_msg>Fix gh-1002 - csv in child query issue<commit_after>/*##############################################################################

    Copyright (C) 2011 HPCC Systems.

    All rights reserved. This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
############################################################################## */

#ifndef _THACTIVITYMASTER_HPP
#define _THACTIVITYMASTER_HPP

#ifdef _WIN32
 #ifdef ACTIVITYMASTERS_EXPORTS
  #define actmaster_decl __declspec(dllexport)
 #else
  #define actmaster_decl __declspec(dllimport)
 #endif
#else
 #define actmaster_decl
#endif

enum masterEvents { ev_unknown, ev_done };

#include "thmfilemanager.hpp"

interface IGetSlaveData : extends IInterface
{
    virtual bool getData(unsigned slave, unsigned part, MemoryBuffer &mb) = 0;
};

struct CSlaveMap : public IArrayOf<IPartDescriptor>, public CInterface
{
};

class CSlavePartMapping : public CSimpleInterface, implements IInterface
{
    CIArrayOf<CSlaveMap> maps;
    UnsignedArray partToNode;
    unsigned fileWidth;
    bool local;
    StringAttr logicalName;
    Linked<IFileDescriptor> fileDesc;
    Linked<IUserDescriptor> userDesc;
public:
    IMPLEMENT_IINTERFACE_USING(CSimpleInterface);

    CSlavePartMapping(const char *logicalName, IFileDescriptor &fileDesc, IUserDescriptor *userDesc, IGroup &localGroup, bool local, bool index, IHash *hash, IDistributedSuperFile *super);
    unsigned queryNode(unsigned part)
    {
        if (part > partToNode.ordinality()) return NotFound;
        return partToNode.item(part);
    }
    unsigned queryParts() { return partToNode.ordinality(); }
    unsigned queryNumMaps() { return maps.ordinality(); }
    unsigned queryMapWidth(unsigned map)
    {
        if (local)
            map = 0;
        if (!maps.isItem(map))
            return 0;
        return maps.item(map).ordinality();
    }
    void serializeFileOffsetMap(MemoryBuffer &mb);
    void getParts(unsigned i, IArrayOf<IPartDescriptor> &parts);
    void serializeMap(unsigned map, MemoryBuffer &mb, IGetSlaveData *extra=NULL);
    static void serializeNullMap(MemoryBuffer &mb);
    static void serializeNullOffsetMap(MemoryBuffer &mb);
};
CSlavePartMapping *getFileSlaveMaps(const char *logicalName, IFileDescriptor &file, IUserDescriptor *userDesc, IGroup &localGroup, bool local=false, bool index=false, IHash *hash=NULL, IDistributedSuperFile *super=NULL);
void checkSuperFileOwnership(IDistributedFile &file);

actmaster_decl void loadMasters();
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/osr/osr_output_device.h"

#include "third_party/skia/include/core/SkDevice.h"
#include "ui/gfx/skia_util.h"

namespace atom {

OffScreenOutputDevice::OffScreenOutputDevice(bool transparent,
                                             const OnPaintCallback& callback)
  : transparent_(transparent),
    callback_(callback),
    active_(false) {
  DCHECK(!callback_.is_null());
}

OffScreenOutputDevice::~OffScreenOutputDevice() {
}

void OffScreenOutputDevice::Resize(
    const gfx::Size& pixel_size, float scale_factor) {
  scale_factor_ = scale_factor;

  if (viewport_pixel_size_ == pixel_size) return;
  viewport_pixel_size_ = pixel_size;

  canvas_.reset();
  bitmap_.reset(new SkBitmap);
  bitmap_->allocN32Pixels(viewport_pixel_size_.width(),
                          viewport_pixel_size_.height(),
                          !transparent_);
  if (bitmap_->drawsNothing()) {
    NOTREACHED();
    bitmap_.reset();
    return;
  }

  if (transparent_)
    bitmap_->eraseARGB(0, 0, 0, 0);

  canvas_.reset(new SkCanvas(*bitmap_));
}

SkCanvas* OffScreenOutputDevice::BeginPaint(const gfx::Rect& damage_rect) {
  DCHECK(canvas_.get());
  DCHECK(bitmap_.get());

  damage_rect_ = damage_rect;

  return canvas_.get();
}

void OffScreenOutputDevice::EndPaint() {
  DCHECK(canvas_.get());
  DCHECK(bitmap_.get());

  if (!bitmap_.get()) return;

  cc::SoftwareOutputDevice::EndPaint();

  if (active_)
    OnPaint(damage_rect_);
}

void OffScreenOutputDevice::SetActive(bool active) {
  if (active == active_)
    return;
  active_ = active;

  if (active_)
    OnPaint(gfx::Rect(viewport_pixel_size_));
}

void OffScreenOutputDevice::OnPaint(const gfx::Rect& damage_rect) {
  gfx::Rect rect = damage_rect;

  rect.Intersect(gfx::Rect(viewport_pixel_size_));
  if (rect.IsEmpty())
    return;

  SkAutoLockPixels bitmap_pixels_lock(*bitmap_);
  callback_.Run(rect, *bitmap_);
}

}  // namespace atom
<commit_msg>Update OffScreenOutputDevice<commit_after>// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/osr/osr_output_device.h"

#include "third_party/skia/include/core/SkDevice.h"
#include "ui/gfx/skia_util.h"

namespace atom {

OffScreenOutputDevice::OffScreenOutputDevice(bool transparent,
                                             const OnPaintCallback& callback)
  : transparent_(transparent),
    callback_(callback),
    active_(false) {
  DCHECK(!callback_.is_null());
}

OffScreenOutputDevice::~OffScreenOutputDevice() {
}

void OffScreenOutputDevice::Resize(
    const gfx::Size& pixel_size, float scale_factor) {
  if (viewport_pixel_size_ == pixel_size) return;
  viewport_pixel_size_ = pixel_size;

  canvas_.reset();
  bitmap_.reset(new SkBitmap);
  bitmap_->allocN32Pixels(viewport_pixel_size_.width(),
                          viewport_pixel_size_.height(),
                          !transparent_);
  if (bitmap_->drawsNothing()) {
    NOTREACHED();
    bitmap_.reset();
    return;
  }

  if (transparent_)
    bitmap_->eraseARGB(0, 0, 0, 0);

  canvas_.reset(new SkCanvas(*bitmap_));
}

SkCanvas* OffScreenOutputDevice::BeginPaint(const gfx::Rect& damage_rect) {
  DCHECK(canvas_.get());
  DCHECK(bitmap_.get());

  damage_rect_ = damage_rect;

  return canvas_.get();
}

void OffScreenOutputDevice::EndPaint() {
  DCHECK(canvas_.get());
  DCHECK(bitmap_.get());

  if (!bitmap_.get()) return;

  cc::SoftwareOutputDevice::EndPaint();

  if (active_)
    OnPaint(damage_rect_);
}

void OffScreenOutputDevice::SetActive(bool active) {
  if (active == active_)
    return;
  active_ = active;

  if (active_)
    OnPaint(gfx::Rect(viewport_pixel_size_));
}

void OffScreenOutputDevice::OnPaint(const gfx::Rect& damage_rect) {
  gfx::Rect rect = damage_rect;

  rect.Intersect(gfx::Rect(viewport_pixel_size_));
  if (rect.IsEmpty())
    return;

  SkAutoLockPixels bitmap_pixels_lock(*bitmap_);
  callback_.Run(rect, *bitmap_);
}

}  // namespace atom
<|endoftext|>


<commit_before>#include <vtkVersion.h>

int main(int, char *[])
{
  std::cout << vtkVersion::GetVTKSourceVersion() << std::endl;
  std::cout << vtkVersion::GetVTKMajorVersion() << std::endl;
  std::cout << vtkVersion::GetVTKMinorVersion() << std::endl;

  return EXIT_SUCCESS;
}
<commit_msg>Updating CheckVTKVersion<commit_after>#include <vtkVersion.h>

#ifdef VTK_VERSION_NUMBER
#if VTK_VERSION_NUMBER >= 90000000000ULL
#define VTK_VER_GE_90 1
#endif
#else
#define VTK_VERSION_NUMBER_NOT_DEFINED 1
#endif

namespace {
/**
 * Check the VTK version.
 *
 * @param major: Major version.
 * @param major: Minor version.
 * @param major: Build version.
 *
 * @return True if the requested VTK version is greater or equal to the actual
 * VTK version.
 */
bool VTKVersionOk(unsigned long long const& major,
                  unsigned long long const& minor,
                  unsigned long long const& build);

} // namespace

int main(int, char*[])
{
#ifdef VTK_VERSION_NUMBER
  std::cout << "Source version: " << vtkVersion::GetVTKSourceVersion()
            << std::endl;
  std::cout << "Major Version : " << vtkVersion::GetVTKMajorVersion()
            << std::endl;
  std::cout << "Minor Version : " << vtkVersion::GetVTKMinorVersion()
            << std::endl;
#elif VTK_VERSION_NUMBER_NOT_DEFINED
  std::cout << "VTK VTK_VERSION_NUMBER is not defined." << std::endl;
  std::cout << "VTK Major Version: " << VTK_MAJOR_VERSION << std::endl;
  std::cout << "VTK Minor Version: " << VTK_MINOR_VERSION << std::endl;
#endif

#ifdef VTK_VER_GE_90
  std::cout << "VTK Version is >= " << VTK_VERSION_NUMBER << std::endl;
#endif

  if (!VTKVersionOk(8, 90, 0))
  {
    std::cerr << "You need VTK version 8.90 or greater to run this program."
              << std::endl;
    return EXIT_FAILURE;
  }
  else
  {
    std::cout << "You have the needed VTK version" << endl;
  }

  return EXIT_SUCCESS;
}

namespace {
bool VTKVersionOk(unsigned long long const& major,
                  unsigned long long const& minor,
                  unsigned long long const& build)
{
  unsigned long long neededVersion =
      10000000000ULL * major + 100000000ULL * minor + build;
#ifndef VTK_VERSION_NUMBER
  auto ver = vtkSmartPointer<vtkVersion>();
  unsigned long long vtk_version_number =
      10000000000ULL * ver->GetVTKMajorVersion() +
      100000000ULL * ver->GetVTKMinorVersion() + ver->GetVTKBuildVersion();
  if (vtk_version_number >= neededVersion)
  {
    return true;
  }
  return false;
#else
  if (VTK_VERSION_NUMBER >= neededVersion)
  {
    return true;
  }
  return false;
#endif
}

} // namespace
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////
// sect2.cpp -- Emit the Section2 Procedures
// Date: Sat Nov 30 13:50:35 2013
///////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <assert.h>

#include <iostream>
#include <sstream>

#include "glue.hpp"
#include "comp.hpp"
#include "config.hpp"

void
emit_section2() {
	char sgenset[32];
	std::fstream ads, adb;

	sprintf(sgenset,"%04d",config.section2.genset);

	std::cout << "Genset " << sgenset << " emit section2\n";

	if ( !gcc_open(ads,config.section2.genset,".ads") )
		exit(3);

	if ( !gcc_open(adb,config.section2.genset,".adb") )
		exit(3);

	ads << "\n";

	for ( auto it=config.section2.funcs.begin(); it != config.section2.funcs.end(); ++it ) {
		s_config::s_section2::s_func& func = *it;
		std::stringstream proto;
		std::string binding_name = "UX_";
		std::vector<std::string> macros_used;
		bool skip = false;

		if ( func.cases.size() > 0 ) {
			skip = true;		// For now

			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() ) {
							skip = false;
							macros_used.push_back(the_case);
						}
					}
				}
			}
		}

		if ( skip )
			continue;			// No cases are define macro names

		binding_name += func.c_name;		// Default internal c binding name

		if ( func.alt_name != "" )
			binding_name = func.alt_name;

		proto << func.type;
		if ( func.type != "function" )
			proto << "procedure " << func.ada_name;
		else	proto << "function " << func.ada_name;

		if ( func.aargs.size() > 0 ) {
			proto << "(";

			bool f=true;

			for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
				s_config::s_section2::s_func::s_aarg& arg = *ait;

				if ( !f ) {
					proto << "; ";
				} else	{
					f = false;
				}
				proto << arg.name << ": ";
				if ( arg.io != "in" )
					proto << arg.io << " ";
				proto << arg.type;
			}
			proto << ")";
			if ( func.type == "function" )
				proto << " return " << func.returns;
		}

		//////////////////////////////////////////////////////
		// Generate the prototype in the Spec
		//////////////////////////////////////////////////////

		for ( auto mit = macros_used.begin(); mit != macros_used.end(); ++mit ) {
			const std::string macro_name = *mit;
			ads << "   -- " << macro_name << "\n";
		}

		ads << "   " << proto.str() << ";\n";
		if ( func.finline )
			ads << "   pragma Inline(" << func.ada_name << ");\n\n";

		//////////////////////////////////////////////////////
		// The body
		//////////////////////////////////////////////////////

		adb 	<< "   " << proto.str() << " is\n";

		// Use clauses
		for ( auto uit=func.use_clauses.begin(); uit != func.use_clauses.end(); ++uit ) {
			const std::string& use_clause = *uit;
			adb << "      use " << use_clause << ";\n";
		}

		// C Function Declaration
		if ( func.returns != "" )
			adb << "      function " << binding_name;
		else	adb << "      procedure " << binding_name;
		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto cit=func.cargs.begin(); cit != func.cargs.end(); ++cit ) {
				const s_config::s_section2::s_func::s_carg& arg = *cit;
				if ( !f )
					adb << "; ";
				else	f = false;
				adb << arg.name << " : " << arg.type;
			}
			adb << ")";
		}

		if ( func.returns != "" )
			adb << " return " << func.returns << ";\n";
		else	adb << ";\n";

		//  pragma Import(C,UX_close,"close");
		adb << "      pragma Import(C," << binding_name << ",\"" << func.c_name << "\");\n";

		// Temporaries
		for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
			s_config::s_section2::s_func::s_aarg& arg = *ait;

			if ( arg.io == "in" && arg.temp != "" ) {
				std::stringstream s;
				std::string tempname;

				s << "T" << arg.argno;
				tempname = s.str();

				adb << "      " << tempname << " : " << arg.type
				    << " := " << arg.tempval << ";\n";
			}
		}

		// Temporary variables
		for ( auto t=func.temps.begin(); t != func.temps.end(); ++t ) {
			s_config::s_section2::s_func::s_temp& temp = *t;

			adb << "      " << temp.name << " : " << temp.type;
			if ( temp.init != "" )
				adb << " := " << temp.init;
			adb << ";\n";
		}

		// Return value:
		if ( func.rname != "" ) {
			adb << "      " << func.rname << " : " << func.returns << ";\n";
		}

		adb	<< "   begin\n";

		// Insert pre-checks
		if ( func.prechecks.size() > 0 ) {
			for ( auto pit=func.prechecks.cbegin(); pit != func.prechecks.cend(); ++pit ) {
				const std::string& cond = *pit;
				adb << "      if not ( " << cond << " ) then\n"
				    << "         " << func.on_error << ";\n"
				    << "         return;\n"
				    << "      end if;\n";
			}
		}

		// Insert case & when checks
		if ( func.cases.size() > 0 ) {
			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					std::vector<std::string> kvec;

					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() )
							kvec.push_back(the_case);
					}

					if ( kvec.size() > 0 ) {
						adb << "      case " << varname << " is\n";

						for ( auto vit=kvec.cbegin(); vit != kvec.cend(); ++vit ) {
							const std::string& the_case = *vit;
							adb << "         when " << the_case << "=>\n"
							    << "            null;\n";
						}

						adb << "         when others =>\n"
						    << "            Error := EINVAL;\n";

						if ( centry.on_error != "" )
							adb << "            " << centry.on_error << ";\n";

						adb << "            return;\n"
						    << "      end case;\n";
					}
				}
			}
		}

		if ( func.rname != "" ) {
			adb << "      " << func.rname << " := " << binding_name;
		} else	{
			adb << "      " << binding_name;
		}

		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto fit=func.cargs.begin(); fit != func.cargs.end(); ++fit ) {
				s_config::s_section2::s_func::s_carg& arg = *fit;
				if ( f )
					f = false;
				else	adb << ",";
				adb << arg.from;
			}
			adb << ")";
		}
		adb 	<< ";\n";

		// Output values:
		for ( auto oit=func.aargs.begin(); oit != func.aargs.end(); ++oit ) {
			s_config::s_section2::s_func::s_aarg& arg = *oit;

			if ( arg.from != "implied" ) {
				if ( arg.io == "out" || arg.io == "in out" ) {
					adb << "      " << arg.name << " := "
					    << arg.from << ";\n";
				}
			}
		}

		adb	<< "   end " << func.ada_name << ";\n\n";
	}

	ads.close();
	adb.close();
}

// End sect2.cpp
<commit_msg>Now emits proper Ada functions + defines adafpx_macro_* when required<commit_after>//////////////////////////////////////////////////////////////////////
// sect2.cpp -- Emit the Section2 Procedures
// Date: Sat Nov 30 13:50:35 2013
///////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <assert.h>

#include <iostream>
#include <sstream>
#include <unordered_set>

#include "glue.hpp"
#include "comp.hpp"
#include "config.hpp"

void
emit_section2() {
	char sgenset[32];
	std::fstream ads, adb, cc;
	std::unordered_set<std::string> inclset;

	sprintf(sgenset,"%04d",config.section2.genset);

	std::cout << "Genset " << sgenset << " emit section2\n";

	if ( !gcc_open(ads,config.section2.genset,".ads") )
		exit(3);

	if ( !gcc_open(adb,config.section2.genset,".adb") )
		exit(3);

	ads << "\n";

	for ( auto it=config.section2.funcs.begin(); it != config.section2.funcs.end(); ++it ) {
		s_config::s_section2::s_func& func = *it;
		std::stringstream proto;
		std::string binding_name = "UX_";
		std::vector<std::string> macros_used;
		bool skip = false;

		if ( func.cases.size() > 0 ) {
			skip = true;		// For now

			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() ) {
							skip = false;
							macros_used.push_back(the_case);
						}
					}
				}
			}
		}

		if ( skip )
			continue;			// No cases are define macro names

		binding_name += func.c_name;		// Default internal c binding name

		if ( func.alt_name != "" )
			binding_name = func.alt_name;

		proto << func.type << " " << func.ada_name;

		if ( func.aargs.size() > 0 ) {
			proto << "(";

			bool f=true;

			for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
				s_config::s_section2::s_func::s_aarg& arg = *ait;

				if ( !f ) {
					proto << "; ";
				} else	{
					f = false;
				}
				proto << arg.name << ": ";
				if ( arg.io != "in" )
					proto << arg.io << " ";
				proto << arg.type;
			}
			proto << ")";
			if ( func.type == "function" )
				proto << " return " << func.ada_return;
		}

		//////////////////////////////////////////////////////
		// Generate the prototype in the Spec
		//////////////////////////////////////////////////////

		for ( auto mit = macros_used.begin(); mit != macros_used.end(); ++mit ) {
			const std::string macro_name = *mit;
			ads << "   -- " << macro_name << "\n";
		}

		ads << "   " << proto.str() << ";\n";
		if ( func.finline )
			ads << "   pragma Inline(" << func.ada_name << ");\n\n";

		//////////////////////////////////////////////////////
		// The body
		//////////////////////////////////////////////////////

		adb 	<< "   " << proto.str() << " is\n";

		// Use clauses
		for ( auto uit=func.use_clauses.begin(); uit != func.use_clauses.end(); ++uit ) {
			const std::string& use_clause = *uit;
			adb << "      use " << use_clause << ";\n";
		}

		// C Function Declaration
		if ( func.returns != "" )
			adb << "      function " << binding_name;
		else	adb << "      procedure " << binding_name;
		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto cit=func.cargs.begin(); cit != func.cargs.end(); ++cit ) {
				const s_config::s_section2::s_func::s_carg& arg = *cit;
				if ( !f )
					adb << "; ";
				else	f = false;
				adb << arg.name << " : " << arg.type;
			}
			adb << ")";
		}

		if ( func.returns != "" )
			adb << " return " << func.returns << ";\n";
		else	adb << ";\n";

		//  pragma Import(C,UX_close,"close");
		adb << "      pragma Import(C," << binding_name << ",\""
                    << func.bind_prefix << func.c_name << "\");\n";

		// Temporaries
		for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
			s_config::s_section2::s_func::s_aarg& arg = *ait;

			if ( arg.io == "in" && arg.temp != "" ) {
				std::stringstream s;
				std::string tempname;

				s << "T" << arg.argno;
				tempname = s.str();

				adb << "      " << tempname << " : " << arg.type
				    << " := " << arg.tempval << ";\n";
			}
		}

		// Temporary variables
		for ( auto t=func.temps.begin(); t != func.temps.end(); ++t ) {
			s_config::s_section2::s_func::s_temp& temp = *t;

			adb << "      " << temp.name << " : " << temp.type;
			if ( temp.init != "" )
				adb << " := " << temp.init;
			adb << ";\n";
		}

		// Return value:
		if ( func.rname != "" ) {
			adb << "      " << func.rname << " : " << func.returns << ";\n";
		}

		adb	<< "   begin\n";

		// Insert pre-checks
		if ( func.prechecks.size() > 0 ) {
			for ( auto pit=func.prechecks.cbegin(); pit != func.prechecks.cend(); ++pit ) {
				const std::string& cond = *pit;
				adb << "      if not ( " << cond << " ) then\n"
				    << "         " << func.on_error << ";\n"
				    << "         return;\n"
				    << "      end if;\n";
			}
		}

		// Insert case & when checks
		if ( func.cases.size() > 0 ) {
			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					std::vector<std::string> kvec;

					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() )
							kvec.push_back(the_case);
					}

					if ( kvec.size() > 0 ) {
						adb << "      case " << varname << " is\n";

						for ( auto vit=kvec.cbegin(); vit != kvec.cend(); ++vit ) {
							const std::string& the_case = *vit;
							adb << "         when " << the_case << "=>\n"
							    << "            null;\n";
						}

						adb << "         when others =>\n"
						    << "            Error := EINVAL;\n";

						if ( centry.on_error != "" )
							adb << "            " << centry.on_error << ";\n";

						adb << "            return;\n"
						    << "      end case;\n";
					}
				}
			}
		}

		if ( func.rname != "" ) {
			adb << "      " << func.rname << " := " << binding_name;
		} else	{
			adb << "      " << binding_name;
		}

		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto fit=func.cargs.begin(); fit != func.cargs.end(); ++fit ) {
				s_config::s_section2::s_func::s_carg& arg = *fit;
				if ( f )
					f = false;
				else	adb << ",";
				adb << arg.from;
			}
			adb << ")";
		}
		adb 	<< ";\n";

		// Output values:
		for ( auto oit=func.aargs.begin(); oit != func.aargs.end(); ++oit ) {
			s_config::s_section2::s_func::s_aarg& arg = *oit;

			if ( arg.from != "implied" ) {
				if ( arg.io == "out" || arg.io == "in out" ) {
					adb << "      " << arg.name << " := "
					    << arg.from << ";\n";
				}
			}
		}

		// Function return value
		if ( func.type == "function" ) {
			adb << "      return " << func.ada_rfrom << ";\n";
		}

		adb	<< "   end " << func.ada_name << ";\n\n";

		//////////////////////////////////////////////////////
		// Check if a macro must be emitted
		//////////////////////////////////////////////////////

		if ( func.macro != "" ) {
			if ( !cc.is_open() && !gcc_open(cc,config.section2.genset,".cc") )
				exit(3);

			for ( auto it=func.includes.begin(); it != func.includes.end(); ++it ) {
				const std::string& incl = *it;

				if ( inclset.find(incl) == inclset.end() ) {
					if ( incl[0] != '.' )
						cc << "#include <" << incl << ">\n";
					else	cc << "#include \"" << incl << "\"\n";
					inclset.insert(incl);
				}
			}

			cc << "\n"
			   << func.macro << "\n\n";
		}

	}

	ads.close();
	adb.close();
	cc.close();
}

// End sect2.cpp
<|endoftext|>


<commit_before>#pragma once

#include "standard_error_handler.hpp"
#include <libxml/xmlerror.h>
#include <libxml/xmlschemas.h>

class LibXml2ErrorHandler : public StandardErrorHandler {
public:
    static void errors( void *ctx, xmlErrorPtr p );
};

class XmlErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( ) {
        xmlSetStructuredErrorFunc( static_cast<void *>( this ),
                                   &LibXml2ErrorHandler::errors );
    }
};

class XmlSchemaParserErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( xmlSchemaParserCtxt *spcp ) {
        xmlSchemaSetParserStructuredErrors( spcp, &LibXml2ErrorHandler::errors,
                                            static_cast<void *>( this ) );
    }
};

class XmlSchemaValidatorErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( xmlSchemaValidCtxt *schemaValidator ) {
        xmlSchemaSetValidStructuredErrors( schemaValidator, &LibXml2ErrorHandler::errors,
                                           static_cast<void *>( this ) );
    }
};
<commit_msg>appended XPathErrorHandler<commit_after>#pragma once

#include "standard_error_handler.hpp"
#include <libxml/xmlerror.h>
#include <libxml/xmlschemas.h>
#include <libxml/xpath.h>

class LibXml2ErrorHandler : public StandardErrorHandler {
public:
    static void errors( void *ctx, xmlErrorPtr p );
};

class XmlErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( ) {
        xmlSetStructuredErrorFunc( static_cast<void *>( this ),
                                   &LibXml2ErrorHandler::errors );
    }
};

class XmlSchemaParserErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( xmlSchemaParserCtxt *spcp ) {
        xmlSchemaSetParserStructuredErrors( spcp, &LibXml2ErrorHandler::errors,
                                            static_cast<void *>( this ) );
    }
};

class XmlSchemaValidatorErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( xmlSchemaValidCtxt *schemaValidator ) {
        xmlSchemaSetValidStructuredErrors( schemaValidator, &LibXml2ErrorHandler::errors,
                                           static_cast<void *>( this ) );
    }
};

class XPathErrorHandler : public LibXml2ErrorHandler {
public:
    void registerHandler( xmlXPathContext *xpathctxt ) {
        xpathctxt->userData = this;
        xpathctxt->error = &LibXml2ErrorHandler::errors;
    }
};
<|endoftext|>


<commit_before>#include "model.h"
#include "model_io.h"
#include "modelwidget.h"
#include "figurepainter.h"
#include "recognition.h"
#include "layouting.h"
#include "model_ops.h"
#include <QPainter>
#include <QMouseEvent>
#include <QInputDialog>
#include <QMessageBox>
#include <QWheelEvent>
#include <QGesture>
#include <QDebug>
#include <QTimer>
#include <QMenu>

Ui::ModelWidget::ModelWidget(QWidget *parent) :
    QWidget(parent), mouseAction(MouseAction::None), _gridStep(0), _showTrack(true), _showRecognitionResult(true), _storeTracks(false) {
    setFocusPolicy(Qt::FocusPolicy::StrongFocus);
    grabGesture(Qt::PinchGesture);
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, &QWidget::customContextMenuRequested, this, &Ui::ModelWidget::customContextMenuRequested);
#if DISABLE_SHOW_RECOGNITION_RESULT == 1
    setShowRecognitionResult(false);
#endif
}

void drawTrack(QPainter &painter, Scaler &scaler, const Track &track) {
    QPen oldPen = painter.pen();
    std::vector<double> speeds = calculateRelativeSpeeds(track);
    for (size_t i = 0; i + 1 < track.size(); i++) {
        double k = speeds[i] * 510;
        QColor color;
        if (k <= 255) color = QColor(255, k, 0, 127);
        else color = QColor(255 - (k - 255), 255, 0, 127);
        QPen pen = oldPen;
        pen.setColor(color);
        painter.setPen(pen);
        painter.drawLine(scaler(track[i]), scaler(track[i + 1]));
    }
    std::vector<int> stops = getSpeedBreakpoints(track);
    for (int stop : stops) {
        QPen pen = oldPen;
        pen.setColor(QColor(0, 255, 255));
        painter.setPen(pen);
        painter.drawEllipse(scaler(track[stop]), scaler.scaleFactor * 10, scaler.scaleFactor * 10);
    }
    painter.setPen(oldPen);
}

int Ui::ModelWidget::gridStep() {
    return _gridStep;
}

void Ui::ModelWidget::setGridStep(int newGridStep) {
    if (newGridStep < 0) {
        throw std::runtime_error("Grid step should be >= 0");
    }
    _gridStep = newGridStep;
    update();
}

double Ui::ModelWidget::scaleFactor() {
    return scaler.scaleFactor;
}

void Ui::ModelWidget::setScaleFactor(double newScaleFactor) {
    if (!(newScaleFactor >= 0.01)) { // >= instead of < for NaNs
        throw std::runtime_error("Scale factor should be >= 0.01");
    }
    scaler.scaleFactor = newScaleFactor;
    emit scaleFactorChanged();
    update();
}

bool Ui::ModelWidget::showTrack() {
    return _showTrack;
}
void Ui::ModelWidget::setShowTrack(bool newShowTrack) {
    _showTrack = newShowTrack;
}

bool Ui::ModelWidget::showRecognitionResult() {
    return _showRecognitionResult;
}
void Ui::ModelWidget::setShowRecognitionResult(bool newShowRecognitionResult) {
    _showRecognitionResult = newShowRecognitionResult;
}

bool Ui::ModelWidget::storeTracks() {
    return _storeTracks;
}
void Ui::ModelWidget::setStoreTracks(bool newStoreTracks) {
    _storeTracks = newStoreTracks;
}

void Ui::ModelWidget::setModel(Model model) {
    commitedModel = std::move(model);
    previousModels.clear();
    redoModels.clear();
    emit canUndoChanged();
    emit canRedoChanged();
    extraTracks = std::vector<Track>();
}
Model &Ui::ModelWidget::getModel() {
    return commitedModel;
}

void Ui::ModelWidget::addModelExtraTrack(Track track) {
    extraTracks.push_back(std::move(track));
}

bool Ui::ModelWidget::canUndo() {
    return !previousModels.empty();
}

void Ui::ModelWidget::undo() {
    if (!canUndo()) {
        throw std::runtime_error("Cannot undo");
    }
    redoModels.push_front(std::move(commitedModel));
    commitedModel = std::move(previousModels.back());
    previousModels.pop_back();
    if (!canUndo()) {
        emit canUndoChanged();
    }
    emit canRedoChanged();
    update();
}

bool Ui::ModelWidget::canRedo() {
    return !redoModels.empty();
}

void Ui::ModelWidget::redo() {
    if (!canRedo()) {
        throw std::runtime_error("Cannot redo");
    }
    previousModels.push_back(std::move(commitedModel));
    commitedModel = std::move(redoModels.front());
    redoModels.pop_front();
    if (!canRedo()) {
        canRedoChanged();
    }
    canUndoChanged();
    update();
}

void Ui::ModelWidget::modifyModelAndCommit(std::function<void()> action) {
    previousModels.push_back(commitedModel);
    redoModels.clear();
    action();
    emit canUndoChanged();
    emit canRedoChanged();
    update();
}

double roundDownToMultiple(double x, double multiple) {
    return floor(x / multiple) * multiple;
}

void Ui::ModelWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.fillRect(QRect(QPoint(), size()), Qt::white);

    QFont font;
    font.setPointSizeF(10 * scaler.scaleFactor);
    painter.setFont(font);

    QPen pen(Qt::black);
    pen.setWidthF(scaler.scaleFactor);
    painter.setPen(pen);

    FigurePainter fpainter(painter, scaler);
    if (gridStep() > 0) {
        int step = gridStep();
        // Calculating visible area
        Point p1 = scaler(QPointF(0, 0));
        Point p2 = scaler(QPointF(width(), height()));
        if (p1.x > p2.x) { std::swap(p1.x, p2.x); }
        if (p1.y > p2.y) { std::swap(p1.y, p2.y); }

        // Finding starting point for the grid
        p1.x = roundDownToMultiple(p1.x, step);
        p1.y = roundDownToMultiple(p1.y, step);

        // Drawing
        QPen pen(QColor(192, 192, 192, 255));
        pen.setStyle(Qt::DashLine);
        painter.setPen(pen);
        for (int x = p1.x; x <= p2.x; x += step) {
            painter.drawLine(scaler(Point(x, p1.y)), scaler(Point(x, p2.y)));
        }
        for (int y = p1.y; y <= p2.y; y += step) {
            painter.drawLine(scaler(Point(p1.x, y)), scaler(Point(p2.x, y)));
        }
    }

    Model copiedModel;
    Model &modelToDraw = (lastTrack.empty() || !showRecognitionResult()) ? commitedModel : (copiedModel = commitedModel);
    PFigure modified = showRecognitionResult() ? recognize(lastTrack, modelToDraw) : nullptr;
    for (PFigure fig : modelToDraw) {
        if (fig == modified) {
            pen.setColor(Qt::magenta);
        } else if (fig == modelToDraw.selectedFigure) {
            pen.setColor(Qt::blue);
        } else {
            pen.setColor(Qt::black);
        }
        painter.setPen(pen);
        fig->visit(fpainter);
    }

    pen.setColor(QColor(255, 0, 0, 16));
    pen.setWidth(3 * scaler.scaleFactor);
    painter.setPen(pen);
    if (showTrack()) {
        drawTrack(painter, scaler, lastTrack);
        for (const Track &track : visibleTracks) {
            drawTrack(painter, scaler, track);
        }
    }
    for (const Track &track : extraTracks) {
        drawTrack(painter, scaler, track);
    }
}

void Ui::ModelWidget::customContextMenuRequested(const QPoint &pos) {
    PFigure figure = findClickedFigure(commitedModel, scaler(pos));
    if (figure) {
        std::shared_ptr<figures::Curve> curve = std::dynamic_pointer_cast<figures::Curve>(figure);
        if (curve) {
            QMenu contextMenu;
            QAction verticalSymmetry("Make vertically symmetric", this);
            connect(&verticalSymmetry, &QAction::triggered, [this, curve]() {
                modifyModelAndCommit([curve]() {
                    makeVerticallySymmetric(curve);
                });
            });
            contextMenu.addAction(&verticalSymmetry);

            QAction horizontalSymmetry("Make horizontally symmetric", this);
            connect(&horizontalSymmetry, &QAction::triggered, [this, curve]() {
                modifyModelAndCommit([curve]() {
                    makeHorizontallySymmetric(curve);
                });
            });
            contextMenu.addAction(&horizontalSymmetry);

            contextMenu.exec(mapToGlobal(pos));
        }

        auto bounded = std::dynamic_pointer_cast<figures::BoundedFigure>(figure);
        if (bounded) {
            QMenu contextMenu;
            QAction topBottomTree("Arrange children in a tree", this);
            connect(&topBottomTree, &QAction::triggered, [this, bounded]() {
                modifyModelAndCommit([this, bounded]() {
                    makeTopBottomTree(commitedModel, bounded);
                });
            });
            contextMenu.addAction(&topBottomTree);

            contextMenu.exec(mapToGlobal(pos));
        }
    }
}

void Ui::ModelWidget::mousePressEvent(QMouseEvent *event) {
    lastTrack = Track();

    if (event->modifiers().testFlag(Qt::ShiftModifier) || event->buttons().testFlag(Qt::MiddleButton)) {
        mouseAction = MouseAction::ViewpointMove;
        viewpointMoveStart = event->pos();
        viewpointMoveOldScaler = scaler;
        setCursor(Qt::ClosedHandCursor);
    } else if (event->buttons().testFlag(Qt::LeftButton)) {
        mouseAction = MouseAction::TrackActive;
        trackTimer.start();
        lastTrack.points.push_back(TrackPoint(scaler(event->pos()), trackTimer.elapsed()));
    }
    update();
}
void Ui::ModelWidget::mouseMoveEvent(QMouseEvent *event) {
    if (mouseAction == MouseAction::ViewpointMove) {
        scaler = viewpointMoveOldScaler;
        scaler.zeroPoint = scaler.zeroPoint + scaler(viewpointMoveStart) - scaler(event->pos());
        update();
    } else if (mouseAction == MouseAction::TrackActive) {
        lastTrack.points.push_back(TrackPoint(scaler(event->pos()), trackTimer.elapsed()));
        #if ENABLE_FAST_REDRAW == 1
        if (showTrack() && !showRecognitionResult()) {
            QPoint a = scaler(lastTrack[lastTrack.size() - 2]).toPoint();
            QPoint b = event->pos();
            QRect r = QRect(a, a).united(QRect(b, b));
            r.adjust(-2, -2, +2, +2);
            update(r);
        } else
        #endif
        if (showTrack() || showRecognitionResult()) {
            update();
        }
    } else {
        event->ignore();
    }
}
void Ui::ModelWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (mouseAction == MouseAction::None) {
        event->ignore();
        return;
    }
    if (mouseAction == MouseAction::ViewpointMove) {
        mouseAction = MouseAction::None;
        setCursor(Qt::ArrowCursor);
        scaler = viewpointMoveOldScaler;
        scaler.zeroPoint = scaler.zeroPoint + scaler(viewpointMoveStart) - scaler(event->pos());
        update();
        return;
    }
    assert(mouseAction == MouseAction::TrackActive);
    mouseAction = MouseAction::None;
    lastTrack.points.push_back(TrackPoint(scaler(event->pos()), trackTimer.elapsed()));
    if (storeTracks()) {
        QFile file(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".track");
        if (!file.open(QFile::WriteOnly | QFile::Text)) {
            QMessageBox::critical(this, "Error while saving track", "Unable to open file for writing");
        } else {
            std::stringstream stream;
            stream << lastTrack;
            std::string data = stream.str();
            if (file.write(data.data(), data.length()) != data.length()) {
                QMessageBox::critical(this, "Error while saving track", "Unable to write to opened file");
            }
        }
    }
    Model previousModel = commitedModel;
    PFigure modifiedFigure = recognize(lastTrack, commitedModel);
    if (_gridStep > 0 && modifiedFigure) {
        GridAlignLayouter layouter(_gridStep);
        layouter.updateLayout(commitedModel, modifiedFigure);
        commitedModel.recalculate();
    }

    visibleTracks.push_back(lastTrack);
    auto iterator = --visibleTracks.end();
    QTimer *timer = new QTimer(this);

    connect(timer, &QTimer::timeout, [this, iterator, timer]() {
        visibleTracks.erase(iterator);
        delete timer;
        update();
    });
    timer->setInterval(1500);
    timer->setSingleShot(true);
    timer->start();

    lastTrack = Track();
    if (modifiedFigure) {
        previousModels.push_back(previousModel);
        redoModels.clear();
        emit canUndoChanged();
        emit canRedoChanged();
    }
    update();
}
void Ui::ModelWidget::keyReleaseEvent(QKeyEvent *event) {
    event->ignore();
    if (event->key() == Qt::Key_Escape && mouseAction == MouseAction::TrackActive) {
        event->accept();
        lastTrack = Track();
        mouseAction = MouseAction::None;
        update();
    }
    if (event->key() == Qt::Key_Delete) {
        if (commitedModel.selectedFigure) {
            event->accept();
            modifyModelAndCommit([this]() {
                for (auto it = commitedModel.begin(); it != commitedModel.end(); it++) {
                    if (*it == commitedModel.selectedFigure) {
                        commitedModel.removeFigure(it);
                        break;
                    }
                }
            });
        }
    }
}

void Ui::ModelWidget::mouseDoubleClickEvent(QMouseEvent *event) {
    event->ignore();
    auto &figure = commitedModel.selectedFigure;
    if (!figure) { return; }

    Point eventPos = scaler(event->pos());
    bool hit = false;
    hit |= figure->isInsideOrOnBorder(eventPos);
    hit |= figure->getApproximateDistanceToBorder(eventPos) <= figureSelectGap();
    if (!hit) { return; }

    event->accept();
    bool ok;
    QString newLabel = QInputDialog::getMultiLineText(this, "Figure label", "Specify new figure label",
                                             QString::fromStdString(figure->label()),
                                                      &ok);
    if (ok) {
        modifyModelAndCommit([figure, &newLabel]() {
            figure->setLabel(newLabel.toStdString());
        });
    }
}

void Ui::ModelWidget::wheelEvent(QWheelEvent *event) {
    event->ignore();
    if (event->modifiers().testFlag(Qt::ControlModifier)) {
        event->accept();
        double scrolled = event->angleDelta().y() / 8;
        double factor = 1.0 + 0.2 * (scrolled / 15); // 20% per each 15 degrees (standard step)
        factor = std::max(factor, 0.1);
        scaler.scaleWithFixedPoint(scaler(event->pos()), factor);
        update();
    }
}

bool Ui::ModelWidget::event(QEvent *event) {
    if (event->type() == QEvent::Gesture) {
        QGestureEvent *gevent = static_cast<QGestureEvent*>(event);
        QPinchGesture *gesture = static_cast<QPinchGesture*>(gevent->gesture(Qt::PinchGesture));
        if (gesture) {
            gevent->accept(gesture);

            lastTrack = Track();
            mouseAction = MouseAction::None;

            scaler.zeroPoint = scaler.zeroPoint + scaler(gesture->lastCenterPoint()) - scaler(gesture->centerPoint());
            scaler.scaleWithFixedPoint(scaler(gesture->centerPoint()), gesture->scaleFactor());
            emit scaleFactorChanged();
            update();

            return true;
        }
    }
    return QWidget::event(event);
}
<commit_msg>modelwidget: 'emit' was added for some signal calls<commit_after>#include "model.h"
#include "model_io.h"
#include "modelwidget.h"
#include "figurepainter.h"
#include "recognition.h"
#include "layouting.h"
#include "model_ops.h"
#include <QPainter>
#include <QMouseEvent>
#include <QInputDialog>
#include <QMessageBox>
#include <QWheelEvent>
#include <QGesture>
#include <QDebug>
#include <QTimer>
#include <QMenu>

Ui::ModelWidget::ModelWidget(QWidget *parent) :
    QWidget(parent), mouseAction(MouseAction::None), _gridStep(0), _showTrack(true), _showRecognitionResult(true), _storeTracks(false) {
    setFocusPolicy(Qt::FocusPolicy::StrongFocus);
    grabGesture(Qt::PinchGesture);
    setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, &QWidget::customContextMenuRequested, this, &Ui::ModelWidget::customContextMenuRequested);
#if DISABLE_SHOW_RECOGNITION_RESULT == 1
    setShowRecognitionResult(false);
#endif
}

void drawTrack(QPainter &painter, Scaler &scaler, const Track &track) {
    QPen oldPen = painter.pen();
    std::vector<double> speeds = calculateRelativeSpeeds(track);
    for (size_t i = 0; i + 1 < track.size(); i++) {
        double k = speeds[i] * 510;
        QColor color;
        if (k <= 255) color = QColor(255, k, 0, 127);
        else color = QColor(255 - (k - 255), 255, 0, 127);
        QPen pen = oldPen;
        pen.setColor(color);
        painter.setPen(pen);
        painter.drawLine(scaler(track[i]), scaler(track[i + 1]));
    }
    std::vector<int> stops = getSpeedBreakpoints(track);
    for (int stop : stops) {
        QPen pen = oldPen;
        pen.setColor(QColor(0, 255, 255));
        painter.setPen(pen);
        painter.drawEllipse(scaler(track[stop]), scaler.scaleFactor * 10, scaler.scaleFactor * 10);
    }
    painter.setPen(oldPen);
}

int Ui::ModelWidget::gridStep() {
    return _gridStep;
}

void Ui::ModelWidget::setGridStep(int newGridStep) {
    if (newGridStep < 0) {
        throw std::runtime_error("Grid step should be >= 0");
    }
    _gridStep = newGridStep;
    update();
}

double Ui::ModelWidget::scaleFactor() {
    return scaler.scaleFactor;
}

void Ui::ModelWidget::setScaleFactor(double newScaleFactor) {
    if (!(newScaleFactor >= 0.01)) { // >= instead of < for NaNs
        throw std::runtime_error("Scale factor should be >= 0.01");
    }
    scaler.scaleFactor = newScaleFactor;
    emit scaleFactorChanged();
    update();
}

bool Ui::ModelWidget::showTrack() {
    return _showTrack;
}
void Ui::ModelWidget::setShowTrack(bool newShowTrack) {
    _showTrack = newShowTrack;
}

bool Ui::ModelWidget::showRecognitionResult() {
    return _showRecognitionResult;
}
void Ui::ModelWidget::setShowRecognitionResult(bool newShowRecognitionResult) {
    _showRecognitionResult = newShowRecognitionResult;
}

bool Ui::ModelWidget::storeTracks() {
    return _storeTracks;
}
void Ui::ModelWidget::setStoreTracks(bool newStoreTracks) {
    _storeTracks = newStoreTracks;
}

void Ui::ModelWidget::setModel(Model model) {
    commitedModel = std::move(model);
    previousModels.clear();
    redoModels.clear();
    emit canUndoChanged();
    emit canRedoChanged();
    extraTracks = std::vector<Track>();
}
Model &Ui::ModelWidget::getModel() {
    return commitedModel;
}

void Ui::ModelWidget::addModelExtraTrack(Track track) {
    extraTracks.push_back(std::move(track));
}

bool Ui::ModelWidget::canUndo() {
    return !previousModels.empty();
}

void Ui::ModelWidget::undo() {
    if (!canUndo()) {
        throw std::runtime_error("Cannot undo");
    }
    redoModels.push_front(std::move(commitedModel));
    commitedModel = std::move(previousModels.back());
    previousModels.pop_back();
    if (!canUndo()) {
        emit canUndoChanged();
    }
    emit canRedoChanged();
    update();
}

bool Ui::ModelWidget::canRedo() {
    return !redoModels.empty();
}

void Ui::ModelWidget::redo() {
    if (!canRedo()) {
        throw std::runtime_error("Cannot redo");
    }
    previousModels.push_back(std::move(commitedModel));
    commitedModel = std::move(redoModels.front());
    redoModels.pop_front();
    if (!canRedo()) {
        emit canRedoChanged();
    }
    emit canUndoChanged();
    update();
}

void Ui::ModelWidget::modifyModelAndCommit(std::function<void()> action) {
    previousModels.push_back(commitedModel);
    redoModels.clear();
    action();
    emit canUndoChanged();
    emit canRedoChanged();
    update();
}

double roundDownToMultiple(double x, double multiple) {
    return floor(x / multiple) * multiple;
}

void Ui::ModelWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.fillRect(QRect(QPoint(), size()), Qt::white);

    QFont font;
    font.setPointSizeF(10 * scaler.scaleFactor);
    painter.setFont(font);

    QPen pen(Qt::black);
    pen.setWidthF(scaler.scaleFactor);
    painter.setPen(pen);

    FigurePainter fpainter(painter, scaler);
    if (gridStep() > 0) {
        int step = gridStep();
        // Calculating visible area
        Point p1 = scaler(QPointF(0, 0));
        Point p2 = scaler(QPointF(width(), height()));
        if (p1.x > p2.x) { std::swap(p1.x, p2.x); }
        if (p1.y > p2.y) { std::swap(p1.y, p2.y); }

        // Finding starting point for the grid
        p1.x = roundDownToMultiple(p1.x, step);
        p1.y = roundDownToMultiple(p1.y, step);

        // Drawing
        QPen pen(QColor(192, 192, 192, 255));
        pen.setStyle(Qt::DashLine);
        painter.setPen(pen);
        for (int x = p1.x; x <= p2.x; x += step) {
            painter.drawLine(scaler(Point(x, p1.y)), scaler(Point(x, p2.y)));
        }
        for (int y = p1.y; y <= p2.y; y += step) {
            painter.drawLine(scaler(Point(p1.x, y)), scaler(Point(p2.x, y)));
        }
    }

    Model copiedModel;
    Model &modelToDraw = (lastTrack.empty() || !showRecognitionResult()) ? commitedModel : (copiedModel = commitedModel);
    PFigure modified = showRecognitionResult() ? recognize(lastTrack, modelToDraw) : nullptr;
    for (PFigure fig : modelToDraw) {
        if (fig == modified) {
            pen.setColor(Qt::magenta);
        } else if (fig == modelToDraw.selectedFigure) {
            pen.setColor(Qt::blue);
        } else {
            pen.setColor(Qt::black);
        }
        painter.setPen(pen);
        fig->visit(fpainter);
    }

    pen.setColor(QColor(255, 0, 0, 16));
    pen.setWidth(3 * scaler.scaleFactor);
    painter.setPen(pen);
    if (showTrack()) {
        drawTrack(painter, scaler, lastTrack);
        for (const Track &track : visibleTracks) {
            drawTrack(painter, scaler, track);
        }
    }
    for (const Track &track : extraTracks) {
        drawTrack(painter, scaler, track);
    }
}

void Ui::ModelWidget::customContextMenuRequested(const QPoint &pos) {
    PFigure figure = findClickedFigure(commitedModel, scaler(pos));
    if (figure) {
        std::shared_ptr<figures::Curve> curve = std::dynamic_pointer_cast<figures::Curve>(figure);
        if (curve) {
            QMenu contextMenu;
            QAction verticalSymmetry("Make vertically symmetric", this);
            connect(&verticalSymmetry, &QAction::triggered, [this, curve]() {
                modifyModelAndCommit([curve]() {
                    makeVerticallySymmetric(curve);
                });
            });
            contextMenu.addAction(&verticalSymmetry);

            QAction horizontalSymmetry("Make horizontally symmetric", this);
            connect(&horizontalSymmetry, &QAction::triggered, [this, curve]() {
                modifyModelAndCommit([curve]() {
                    makeHorizontallySymmetric(curve);
                });
            });
            contextMenu.addAction(&horizontalSymmetry);

            contextMenu.exec(mapToGlobal(pos));
        }

        auto bounded = std::dynamic_pointer_cast<figures::BoundedFigure>(figure);
        if (bounded) {
            QMenu contextMenu;
            QAction topBottomTree("Arrange children in a tree", this);
            connect(&topBottomTree, &QAction::triggered, [this, bounded]() {
                modifyModelAndCommit([this, bounded]() {
                    makeTopBottomTree(commitedModel, bounded);
                });
            });
            contextMenu.addAction(&topBottomTree);

            contextMenu.exec(mapToGlobal(pos));
        }
    }
}

void Ui::ModelWidget::mousePressEvent(QMouseEvent *event) {
    lastTrack = Track();

    if (event->modifiers().testFlag(Qt::ShiftModifier) || event->buttons().testFlag(Qt::MiddleButton)) {
        mouseAction = MouseAction::ViewpointMove;
        viewpointMoveStart = event->pos();
        viewpointMoveOldScaler = scaler;
        setCursor(Qt::ClosedHandCursor);
    } else if (event->buttons().testFlag(Qt::LeftButton)) {
        mouseAction = MouseAction::TrackActive;
        trackTimer.start();
        lastTrack.points.push_back(TrackPoint(scaler(event->pos()), trackTimer.elapsed()));
    }
    update();
}
void Ui::ModelWidget::mouseMoveEvent(QMouseEvent *event) {
    if (mouseAction == MouseAction::ViewpointMove) {
        scaler = viewpointMoveOldScaler;
        scaler.zeroPoint = scaler.zeroPoint + scaler(viewpointMoveStart) - scaler(event->pos());
        update();
    } else if (mouseAction == MouseAction::TrackActive) {
        lastTrack.points.push_back(TrackPoint(scaler(event->pos()), trackTimer.elapsed()));
        #if ENABLE_FAST_REDRAW == 1
        if (showTrack() && !showRecognitionResult()) {
            QPoint a = scaler(lastTrack[lastTrack.size() - 2]).toPoint();
            QPoint b = event->pos();
            QRect r = QRect(a, a).united(QRect(b, b));
            r.adjust(-2, -2, +2, +2);
            update(r);
        } else
        #endif
        if (showTrack() || showRecognitionResult()) {
            update();
        }
    } else {
        event->ignore();
    }
}
void Ui::ModelWidget::mouseReleaseEvent(QMouseEvent *event) {
    if (mouseAction == MouseAction::None) {
        event->ignore();
        return;
    }
    if (mouseAction == MouseAction::ViewpointMove) {
        mouseAction = MouseAction::None;
        setCursor(Qt::ArrowCursor);
        scaler = viewpointMoveOldScaler;
        scaler.zeroPoint = scaler.zeroPoint + scaler(viewpointMoveStart) - scaler(event->pos());
        update();
        return;
    }
    assert(mouseAction == MouseAction::TrackActive);
    mouseAction = MouseAction::None;
    lastTrack.points.push_back(TrackPoint(scaler(event->pos()), trackTimer.elapsed()));
    if (storeTracks()) {
        QFile file(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".track");
        if (!file.open(QFile::WriteOnly | QFile::Text)) {
            QMessageBox::critical(this, "Error while saving track", "Unable to open file for writing");
        } else {
            std::stringstream stream;
            stream << lastTrack;
            std::string data = stream.str();
            if (file.write(data.data(), data.length()) != data.length()) {
                QMessageBox::critical(this, "Error while saving track", "Unable to write to opened file");
            }
        }
    }
    Model previousModel = commitedModel;
    PFigure modifiedFigure = recognize(lastTrack, commitedModel);
    if (_gridStep > 0 && modifiedFigure) {
        GridAlignLayouter layouter(_gridStep);
        layouter.updateLayout(commitedModel, modifiedFigure);
        commitedModel.recalculate();
    }

    visibleTracks.push_back(lastTrack);
    auto iterator = --visibleTracks.end();
    QTimer *timer = new QTimer(this);

    connect(timer, &QTimer::timeout, [this, iterator, timer]() {
        visibleTracks.erase(iterator);
        delete timer;
        update();
    });
    timer->setInterval(1500);
    timer->setSingleShot(true);
    timer->start();

    lastTrack = Track();
    if (modifiedFigure) {
        previousModels.push_back(previousModel);
        redoModels.clear();
        emit canUndoChanged();
        emit canRedoChanged();
    }
    update();
}
void Ui::ModelWidget::keyReleaseEvent(QKeyEvent *event) {
    event->ignore();
    if (event->key() == Qt::Key_Escape && mouseAction == MouseAction::TrackActive) {
        event->accept();
        lastTrack = Track();
        mouseAction = MouseAction::None;
        update();
    }
    if (event->key() == Qt::Key_Delete) {
        if (commitedModel.selectedFigure) {
            event->accept();
            modifyModelAndCommit([this]() {
                for (auto it = commitedModel.begin(); it != commitedModel.end(); it++) {
                    if (*it == commitedModel.selectedFigure) {
                        commitedModel.removeFigure(it);
                        break;
                    }
                }
            });
        }
    }
}

void Ui::ModelWidget::mouseDoubleClickEvent(QMouseEvent *event) {
    event->ignore();
    auto &figure = commitedModel.selectedFigure;
    if (!figure) { return; }

    Point eventPos = scaler(event->pos());
    bool hit = false;
    hit |= figure->isInsideOrOnBorder(eventPos);
    hit |= figure->getApproximateDistanceToBorder(eventPos) <= figureSelectGap();
    if (!hit) { return; }

    event->accept();
    bool ok;
    QString newLabel = QInputDialog::getMultiLineText(this, "Figure label", "Specify new figure label",
                                             QString::fromStdString(figure->label()),
                                                      &ok);
    if (ok) {
        modifyModelAndCommit([figure, &newLabel]() {
            figure->setLabel(newLabel.toStdString());
        });
    }
}

void Ui::ModelWidget::wheelEvent(QWheelEvent *event) {
    event->ignore();
    if (event->modifiers().testFlag(Qt::ControlModifier)) {
        event->accept();
        double scrolled = event->angleDelta().y() / 8;
        double factor = 1.0 + 0.2 * (scrolled / 15); // 20% per each 15 degrees (standard step)
        factor = std::max(factor, 0.1);
        scaler.scaleWithFixedPoint(scaler(event->pos()), factor);
        update();
    }
}

bool Ui::ModelWidget::event(QEvent *event) {
    if (event->type() == QEvent::Gesture) {
        QGestureEvent *gevent = static_cast<QGestureEvent*>(event);
        QPinchGesture *gesture = static_cast<QPinchGesture*>(gevent->gesture(Qt::PinchGesture));
        if (gesture) {
            gevent->accept(gesture);

            lastTrack = Track();
            mouseAction = MouseAction::None;

            scaler.zeroPoint = scaler.zeroPoint + scaler(gesture->lastCenterPoint()) - scaler(gesture->centerPoint());
            scaler.scaleWithFixedPoint(scaler(gesture->centerPoint()), gesture->scaleFactor());
            emit scaleFactorChanged();
            update();

            return true;
        }
    }
    return QWidget::event(event);
}
<|endoftext|>