<commit_before>/* libs/graphics/images/SkImageDecoder.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include "SkImageDecoder.h"
#include "SkBitmap.h"
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkTemplates.h"

static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;

SkBitmap::Config SkImageDecoder::GetDeviceConfig()
{
    return gDeviceConfig;
}

void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
{
    gDeviceConfig = config;
}

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

SkImageDecoder::SkImageDecoder()
    : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
      fDitherImage(true) {
}

SkImageDecoder::~SkImageDecoder() {
    fPeeker->safeUnref();
    fChooser->safeUnref();
    fAllocator->safeUnref();
}

SkImageDecoder::Format SkImageDecoder::getFormat() const {
    return kUnknown_Format;
}

SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
    SkRefCnt_SafeAssign(fPeeker, peeker);
    return peeker;
}

SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
    SkRefCnt_SafeAssign(fChooser, chooser);
    return chooser;
}

SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
    SkRefCnt_SafeAssign(fAllocator, alloc);
    return alloc;
}

void SkImageDecoder::setSampleSize(int size) {
    if (size < 1) {
        size = 1;
    }
    fSampleSize = size;
}

bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
                                         int height) const {
    Chooser* chooser = fChooser;

    if (NULL == chooser) {    // no chooser, we just say YES to decoding :)
        return true;
    }
    chooser->begin(1);
    chooser->inspect(0, config, width, height);
    return chooser->choose() == 0;
}

bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
                                   SkColorTable* ctable) const {
    return bitmap->allocPixels(fAllocator, ctable);
}

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

/*  Technically, this should be 342, since that is the cutoff point between
    an index and 32bit bitmap (they take equal ram), but since 32bit is almost
    always faster, I bump up the value a bit.
*/
#define MIN_SIZE_FOR_INDEX  (512)

/*  Return the "optimal" config for this bitmap. In this case, we just look to
    promote index bitmaps to full-color, since those are a little faster to
    draw (fewer memory lookups).

    Seems like we could expose this to the caller through some exising or new
    proxy object, allowing them to decide (after sniffing some aspect of the
    original bitmap) what config they really want.
 */
static SkBitmap::Config optimal_config(const SkBitmap& bm,
                                       SkBitmap::Config pref) {
    if (bm.config() != pref) {
        if (bm.config() == SkBitmap::kIndex8_Config) {
            Sk64 size64 = bm.getSize64();
            if (size64.is32()) {
                int32_t size = size64.get32();
                if (size < MIN_SIZE_FOR_INDEX) {
                    return SkBitmap::kARGB_8888_Config;
                }
            }
        }
    }
    return bm.config();
}

bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
                            SkBitmap::Config pref, Mode mode) {
    // pass a temporary bitmap, so that if we return false, we are assured of
    // leaving the caller's bitmap untouched.
    SkBitmap    tmp;

    // we reset this to false before calling onDecode
    fShouldCancelDecode = false;

    if (!this->onDecode(stream, &tmp, pref, mode)) {
        return false;
    }

    SkBitmap::Config c = optimal_config(tmp, pref);
    if (c != tmp.config()) {
        if (mode == kDecodeBounds_Mode) {
            tmp.setConfig(c, tmp.width(), tmp.height());
        } else {
            SkBitmap tmp2;
            if (tmp.copyTo(&tmp2, c, this->getAllocator())) {
                tmp.swap(tmp2);
            }
        }
    }
    bm->swap(tmp);
    return true;
}

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

bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
                                SkBitmap::Config pref,  Mode mode) {
    SkASSERT(file);
    SkASSERT(bm);

    SkFILEStream    stream(file);
    if (stream.isValid()) {
        if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode)) {
            bm->pixelRef()->setURI(file);
        }
        return true;
    }
    return false;
}

bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
                                  SkBitmap::Config pref, Mode mode) {
    if (0 == size) {
        return false;
    }
    SkASSERT(buffer);

    SkMemoryStream  stream(buffer, size);
    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode);
}

bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
                                  SkBitmap::Config pref, Mode mode) {
    SkASSERT(stream);
    SkASSERT(bm);

    bool success = false;
    SkImageDecoder* codec = SkImageDecoder::Factory(stream);

    if (NULL != codec) {
        success = codec->decode(stream, bm, pref, mode);
        delete codec;
    }
    return success;
}

<commit_msg>Do not merge check if we can promote to the preferred config<commit_after>/* libs/graphics/images/SkImageDecoder.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include "SkImageDecoder.h"
#include "SkBitmap.h"
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkTemplates.h"

static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;

SkBitmap::Config SkImageDecoder::GetDeviceConfig()
{
    return gDeviceConfig;
}

void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
{
    gDeviceConfig = config;
}

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

SkImageDecoder::SkImageDecoder()
    : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
      fDitherImage(true) {
}

SkImageDecoder::~SkImageDecoder() {
    fPeeker->safeUnref();
    fChooser->safeUnref();
    fAllocator->safeUnref();
}

SkImageDecoder::Format SkImageDecoder::getFormat() const {
    return kUnknown_Format;
}

SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
    SkRefCnt_SafeAssign(fPeeker, peeker);
    return peeker;
}

SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
    SkRefCnt_SafeAssign(fChooser, chooser);
    return chooser;
}

SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
    SkRefCnt_SafeAssign(fAllocator, alloc);
    return alloc;
}

void SkImageDecoder::setSampleSize(int size) {
    if (size < 1) {
        size = 1;
    }
    fSampleSize = size;
}

bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
                                         int height) const {
    Chooser* chooser = fChooser;

    if (NULL == chooser) {    // no chooser, we just say YES to decoding :)
        return true;
    }
    chooser->begin(1);
    chooser->inspect(0, config, width, height);
    return chooser->choose() == 0;
}

bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
                                   SkColorTable* ctable) const {
    return bitmap->allocPixels(fAllocator, ctable);
}

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

static bool canCopyTo(SkBitmap::Config src, SkBitmap::Config dst) {
    if (src == SkBitmap::kNo_Config) {
        return false;
    }

    bool sameConfigs = (src == dst);
    switch (dst) {
        case SkBitmap::kA8_Config:
        case SkBitmap::kARGB_4444_Config:
        case SkBitmap::kRGB_565_Config:
        case SkBitmap::kARGB_8888_Config:
            break;
        case SkBitmap::kA1_Config:
        case SkBitmap::kIndex8_Config:
            if (!sameConfigs) {
                return false;
            }
            break;
        default:
            return false;
    }

    // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config
    if (src == SkBitmap::kA1_Config && !sameConfigs) {
        return false;
    }

    return true;
}

bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
                            SkBitmap::Config pref, Mode mode) {
    // pass a temporary bitmap, so that if we return false, we are assured of
    // leaving the caller's bitmap untouched.
    SkBitmap    tmp;

    // we reset this to false before calling onDecode
    fShouldCancelDecode = false;

    if (!this->onDecode(stream, &tmp, pref, mode)) {
        return false;
    }

    if (tmp.config() != pref && canCopyTo(tmp.config(), pref)) {
        if (mode == kDecodeBounds_Mode) {
            tmp.setConfig(pref, tmp.width(), tmp.height());
        } else if (mode == kDecodePixels_Mode) {
            SkBitmap tmp2;
            if (tmp.copyTo(&tmp2, pref, this->getAllocator())) {
                tmp.swap(tmp2);
            }
        }
    }
    bm->swap(tmp);
    return true;
}

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

bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
                                SkBitmap::Config pref,  Mode mode) {
    SkASSERT(file);
    SkASSERT(bm);

    SkFILEStream    stream(file);
    if (stream.isValid()) {
        if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode)) {
            bm->pixelRef()->setURI(file);
        }
        return true;
    }
    return false;
}

bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
                                  SkBitmap::Config pref, Mode mode) {
    if (0 == size) {
        return false;
    }
    SkASSERT(buffer);

    SkMemoryStream  stream(buffer, size);
    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode);
}

bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
                                  SkBitmap::Config pref, Mode mode) {
    SkASSERT(stream);
    SkASSERT(bm);

    bool success = false;
    SkImageDecoder* codec = SkImageDecoder::Factory(stream);

    if (NULL != codec) {
        success = codec->decode(stream, bm, pref, mode);
        delete codec;
    }
    return success;
}

<|endoftext|>


<commit_before>//Copyright (c) 2021 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "LightningLayer.h"

#include "LightningTree.h"

#include "../sliceDataStorage.h"
#include "../utils/linearAlg2D.h"
#include "../utils/SVG.h"
#include "../utils/SparsePointGridInclusive.h"

using namespace cura;

coord_t LightningLayer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_loc)
{
    return vSize(boundary_loc - unsupported_loc);
}

PolygonLightningDistanceField::PolygonLightningDistanceField
(
    const coord_t& radius,
 const Polygons& current_outline,
 const Polygons& current_overhang,
 const std::vector<std::shared_ptr<LightningTreeNode>>& initial_trees
)
{
    supporting_radius = radius;
    Polygons supporting_polylines = current_outline;
    for (PolygonRef poly : supporting_polylines)
    {
        if (!poly.empty())
        {
            poly.add(poly[0]); // add start so that the polyline is closed
        }
    }

    const LightningTreeNode::branch_visitor_func_t add_offset_branch_func =
    [&](const Point& parent, const Point& child)
    {
        supporting_polylines.addLine(parent, child);
    };
    for (const auto& tree : initial_trees)
    {
        tree->visitBranches(add_offset_branch_func);
    }
    supported = supporting_polylines.offsetPolyLine(supporting_radius);
    unsupported = current_overhang.difference(supported);
}

bool PolygonLightningDistanceField::tryGetNextPoint(Point* p, coord_t supporting_radius) const
{
    if (unsupported.area() < 25)
    {
        return false;
    }
    coord_t total_length = unsupported[0].polygonLength();
    coord_t dist_to_point_on_boundary = std::rand() % total_length;
    ClosestPolygonPoint cpp = PolygonUtils::walk(ClosestPolygonPoint(unsupported[0][0], 0, unsupported[0]), dist_to_point_on_boundary);
    *p = PolygonUtils::moveInside(cpp, supporting_radius);
    if (!unsupported.inside(*p))
    {
        PolygonUtils::moveInside(unsupported, *p, supporting_radius / 2);
    }
    // NOTE: it's okay for the rare case where a point ends up outside; it's just an inefficient tree branch.
    return true;
}

void PolygonLightningDistanceField::update(const Point& to_node, const Point& added_leaf)
{
    Polygons line;
    line.addLine(to_node, added_leaf);
    Polygons offsetted = line.offsetPolyLine(supporting_radius, ClipperLib::jtRound);
    supported = supported.unionPolygons(offsetted);
    unsupported = unsupported.difference(supported);
}

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

LightningDistanceField::LightningDistanceField
(
    const coord_t& radius,
 const Polygons& current_outline,
 const Polygons& current_overhang,
 const std::vector<std::shared_ptr<LightningTreeNode>>& initial_trees
)
: grid(cell_size)
, supporting_radius(radius)
, current_outline(current_outline)
, current_overhang(current_overhang)
{
    std::vector<Point> regular_dots = PolygonUtils::spreadDotsArea(current_overhang, cell_size);
    for (Point p : regular_dots)
    {
        const ClosestPolygonPoint cpp = PolygonUtils::findClosest(p, current_outline);
        const coord_t dist_to_boundary = vSize(p - cpp.p());
        unsupported_points.emplace_back(p, dist_to_boundary);
    }
    unsupported_points.sort([](const UnsupCell& a, const UnsupCell& b) { return a.dist_to_boundary < b.dist_to_boundary; });
    for (auto it = unsupported_points.begin(); it != unsupported_points.end(); ++it)
    {
        UnsupCell& cell = *it;
        unsupported_points_grid.emplace(grid.toGridPoint(cell.loc), it);
    }
}

bool LightningDistanceField::tryGetNextPoint(Point* p, coord_t supporting_radius) const
{
    if (unsupported_points.empty()) return false;
    *p = unsupported_points.front().loc;
    return true;
}

void LightningDistanceField::update(const Point& to_node, const Point& added_leaf)
{
    grid.processNearby(added_leaf, supporting_radius,
                       [added_leaf, this](const SquareGrid::GridPoint& grid_loc)
                       {
                           auto it = unsupported_points_grid.find(grid_loc);
                           if (it != unsupported_points_grid.end())
                           {
                               std::list<UnsupCell>::iterator& list_it = it->second;
                               UnsupCell& cell = *list_it;
                               if (shorterThen(cell.loc - added_leaf, supporting_radius))
                               {
                                   unsupported_points.erase(list_it);
                                   unsupported_points_grid.erase(it);
                               }
                           }
                           return true;
                       });
}

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

Point GroundingLocation::p() const
{
    if (tree_node != nullptr)
    {
        return tree_node->getLocation();
    }
    else
    {
        assert(boundary_location);
        return boundary_location->p();
    }
}

LightningTreeNode::node_visitor_func_t getAddToLocatorFunc(SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>>& tree_node_locator)
{
    return
        [&tree_node_locator](std::shared_ptr<LightningTreeNode> node)
    {
        tree_node_locator.insert(node->getLocation(), node);
    };
}

void LightningLayer::fillLocator(SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>>& tree_node_locator)
{
    const LightningTreeNode::node_visitor_func_t add_node_to_locator_func = getAddToLocatorFunc(tree_node_locator);
    for (auto& tree : tree_roots)
    {
        tree->visitNodes(add_node_to_locator_func);
    }
}

void LightningLayer::generateNewTrees(const Polygons& current_overhang, Polygons& current_outlines, coord_t supporting_radius)
{
    LightningDistanceField distance_field(supporting_radius, current_outlines, current_overhang, tree_roots);

    constexpr coord_t locator_cell_size = 2000;
    SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>> tree_node_locator(locator_cell_size);
    const auto add_to_locator_func = getAddToLocatorFunc(tree_node_locator);
    fillLocator(tree_node_locator);

    constexpr size_t debug_max_iterations = 9999; // TODO: remove
    size_t i_debug = 0;

    // Until no more points need to be added to support all:
    // Determine next point from tree/outline areas via distance-field
    Point unsupported_location;
    while (distance_field.tryGetNextPoint(&unsupported_location, supporting_radius) && i_debug < debug_max_iterations)
    {
        ++i_debug;

        GroundingLocation grounding_loc = getBestGroundingLocation(unsupported_location, current_outlines, supporting_radius, tree_node_locator);

        // TODO: update unsupported_location to lie closer to grounding_loc

        attach(unsupported_location, grounding_loc)->visitNodes(add_to_locator_func);

        // update distance field
        distance_field.update(grounding_loc.p(), unsupported_location);
    }
}

GroundingLocation LightningLayer::getBestGroundingLocation(const Point& unsupported_location, const Polygons& current_outlines, const coord_t supporting_radius, const SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>>& tree_node_locator, const std::shared_ptr<LightningTreeNode>& exclude_tree)
{
    ClosestPolygonPoint cpp = PolygonUtils::findClosest(unsupported_location, current_outlines);
    Point node_location = cpp.p();

    std::shared_ptr<LightningTreeNode> sub_tree(nullptr);
    coord_t current_dist = getWeightedDistance(node_location, unsupported_location);
    auto candidate_trees = tree_node_locator.getNearbyVals(unsupported_location, std::min(current_dist, supporting_radius));
    for (auto& candidate_wptr : candidate_trees)
    {
        auto candidate_sub_tree = candidate_wptr.lock();
        if (candidate_sub_tree && candidate_sub_tree != exclude_tree && !(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)))
        {
            const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius);
            if (candidate_dist < current_dist)
            {
                current_dist = candidate_dist;
                sub_tree = candidate_sub_tree;
            }
        }
    }

    if (!sub_tree)
    {
        return GroundingLocation{ nullptr, cpp };
    }
    else
    {
        return GroundingLocation{ sub_tree, std::optional<ClosestPolygonPoint>() };
    }
}

std::shared_ptr<LightningTreeNode> LightningLayer::attach(const Point& unsupported_location, const GroundingLocation& grounding_loc)
{
    // Update trees & distance fields.
    if (grounding_loc.boundary_location)
    {
        tree_roots.push_back(LightningTreeNode::create(grounding_loc.p(), unsupported_location));
        return tree_roots.back();
    }
    else
    {
        return grounding_loc.tree_node->addChild(unsupported_location);
    }
}

void LightningLayer::reconnectRoots(std::vector<std::shared_ptr<LightningTreeNode>>& to_be_reconnected_tree_roots, const Polygons& current_outlines, const coord_t supporting_radius)
{
    constexpr coord_t locator_cell_size = 2000;
    SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>> tree_node_locator(locator_cell_size);
    fillLocator(tree_node_locator);

    const LightningTreeNode::node_visitor_func_t add_node_to_locator_func = getAddToLocatorFunc(tree_node_locator);
    for (auto root_ptr : to_be_reconnected_tree_roots)
    {
        auto old_root_it = std::find(tree_roots.begin(), tree_roots.end(), root_ptr);
        GroundingLocation ground = getBestGroundingLocation(root_ptr->getLocation(), current_outlines, supporting_radius, tree_node_locator, root_ptr);
        if (ground.boundary_location)
        {
            if (ground.boundary_location.value().p() == root_ptr->getLocation())
            {
                continue; // Already on the boundary.
            }

            auto new_root = LightningTreeNode::create(ground.p());
            new_root->addChild(root_ptr);
            tree_node_locator.insert(new_root->getLocation(), new_root);

            *old_root_it = std::move(new_root); // replace old root with new root
        }
        else
        {
            assert(ground.tree_node);
            assert(ground.tree_node != root_ptr);
            assert(!root_ptr->hasOffspring(ground.tree_node));
            assert(!ground.tree_node->hasOffspring(root_ptr));

            ground.tree_node->addChild(root_ptr);

            // remove old root
            *old_root_it = std::move(tree_roots.back());
            tree_roots.pop_back();
        }
    }
}

// Returns 'added someting'.
Polygons LightningLayer::convertToLines() const
{
    Polygons result_lines;
    if (tree_roots.empty())
    {
        return result_lines;
    }

    // TODO: The convert trees to lines 'algorithm' is way too simple right now (unless they're already going to be connected later).
    LightningTreeNode::branch_visitor_func_t convert_trees_to_lines =
        [&result_lines](const Point& node, const Point& leaf)
    {
        result_lines.addLine(node, leaf);
    };
    for (const auto& tree : tree_roots)
    {
        tree->visitBranches(convert_trees_to_lines);
    }
    return result_lines;
}
<commit_msg>No need for closure outside of fillLocator.<commit_after>//Copyright (c) 2021 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "LightningLayer.h"

#include "LightningTree.h"

#include "../sliceDataStorage.h"
#include "../utils/linearAlg2D.h"
#include "../utils/SVG.h"
#include "../utils/SparsePointGridInclusive.h"

using namespace cura;

coord_t LightningLayer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_loc)
{
    return vSize(boundary_loc - unsupported_loc);
}

PolygonLightningDistanceField::PolygonLightningDistanceField
(
    const coord_t& radius,
 const Polygons& current_outline,
 const Polygons& current_overhang,
 const std::vector<std::shared_ptr<LightningTreeNode>>& initial_trees
)
{
    supporting_radius = radius;
    Polygons supporting_polylines = current_outline;
    for (PolygonRef poly : supporting_polylines)
    {
        if (!poly.empty())
        {
            poly.add(poly[0]); // add start so that the polyline is closed
        }
    }

    const LightningTreeNode::branch_visitor_func_t add_offset_branch_func =
    [&](const Point& parent, const Point& child)
    {
        supporting_polylines.addLine(parent, child);
    };
    for (const auto& tree : initial_trees)
    {
        tree->visitBranches(add_offset_branch_func);
    }
    supported = supporting_polylines.offsetPolyLine(supporting_radius);
    unsupported = current_overhang.difference(supported);
}

bool PolygonLightningDistanceField::tryGetNextPoint(Point* p, coord_t supporting_radius) const
{
    if (unsupported.area() < 25)
    {
        return false;
    }
    coord_t total_length = unsupported[0].polygonLength();
    coord_t dist_to_point_on_boundary = std::rand() % total_length;
    ClosestPolygonPoint cpp = PolygonUtils::walk(ClosestPolygonPoint(unsupported[0][0], 0, unsupported[0]), dist_to_point_on_boundary);
    *p = PolygonUtils::moveInside(cpp, supporting_radius);
    if (!unsupported.inside(*p))
    {
        PolygonUtils::moveInside(unsupported, *p, supporting_radius / 2);
    }
    // NOTE: it's okay for the rare case where a point ends up outside; it's just an inefficient tree branch.
    return true;
}

void PolygonLightningDistanceField::update(const Point& to_node, const Point& added_leaf)
{
    Polygons line;
    line.addLine(to_node, added_leaf);
    Polygons offsetted = line.offsetPolyLine(supporting_radius, ClipperLib::jtRound);
    supported = supported.unionPolygons(offsetted);
    unsupported = unsupported.difference(supported);
}

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

LightningDistanceField::LightningDistanceField
(
    const coord_t& radius,
 const Polygons& current_outline,
 const Polygons& current_overhang,
 const std::vector<std::shared_ptr<LightningTreeNode>>& initial_trees
)
: grid(cell_size)
, supporting_radius(radius)
, current_outline(current_outline)
, current_overhang(current_overhang)
{
    std::vector<Point> regular_dots = PolygonUtils::spreadDotsArea(current_overhang, cell_size);
    for (Point p : regular_dots)
    {
        const ClosestPolygonPoint cpp = PolygonUtils::findClosest(p, current_outline);
        const coord_t dist_to_boundary = vSize(p - cpp.p());
        unsupported_points.emplace_back(p, dist_to_boundary);
    }
    unsupported_points.sort([](const UnsupCell& a, const UnsupCell& b) { return a.dist_to_boundary < b.dist_to_boundary; });
    for (auto it = unsupported_points.begin(); it != unsupported_points.end(); ++it)
    {
        UnsupCell& cell = *it;
        unsupported_points_grid.emplace(grid.toGridPoint(cell.loc), it);
    }
}

bool LightningDistanceField::tryGetNextPoint(Point* p, coord_t supporting_radius) const
{
    if (unsupported_points.empty()) return false;
    *p = unsupported_points.front().loc;
    return true;
}

void LightningDistanceField::update(const Point& to_node, const Point& added_leaf)
{
    grid.processNearby(added_leaf, supporting_radius,
                       [added_leaf, this](const SquareGrid::GridPoint& grid_loc)
                       {
                           auto it = unsupported_points_grid.find(grid_loc);
                           if (it != unsupported_points_grid.end())
                           {
                               std::list<UnsupCell>::iterator& list_it = it->second;
                               UnsupCell& cell = *list_it;
                               if (shorterThen(cell.loc - added_leaf, supporting_radius))
                               {
                                   unsupported_points.erase(list_it);
                                   unsupported_points_grid.erase(it);
                               }
                           }
                           return true;
                       });
}

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

Point GroundingLocation::p() const
{
    if (tree_node != nullptr)
    {
        return tree_node->getLocation();
    }
    else
    {
        assert(boundary_location);
        return boundary_location->p();
    }
}

void LightningLayer::fillLocator(SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>>& tree_node_locator)
{
    const LightningTreeNode::node_visitor_func_t add_node_to_locator_func =
        [&tree_node_locator](std::shared_ptr<LightningTreeNode> node)
        {
            tree_node_locator.insert(node->getLocation(), node);
        };
    for (auto& tree : tree_roots)
    {
        tree->visitNodes(add_node_to_locator_func);
    }
}

void LightningLayer::generateNewTrees(const Polygons& current_overhang, Polygons& current_outlines, coord_t supporting_radius)
{
    LightningDistanceField distance_field(supporting_radius, current_outlines, current_overhang, tree_roots);

    constexpr coord_t locator_cell_size = 2000;
    SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>> tree_node_locator(locator_cell_size);
    fillLocator(tree_node_locator);

    constexpr size_t debug_max_iterations = 9999; // TODO: remove
    size_t i_debug = 0;

    // Until no more points need to be added to support all:
    // Determine next point from tree/outline areas via distance-field
    Point unsupported_location;
    while (distance_field.tryGetNextPoint(&unsupported_location, supporting_radius) && i_debug < debug_max_iterations)
    {
        ++i_debug;

        GroundingLocation grounding_loc = getBestGroundingLocation(unsupported_location, current_outlines, supporting_radius, tree_node_locator);

        // TODO: update unsupported_location to lie closer to grounding_loc

        auto tree_node = attach(unsupported_location, grounding_loc);
        tree_node_locator.insert(tree_node->getLocation(), tree_node);

        // update distance field
        distance_field.update(grounding_loc.p(), unsupported_location);
    }
}

GroundingLocation LightningLayer::getBestGroundingLocation(const Point& unsupported_location, const Polygons& current_outlines, const coord_t supporting_radius, const SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>>& tree_node_locator, const std::shared_ptr<LightningTreeNode>& exclude_tree)
{
    ClosestPolygonPoint cpp = PolygonUtils::findClosest(unsupported_location, current_outlines);
    Point node_location = cpp.p();

    std::shared_ptr<LightningTreeNode> sub_tree(nullptr);
    coord_t current_dist = getWeightedDistance(node_location, unsupported_location);
    auto candidate_trees = tree_node_locator.getNearbyVals(unsupported_location, std::min(current_dist, supporting_radius));
    for (auto& candidate_wptr : candidate_trees)
    {
        auto candidate_sub_tree = candidate_wptr.lock();
        if (candidate_sub_tree && candidate_sub_tree != exclude_tree && !(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)))
        {
            const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius);
            if (candidate_dist < current_dist)
            {
                current_dist = candidate_dist;
                sub_tree = candidate_sub_tree;
            }
        }
    }

    if (!sub_tree)
    {
        return GroundingLocation{ nullptr, cpp };
    }
    else
    {
        return GroundingLocation{ sub_tree, std::optional<ClosestPolygonPoint>() };
    }
}

std::shared_ptr<LightningTreeNode> LightningLayer::attach(const Point& unsupported_location, const GroundingLocation& grounding_loc)
{
    // Update trees & distance fields.
    if (grounding_loc.boundary_location)
    {
        tree_roots.push_back(LightningTreeNode::create(grounding_loc.p(), unsupported_location));
        return tree_roots.back();
    }
    else
    {
        return grounding_loc.tree_node->addChild(unsupported_location);
    }
}

void LightningLayer::reconnectRoots(std::vector<std::shared_ptr<LightningTreeNode>>& to_be_reconnected_tree_roots, const Polygons& current_outlines, const coord_t supporting_radius)
{
    constexpr coord_t locator_cell_size = 2000;
    SparsePointGridInclusive<std::weak_ptr<LightningTreeNode>> tree_node_locator(locator_cell_size);
    fillLocator(tree_node_locator);

    for (auto root_ptr : to_be_reconnected_tree_roots)
    {
        auto old_root_it = std::find(tree_roots.begin(), tree_roots.end(), root_ptr);
        GroundingLocation ground = getBestGroundingLocation(root_ptr->getLocation(), current_outlines, supporting_radius, tree_node_locator, root_ptr);
        if (ground.boundary_location)
        {
            if (ground.boundary_location.value().p() == root_ptr->getLocation())
            {
                continue; // Already on the boundary.
            }

            auto new_root = LightningTreeNode::create(ground.p());
            new_root->addChild(root_ptr);
            tree_node_locator.insert(new_root->getLocation(), new_root);

            *old_root_it = std::move(new_root); // replace old root with new root
        }
        else
        {
            assert(ground.tree_node);
            assert(ground.tree_node != root_ptr);
            assert(!root_ptr->hasOffspring(ground.tree_node));
            assert(!ground.tree_node->hasOffspring(root_ptr));

            ground.tree_node->addChild(root_ptr);

            // remove old root
            *old_root_it = std::move(tree_roots.back());
            tree_roots.pop_back();
        }
    }
}

// Returns 'added someting'.
Polygons LightningLayer::convertToLines() const
{
    Polygons result_lines;
    if (tree_roots.empty())
    {
        return result_lines;
    }

    // TODO: The convert trees to lines 'algorithm' is way too simple right now (unless they're already going to be connected later).
    LightningTreeNode::branch_visitor_func_t convert_trees_to_lines =
        [&result_lines](const Point& node, const Point& leaf)
    {
        result_lines.addLine(node, leaf);
    };
    for (const auto& tree : tree_roots)
    {
        tree->visitBranches(convert_trees_to_lines);
    }
    return result_lines;
}
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    LiveSupport is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    LiveSupport 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: fgerlits $
    Version  : $Revision: 1.21 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/products/gLiveSupport/src/MasterPanelWindow.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#include <iostream>
#include <unicode/msgfmt.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>

#include "LiveSupport/Core/TimeConversion.h"
#include "MasterPanelWindow.h"

using namespace LiveSupport;
using namespace LiveSupport::GLiveSupport;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: MasterPanelWindow (Ptr<GLiveSupport>::Ref    gLiveSupport,
                                        Ptr<ResourceBundle>::Ref  bundle)
                                                                    throw ()
                        : LocalizedObject(bundle)
{
    this->gLiveSupport = gLiveSupport;

    Ptr<WidgetFactory>::Ref widgetFactory = WidgetFactory::getInstance();

    // TODO: remove hard-coded station logo path reference
    radioLogoWidget = Gtk::manage(new Gtk::Image("var/stationLogo.png"));
    radioLogoWidget->set_size_request(158, 104);

    // set up the layout, which is a button box
    layout = Gtk::manage(new Gtk::Table());

    // set up the time label
    timeWidget = Gtk::manage(new Gtk::Label("time"));
    timeBin = Gtk::manage(widgetFactory->createBlueBin());
    timeBin->add(*timeWidget);
    timeBin->set_size_request(153, 104);

    // set up the now playing widget
    nowPlayingWidget = Gtk::manage(new Gtk::Label("now playing"));
    nowPlayingBin = Gtk::manage(widgetFactory->createDarkBlueBin());
    nowPlayingBin->add(*nowPlayingWidget);
    timeBin->set_size_request(-1, 104);

    // set up the VU meter widget
    vuMeterWidget = Gtk::manage(new Gtk::Label("VU meter"));
    vuMeterBin = Gtk::manage(widgetFactory->createBlueBin());
    vuMeterBin->add(*vuMeterWidget);
    vuMeterBin->set_size_request(400, 40);
    // set up the next playing widget
    nextPlayingWidget = Gtk::manage(new Gtk::Label("next playing"));
    nextPlayingBin = Gtk::manage(widgetFactory->createBlueBin());
    nextPlayingBin->add(*nextPlayingWidget);
    nextPlayingBin->set_size_request(400, 59);

    // create the bottom bar
    bottomBar = Gtk::manage(new Gtk::Table());
    bottomBar->set_size_request(-1, 30);
    buttonBar = Gtk::manage(new Gtk::Table());
    buttonBarAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT,
                                                        Gtk::ALIGN_CENTER,
                                                        0, 0));
    buttonBarAlignment->add(*buttonBar);
    userInfoWidget = Gtk::manage(new MasterPanelUserInfoWidget(gLiveSupport,
                                                               bundle));
    userInfoAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
                                                       Gtk::ALIGN_CENTER,
                                                       0, 0));
    userInfoAlignment->add(*userInfoWidget);
    bottomBar->attach(*buttonBarAlignment, 0, 1, 0, 1,
                      Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    bottomBar->attach(*userInfoAlignment,  1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    // set up the main window, and show everything
    // all the localized widgets were set up in changeLanguage()
    set_border_width(10);
    layout->attach(*timeBin,         0, 1, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nowPlayingBin,   1, 2, 0, 2,
                   Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                   5, 0);
    layout->attach(*vuMeterBin,      2, 3, 0, 1,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nextPlayingBin,  2, 3, 1, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*radioLogoWidget, 3, 4, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    5, 0);
    layout->attach(*bottomBar,       0, 4, 2, 3,
                    Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    add(*layout);

    // set the background to white
    bgColor = Colors::getColor(Colors::White);
    modify_bg(Gtk::STATE_NORMAL, bgColor);

    // set the size and location of the window, according to the screen size
    Glib::RefPtr<Gdk::Screen>   screen = get_screen();
    int                         width;
    int                         height;
    get_size(width, height);
    width = screen->get_width();
    set_default_size(width, height);
    move(0, 0);
    set_decorated(false);

    // set the localized resources
    changeLanguage(bundle);

    // show what's there to see
    showAnonymousUI();

    // set the timer, that will update timeWidget
    setTimer();
}

/*------------------------------------------------------------------------------
 *  Destructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: ~MasterPanelWindow (void)                        throw ()
{
    resetTimer();
    gLiveSupport->stopAudio();
}

/*------------------------------------------------------------------------------
 *  Change the language of the panel
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: changeLanguage(Ptr<ResourceBundle>::Ref    bundle)
                                                                    throw ()
{
    setBundle(bundle);

    try {
        set_title(*getResourceUstring("windowTitle"));

        Ptr<WidgetFactory>::Ref wf = WidgetFactory::getInstance();

        uploadFileButton = wf->createButton(
                                *getResourceUstring("uploadFileButtonLabel"));
        scratchpadButton = wf->createButton(
                                *getResourceUstring("scratchpadButtonLabel"));
        simplePlaylistMgmtButton = wf->createButton(
                        *getResourceUstring("simplePlaylistMgmtButtonLabel"));
        schedulerButton = wf->createButton(
                                *getResourceUstring("schedulerButtonLabel"));
        searchButton = wf->createButton(
                                *getResourceUstring("searchButtonLabel"));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    userInfoWidget->changeLanguage(bundle);

    // re-attach the localized widgets to the layout
    buttonBar->attach(*uploadFileButton,           0, 1, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*scratchpadButton,           1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*simplePlaylistMgmtButton,   2, 3, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*schedulerButton,            3, 4, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*searchButton,               4, 5, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);

    // re-bind events to the buttons
    uploadFileButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onUploadFileButtonClicked));
    scratchpadButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onScratchpadButtonClicked));
    simplePlaylistMgmtButton->signal_clicked().connect(
            sigc::mem_fun(*this,
                 &MasterPanelWindow::onSimplePlaylistMgmtButtonClicked));
    schedulerButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onSchedulerButtonClicked));
    searchButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onSearchButtonClicked));
}

/*------------------------------------------------------------------------------
 *  Set the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: setTimer(void)                                  throw ()
{
    sigc::slot<bool>    slot = sigc::bind(sigc::mem_fun(*this,
                                              &MasterPanelWindow::onUpdateTime),
                                              0);

    // set the timer to active once a second
    timer.reset(new sigc::connection(
                                  Glib::signal_timeout().connect(slot, 1000)));
}

/*------------------------------------------------------------------------------
 *  Clear the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: resetTimer(void)                                throw ()
{
    timer->disconnect();
    timer.reset();
}

/*------------------------------------------------------------------------------
 *  Update the timeWidget display, with the current time
 *----------------------------------------------------------------------------*/
bool
MasterPanelWindow :: onUpdateTime(int   dummy)                       throw ()
{
    Ptr<const ptime>::Ref   now;

    try {
        now = gLiveSupport->getScheduler()->getSchedulerTime();
    } catch (XmlRpcException &e) {
        // TODO: handle error
    }

    if (now.get()) {
        time_duration           dayTime = now->time_of_day();
        // get the time of day, only up to a second precision
        time_duration           dayTimeSec(dayTime.hours(),
                                           dayTime.minutes(),
                                           dayTime.seconds(),
                                           0);

        timeWidget->set_text(to_simple_string(dayTimeSec));
    }

    return true;
}

/*------------------------------------------------------------------------------
 *  The event when the upload file button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onUploadFileButtonClicked(void)                 throw ()
{
    if (!scratchpadWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("uploadFileWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        uploadFileWindow.reset(new UploadFileWindow(gLiveSupport, bundle));
    }

    if (!uploadFileWindow->is_visible()) {
        uploadFileWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Scratchpad button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onScratchpadButtonClicked(void)                throw ()
{
    if (!scratchpadWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("scratchpadWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        scratchpadWindow.reset(new ScratchpadWindow(gLiveSupport, bundle));
    }

    if (!scratchpadWindow->is_visible()) {
        scratchpadWindow->show();
    }

    scratchpadWindow->showContents();
}

/*------------------------------------------------------------------------------
 *  The event when the Simple Playlist Management button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSimplePlaylistMgmtButtonClicked(void)        throw ()
{
    if (!simplePlaylistMgmtWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("simplePlaylistManagementWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        simplePlaylistMgmtWindow.reset(
                new SimplePlaylistManagementWindow(gLiveSupport, bundle));
    }

    if (!simplePlaylistMgmtWindow->is_visible()) {
        simplePlaylistMgmtWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Scheduler button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSchedulerButtonClicked(void)                 throw ()
{
    if (!schedulerWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("schedulerWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        schedulerWindow.reset(new SchedulerWindow(gLiveSupport, bundle));
    }

    if (!schedulerWindow->is_visible()) {
        schedulerWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Search button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSearchButtonClicked(void)                    throw ()
{
    if (!searchWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("searchWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        searchWindow.reset(new SearchWindow(gLiveSupport, bundle));
    }

    if (!searchWindow->is_visible()) {
        searchWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  Show only the UI components that are visible when no one is logged in
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showAnonymousUI(void)                          throw ()
{
    show_all();
    buttonBar->hide();
    uploadFileButton->hide();
    scratchpadButton->hide();
    simplePlaylistMgmtButton->hide();
    schedulerButton->hide();
    searchButton->hide();

    if (uploadFileWindow) {
        uploadFileWindow->hide();
    }
    if (scratchpadWindow) {
        scratchpadWindow->hide();
    }
    if (simplePlaylistMgmtWindow) {
        simplePlaylistMgmtWindow->hide();
    }
    if (schedulerWindow) {
        schedulerWindow->hide();
    }
    if (searchWindow) {
        searchWindow->hide();
    }
}

/*------------------------------------------------------------------------------
 *  Show the UI components that are visible to a specific user.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showLoggedInUI(void)                           throw ()
{
    show_all();
}

<commit_msg>all windows but the master panel are destroyed at logout fix for issue #878, see http://bugs.campware.org/view.php?id=878<commit_after>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the LiveSupport project.
    http://livesupport.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    LiveSupport is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    LiveSupport 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with LiveSupport; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author: maroy $
    Version  : $Revision: 1.22 $
    Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/products/gLiveSupport/src/MasterPanelWindow.cxx,v $

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#include <iostream>
#include <unicode/msgfmt.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>

#include "LiveSupport/Core/TimeConversion.h"
#include "MasterPanelWindow.h"

using namespace LiveSupport;
using namespace LiveSupport::GLiveSupport;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: MasterPanelWindow (Ptr<GLiveSupport>::Ref    gLiveSupport,
                                        Ptr<ResourceBundle>::Ref  bundle)
                                                                    throw ()
                        : LocalizedObject(bundle)
{
    this->gLiveSupport = gLiveSupport;

    Ptr<WidgetFactory>::Ref widgetFactory = WidgetFactory::getInstance();

    // TODO: remove hard-coded station logo path reference
    radioLogoWidget = Gtk::manage(new Gtk::Image("var/stationLogo.png"));
    radioLogoWidget->set_size_request(158, 104);

    // set up the layout, which is a button box
    layout = Gtk::manage(new Gtk::Table());

    // set up the time label
    timeWidget = Gtk::manage(new Gtk::Label("time"));
    timeBin = Gtk::manage(widgetFactory->createBlueBin());
    timeBin->add(*timeWidget);
    timeBin->set_size_request(153, 104);

    // set up the now playing widget
    nowPlayingWidget = Gtk::manage(new Gtk::Label("now playing"));
    nowPlayingBin = Gtk::manage(widgetFactory->createDarkBlueBin());
    nowPlayingBin->add(*nowPlayingWidget);
    timeBin->set_size_request(-1, 104);

    // set up the VU meter widget
    vuMeterWidget = Gtk::manage(new Gtk::Label("VU meter"));
    vuMeterBin = Gtk::manage(widgetFactory->createBlueBin());
    vuMeterBin->add(*vuMeterWidget);
    vuMeterBin->set_size_request(400, 40);
    // set up the next playing widget
    nextPlayingWidget = Gtk::manage(new Gtk::Label("next playing"));
    nextPlayingBin = Gtk::manage(widgetFactory->createBlueBin());
    nextPlayingBin->add(*nextPlayingWidget);
    nextPlayingBin->set_size_request(400, 59);

    // create the bottom bar
    bottomBar = Gtk::manage(new Gtk::Table());
    bottomBar->set_size_request(-1, 30);
    buttonBar = Gtk::manage(new Gtk::Table());
    buttonBarAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_LEFT,
                                                        Gtk::ALIGN_CENTER,
                                                        0, 0));
    buttonBarAlignment->add(*buttonBar);
    userInfoWidget = Gtk::manage(new MasterPanelUserInfoWidget(gLiveSupport,
                                                               bundle));
    userInfoAlignment = Gtk::manage(new Gtk::Alignment(Gtk::ALIGN_RIGHT,
                                                       Gtk::ALIGN_CENTER,
                                                       0, 0));
    userInfoAlignment->add(*userInfoWidget);
    bottomBar->attach(*buttonBarAlignment, 0, 1, 0, 1,
                      Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    bottomBar->attach(*userInfoAlignment,  1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    // set up the main window, and show everything
    // all the localized widgets were set up in changeLanguage()
    set_border_width(10);
    layout->attach(*timeBin,         0, 1, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nowPlayingBin,   1, 2, 0, 2,
                   Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                   5, 0);
    layout->attach(*vuMeterBin,      2, 3, 0, 1,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*nextPlayingBin,  2, 3, 1, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    layout->attach(*radioLogoWidget, 3, 4, 0, 2,
                    Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    5, 0);
    layout->attach(*bottomBar,       0, 4, 2, 3,
                    Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                    0, 0);
    add(*layout);

    // set the background to white
    bgColor = Colors::getColor(Colors::White);
    modify_bg(Gtk::STATE_NORMAL, bgColor);

    // set the size and location of the window, according to the screen size
    Glib::RefPtr<Gdk::Screen>   screen = get_screen();
    int                         width;
    int                         height;
    get_size(width, height);
    width = screen->get_width();
    set_default_size(width, height);
    move(0, 0);
    set_decorated(false);

    // set the localized resources
    changeLanguage(bundle);

    // show what's there to see
    showAnonymousUI();

    // set the timer, that will update timeWidget
    setTimer();
}

/*------------------------------------------------------------------------------
 *  Destructor.
 *----------------------------------------------------------------------------*/
MasterPanelWindow :: ~MasterPanelWindow (void)                        throw ()
{
    resetTimer();
    gLiveSupport->stopAudio();
}

/*------------------------------------------------------------------------------
 *  Change the language of the panel
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: changeLanguage(Ptr<ResourceBundle>::Ref    bundle)
                                                                    throw ()
{
    setBundle(bundle);

    try {
        set_title(*getResourceUstring("windowTitle"));

        Ptr<WidgetFactory>::Ref wf = WidgetFactory::getInstance();

        uploadFileButton = wf->createButton(
                                *getResourceUstring("uploadFileButtonLabel"));
        scratchpadButton = wf->createButton(
                                *getResourceUstring("scratchpadButtonLabel"));
        simplePlaylistMgmtButton = wf->createButton(
                        *getResourceUstring("simplePlaylistMgmtButtonLabel"));
        schedulerButton = wf->createButton(
                                *getResourceUstring("schedulerButtonLabel"));
        searchButton = wf->createButton(
                                *getResourceUstring("searchButtonLabel"));
    } catch (std::invalid_argument &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }

    userInfoWidget->changeLanguage(bundle);

    // re-attach the localized widgets to the layout
    buttonBar->attach(*uploadFileButton,           0, 1, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*scratchpadButton,           1, 2, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*simplePlaylistMgmtButton,   2, 3, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*schedulerButton,            3, 4, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);
    buttonBar->attach(*searchButton,               4, 5, 0, 1,
                      Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL,
                      5, 0);

    // re-bind events to the buttons
    uploadFileButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onUploadFileButtonClicked));
    scratchpadButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onScratchpadButtonClicked));
    simplePlaylistMgmtButton->signal_clicked().connect(
            sigc::mem_fun(*this,
                 &MasterPanelWindow::onSimplePlaylistMgmtButtonClicked));
    schedulerButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onSchedulerButtonClicked));
    searchButton->signal_clicked().connect(sigc::mem_fun(*this,
                            &MasterPanelWindow::onSearchButtonClicked));
}

/*------------------------------------------------------------------------------
 *  Set the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: setTimer(void)                                  throw ()
{
    sigc::slot<bool>    slot = sigc::bind(sigc::mem_fun(*this,
                                              &MasterPanelWindow::onUpdateTime),
                                              0);

    // set the timer to active once a second
    timer.reset(new sigc::connection(
                                  Glib::signal_timeout().connect(slot, 1000)));
}

/*------------------------------------------------------------------------------
 *  Clear the timer
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: resetTimer(void)                                throw ()
{
    timer->disconnect();
    timer.reset();
}

/*------------------------------------------------------------------------------
 *  Update the timeWidget display, with the current time
 *----------------------------------------------------------------------------*/
bool
MasterPanelWindow :: onUpdateTime(int   dummy)                       throw ()
{
    Ptr<const ptime>::Ref   now;

    try {
        now = gLiveSupport->getScheduler()->getSchedulerTime();
    } catch (XmlRpcException &e) {
        // TODO: handle error
    }

    if (now.get()) {
        time_duration           dayTime = now->time_of_day();
        // get the time of day, only up to a second precision
        time_duration           dayTimeSec(dayTime.hours(),
                                           dayTime.minutes(),
                                           dayTime.seconds(),
                                           0);

        timeWidget->set_text(to_simple_string(dayTimeSec));
    }

    return true;
}

/*------------------------------------------------------------------------------
 *  The event when the upload file button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onUploadFileButtonClicked(void)                 throw ()
{
    if (!uploadFileWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("uploadFileWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        uploadFileWindow.reset(new UploadFileWindow(gLiveSupport, bundle));
    }

    if (!uploadFileWindow->is_visible()) {
        uploadFileWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Scratchpad button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onScratchpadButtonClicked(void)                throw ()
{
    if (!scratchpadWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("scratchpadWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        scratchpadWindow.reset(new ScratchpadWindow(gLiveSupport, bundle));
    }

    if (!scratchpadWindow->is_visible()) {
        scratchpadWindow->show();
    }

    scratchpadWindow->showContents();
}

/*------------------------------------------------------------------------------
 *  The event when the Simple Playlist Management button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSimplePlaylistMgmtButtonClicked(void)        throw ()
{
    if (!simplePlaylistMgmtWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("simplePlaylistManagementWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        simplePlaylistMgmtWindow.reset(
                new SimplePlaylistManagementWindow(gLiveSupport, bundle));
    }

    if (!simplePlaylistMgmtWindow->is_visible()) {
        simplePlaylistMgmtWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Scheduler button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSchedulerButtonClicked(void)                 throw ()
{
    if (!schedulerWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("schedulerWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        schedulerWindow.reset(new SchedulerWindow(gLiveSupport, bundle));
    }

    if (!schedulerWindow->is_visible()) {
        schedulerWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  The event when the Search button has been clicked.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: onSearchButtonClicked(void)                    throw ()
{
    if (!searchWindow.get()) {
        Ptr<ResourceBundle>::Ref    bundle;
        try {
            bundle       = getBundle("searchWindow");
        } catch (std::invalid_argument &e) {
            std::cerr << e.what() << std::endl;
            return;
        }

        searchWindow.reset(new SearchWindow(gLiveSupport, bundle));
    }

    if (!searchWindow->is_visible()) {
        searchWindow->show();
    }
}

/*------------------------------------------------------------------------------
 *  Show only the UI components that are visible when no one is logged in
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showAnonymousUI(void)                          throw ()
{
    show_all();
    buttonBar->hide();
    uploadFileButton->hide();
    scratchpadButton->hide();
    simplePlaylistMgmtButton->hide();
    schedulerButton->hide();
    searchButton->hide();

    if (uploadFileWindow.get()) {
        uploadFileWindow->hide();
        uploadFileWindow.reset();
    }
    if (scratchpadWindow.get()) {
        scratchpadWindow->hide();
        scratchpadWindow.reset();
    }
    if (simplePlaylistMgmtWindow.get()) {
        simplePlaylistMgmtWindow->hide();
        simplePlaylistMgmtWindow.reset();
    }
    if (schedulerWindow.get()) {
        schedulerWindow->hide();
        schedulerWindow.reset();
    }
    if (searchWindow.get()) {
        searchWindow->hide();
        searchWindow.reset();
    }
}

/*------------------------------------------------------------------------------
 *  Show the UI components that are visible to a specific user.
 *----------------------------------------------------------------------------*/
void
MasterPanelWindow :: showLoggedInUI(void)                           throw ()
{
    show_all();
}

<|endoftext|>


<commit_before>/**********************************************************************
* Copyright (c) 2013-2014  Red Hat, Inc.
*
* Developed by Daynix Computing LTD.
*
* Authors:
*     Dmitry Fleytman <dmitry@daynix.com>
*     Pavel Gurvich <pavel@daynix.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************/

#include "stdafx.h"
#include "WdfDevice.h"
#include "trace.h"
#include "WdfDevice.tmh"

CDeviceInit::~CDeviceInit()
{
    if (m_Attached)
    {
        Free();
    }
}

void CDeviceInit::Attach(PWDFDEVICE_INIT DevInit)
{
    m_Attached = true;
    CPreAllocatedDeviceInit::Attach(DevInit);
}

PWDFDEVICE_INIT CDeviceInit::Detach()
{
    m_Attached = false;
    return CPreAllocatedDeviceInit::Detach();
}

NTSTATUS CPreAllocatedDeviceInit::SetName(const UNICODE_STRING &Name)
{
    auto status = WdfDeviceInitAssignName(m_DeviceInit, &Name);

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    return status;
}

void CPreAllocatedDeviceInit::Free()
{
    WdfDeviceInitFree(m_DeviceInit);
}

void CPreAllocatedDeviceInit::SetPowerCallbacks(PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT SelfManagedIoFunc)
{
    WDF_PNPPOWER_EVENT_CALLBACKS  Callbacks;
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
    Callbacks.EvtDeviceSelfManagedIoInit = SelfManagedIoFunc;
    WdfDeviceInitSetPnpPowerEventCallbacks(m_DeviceInit, &Callbacks);
}

void CPreAllocatedDeviceInit::Attach(PWDFDEVICE_INIT DeviceInit)
{
    m_DeviceInit = DeviceInit;
}

PWDFDEVICE_INIT CPreAllocatedDeviceInit::Detach()
{
    auto DevInit = m_DeviceInit;
    m_DeviceInit = nullptr;
    return DevInit;
}

NTSTATUS CPreAllocatedDeviceInit::SetPreprocessCallback(PFN_WDFDEVICE_WDM_IRP_PREPROCESS Callback,
                                                        UCHAR MajorFunction,
                                                        const PUCHAR MinorFunctions,
                                                        ULONG NumMinorFunctions)
{
    auto status = WdfDeviceInitAssignWdmIrpPreprocessCallback(m_DeviceInit,
                                                              Callback,
                                                              MajorFunction,
                                                              MinorFunctions,
                                                              NumMinorFunctions);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! status: %!STATUS!", status);
    }
    return status;
}

NTSTATUS CWdfDevice::CreateSymLink(const UNICODE_STRING &Name)
{
    auto status = WdfDeviceCreateSymbolicLink(m_Device, &Name);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }
    return status;
}

NTSTATUS CWdfDevice::Create(CPreAllocatedDeviceInit &DeviceInit, WDF_OBJECT_ATTRIBUTES &DeviceAttr)
{
    auto DevInitObj = DeviceInit.Detach();

    auto status = WdfDeviceCreate(&DevInitObj, &DeviceAttr, &m_Device);
    if (!NT_SUCCESS(status))
    {
        DeviceInit.Attach(DevInitObj);
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    status = CacheDeviceName();
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! Device name caching failed %!STATUS!", status);
    }

    return status;
}

NTSTATUS CWdfQueue::Create(CWdfDevice &Device)
{
    WDF_IO_QUEUE_CONFIG      QueueConfig;
    WDF_OBJECT_ATTRIBUTES    Attributes;

    InitConfig(QueueConfig);
    SetCallbacks(QueueConfig);

    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
    Attributes.ExecutionLevel = WdfExecutionLevelPassive;

    auto status = Device.AddQueue(QueueConfig, Attributes, m_Queue);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    return status;
}

NTSTATUS CWdfDevice::AddQueue(WDF_IO_QUEUE_CONFIG &Config, WDF_OBJECT_ATTRIBUTES &Attributes, WDFQUEUE &Queue)
{
    auto status = WdfIoQueueCreate(m_Device, &Config, &Attributes, &Queue);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    return status;
}

void CWdfDefaultQueue::InitConfig(WDF_IO_QUEUE_CONFIG &QueueConfig)
{
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, m_DispatchType);
}

void CWdfSpecificQueue::InitConfig(WDF_IO_QUEUE_CONFIG &QueueConfig)
{
    WDF_IO_QUEUE_CONFIG_INIT(&QueueConfig, m_DispatchType);
}

NTSTATUS CWdfDevice::CacheDeviceName()
{
    WDFSTRING deviceName;
    auto status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &deviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! WdfStringCreate failed. %!STATUS!", status);
        return status;
    }

    status = WdfDeviceRetrieveDeviceName(m_Device, deviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! WdfDeviceRetrieveDeviceName failed. %!STATUS!", status);
        WdfObjectDelete(deviceName);
        return status;
    }

    UNICODE_STRING UnicodeDeviceName;
    WdfStringGetUnicodeString(deviceName, &UnicodeDeviceName);

    status = m_CachedName.Create(&UnicodeDeviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! CString creation failed. %!STATUS!", status);
        WdfObjectDelete(deviceName);
        return status;
    }

    TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! Newly created device name is %wZ", &UnicodeDeviceName);
    WdfObjectDelete(deviceName);
    return STATUS_SUCCESS;
}

NTSTATUS CWdfDevice::CreateUserModeHandle(HANDLE RequestorProcess, PHANDLE ObjectHandle)
{
    IO_STATUS_BLOCK IoStatusBlock;
    PCUNICODE_STRING UniName = m_CachedName;

    OBJECT_ATTRIBUTES ObjectAttributes;
    InitializeObjectAttributes(&ObjectAttributes,
                               const_cast<PUNICODE_STRING>(UniName),
                               OBJ_KERNEL_HANDLE,
                               nullptr, nullptr);

    HANDLE KernelHandle;
    auto status = ZwOpenFile(&KernelHandle,
                             GENERIC_READ | GENERIC_WRITE,
                             &ObjectAttributes, &IoStatusBlock, 0,
                             FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! ZwOpenFile failed. %!STATUS!", status);
        return status;
    }

    status = ZwDuplicateObject(ZwCurrentProcess(),
                               KernelHandle,
                               RequestorProcess,
                               ObjectHandle,
                               0,
                               0,
                               DUPLICATE_SAME_ACCESS |
                               DUPLICATE_SAME_ATTRIBUTES |
                               DUPLICATE_CLOSE_SOURCE);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! ZwDuplicateObject failed. %!STATUS!", status);
        ZwClose(KernelHandle);
    }

    return status;
}
<commit_msg>CWdfDevice: Pacify excessive traces<commit_after>/**********************************************************************
* Copyright (c) 2013-2014  Red Hat, Inc.
*
* Developed by Daynix Computing LTD.
*
* Authors:
*     Dmitry Fleytman <dmitry@daynix.com>
*     Pavel Gurvich <pavel@daynix.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************/

#include "stdafx.h"
#include "WdfDevice.h"
#include "trace.h"
#include "WdfDevice.tmh"

CDeviceInit::~CDeviceInit()
{
    if (m_Attached)
    {
        Free();
    }
}

void CDeviceInit::Attach(PWDFDEVICE_INIT DevInit)
{
    m_Attached = true;
    CPreAllocatedDeviceInit::Attach(DevInit);
}

PWDFDEVICE_INIT CDeviceInit::Detach()
{
    m_Attached = false;
    return CPreAllocatedDeviceInit::Detach();
}

NTSTATUS CPreAllocatedDeviceInit::SetName(const UNICODE_STRING &Name)
{
    auto status = WdfDeviceInitAssignName(m_DeviceInit, &Name);

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    return status;
}

void CPreAllocatedDeviceInit::Free()
{
    WdfDeviceInitFree(m_DeviceInit);
}

void CPreAllocatedDeviceInit::SetPowerCallbacks(PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT SelfManagedIoFunc)
{
    WDF_PNPPOWER_EVENT_CALLBACKS  Callbacks;
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
    Callbacks.EvtDeviceSelfManagedIoInit = SelfManagedIoFunc;
    WdfDeviceInitSetPnpPowerEventCallbacks(m_DeviceInit, &Callbacks);
}

void CPreAllocatedDeviceInit::Attach(PWDFDEVICE_INIT DeviceInit)
{
    m_DeviceInit = DeviceInit;
}

PWDFDEVICE_INIT CPreAllocatedDeviceInit::Detach()
{
    auto DevInit = m_DeviceInit;
    m_DeviceInit = nullptr;
    return DevInit;
}

NTSTATUS CPreAllocatedDeviceInit::SetPreprocessCallback(PFN_WDFDEVICE_WDM_IRP_PREPROCESS Callback,
                                                        UCHAR MajorFunction,
                                                        const PUCHAR MinorFunctions,
                                                        ULONG NumMinorFunctions)
{
    auto status = WdfDeviceInitAssignWdmIrpPreprocessCallback(m_DeviceInit,
                                                              Callback,
                                                              MajorFunction,
                                                              MinorFunctions,
                                                              NumMinorFunctions);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! status: %!STATUS!", status);
    }
    return status;
}

NTSTATUS CWdfDevice::CreateSymLink(const UNICODE_STRING &Name)
{
    auto status = WdfDeviceCreateSymbolicLink(m_Device, &Name);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }
    return status;
}

NTSTATUS CWdfDevice::Create(CPreAllocatedDeviceInit &DeviceInit, WDF_OBJECT_ATTRIBUTES &DeviceAttr)
{
    auto DevInitObj = DeviceInit.Detach();

    auto status = WdfDeviceCreate(&DevInitObj, &DeviceAttr, &m_Device);
    if (!NT_SUCCESS(status))
    {
        DeviceInit.Attach(DevInitObj);
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    status = CacheDeviceName();
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! Device name caching failed %!STATUS!", status);
    }

    return status;
}

NTSTATUS CWdfQueue::Create(CWdfDevice &Device)
{
    WDF_IO_QUEUE_CONFIG      QueueConfig;
    WDF_OBJECT_ATTRIBUTES    Attributes;

    InitConfig(QueueConfig);
    SetCallbacks(QueueConfig);

    WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
    Attributes.ExecutionLevel = WdfExecutionLevelPassive;

    auto status = Device.AddQueue(QueueConfig, Attributes, m_Queue);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    return status;
}

NTSTATUS CWdfDevice::AddQueue(WDF_IO_QUEUE_CONFIG &Config, WDF_OBJECT_ATTRIBUTES &Attributes, WDFQUEUE &Queue)
{
    auto status = WdfIoQueueCreate(m_Device, &Config, &Attributes, &Queue);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! failed %!STATUS!", status);
    }

    return status;
}

void CWdfDefaultQueue::InitConfig(WDF_IO_QUEUE_CONFIG &QueueConfig)
{
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, m_DispatchType);
}

void CWdfSpecificQueue::InitConfig(WDF_IO_QUEUE_CONFIG &QueueConfig)
{
    WDF_IO_QUEUE_CONFIG_INIT(&QueueConfig, m_DispatchType);
}

NTSTATUS CWdfDevice::CacheDeviceName()
{
    WDFSTRING deviceName;
    auto status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &deviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! WdfStringCreate failed. %!STATUS!", status);
        return status;
    }

    status = WdfDeviceRetrieveDeviceName(m_Device, deviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! WdfDeviceRetrieveDeviceName failed. %!STATUS!", status);
        WdfObjectDelete(deviceName);
        return status;
    }

    UNICODE_STRING UnicodeDeviceName;
    WdfStringGetUnicodeString(deviceName, &UnicodeDeviceName);

    status = m_CachedName.Create(&UnicodeDeviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! CString creation failed. %!STATUS!", status);
        WdfObjectDelete(deviceName);
        return status;
    }

    TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! Newly created device name is %wZ", &UnicodeDeviceName);
    WdfObjectDelete(deviceName);
    return STATUS_SUCCESS;
}

NTSTATUS CWdfDevice::CreateUserModeHandle(HANDLE RequestorProcess, PHANDLE ObjectHandle)
{
    IO_STATUS_BLOCK IoStatusBlock;
    PCUNICODE_STRING UniName = m_CachedName;

    OBJECT_ATTRIBUTES ObjectAttributes;
    InitializeObjectAttributes(&ObjectAttributes,
                               const_cast<PUNICODE_STRING>(UniName),
                               OBJ_KERNEL_HANDLE,
                               nullptr, nullptr);

    HANDLE KernelHandle;
    auto status = ZwOpenFile(&KernelHandle,
                             GENERIC_READ | GENERIC_WRITE,
                             &ObjectAttributes, &IoStatusBlock, 0,
                             FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS);
    if (!NT_SUCCESS(status))
    {
        return status;
    }

    status = ZwDuplicateObject(ZwCurrentProcess(),
                               KernelHandle,
                               RequestorProcess,
                               ObjectHandle,
                               0,
                               0,
                               DUPLICATE_SAME_ACCESS |
                               DUPLICATE_SAME_ATTRIBUTES |
                               DUPLICATE_CLOSE_SOURCE);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_WDFDEVICE, "%!FUNC! ZwDuplicateObject failed. %!STATUS!", status);
        ZwClose(KernelHandle);
    }

    return status;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 - 2015, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/io/BufferedPipe.h>

namespace stingray
{

	BufferedPipe::BufferedPipe(const IPipePtr& pipe, size_t bufferSize)
		: _pipe(pipe), _buffer(bufferSize), _bufferOffset(), _bufferSize()
	{ }

	u64 BufferedPipe::Read(ByteData data, const ICancellationToken& token)
	{
		if (_bufferOffset == _bufferSize)
		{
			const size_t size = _pipe->Read(_buffer.GetByteData(), token);
			if (size == 0)
				return 0;

			_bufferOffset = 0;
			_bufferSize = size;
		}

		const size_t size = std::min(_bufferSize - _bufferOffset, data.size());
		std::copy(_buffer.begin() + _bufferOffset, _buffer.begin() + _bufferOffset + size, data.begin());
		_bufferOffset += size;

		return size;
	}

}
<commit_msg>use data/size methods of ByteData instead of begin/end<commit_after>// Copyright (c) 2011 - 2015, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/io/BufferedPipe.h>

namespace stingray
{

	BufferedPipe::BufferedPipe(const IPipePtr& pipe, size_t bufferSize)
		: _pipe(pipe), _buffer(bufferSize), _bufferOffset(), _bufferSize()
	{ }

	u64 BufferedPipe::Read(ByteData data, const ICancellationToken& token)
	{
		if (_bufferOffset == _bufferSize)
		{
			const size_t size = _pipe->Read(_buffer.GetByteData(), token);
			if (size == 0)
				return 0;

			_bufferOffset = 0;
			_bufferSize = size;
		}

		const size_t size = std::min(_bufferSize - _bufferOffset, data.size());
		std::copy(_buffer.data() + _bufferOffset, _buffer.data() + _bufferOffset + size, data.data());
		_bufferOffset += size;

		return size;
	}

}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef TWSM_SERVER_BROWSER
#define TWSM_SERVER_BROWSER

#include "ui_main_window.h"

#include <mlk/log/log.h>
#include <mlk/time/simple_timer.h>

#include <twl/network/network.hpp>

#include <QObject>
#include <QTableWidgetItem>

namespace Ui
{class main_window;}

namespace twsm
{
	class server_browser : public QObject
	{
		Q_OBJECT

		Ui::main_window& m_ui;

		twl::master_server m_masters;
		twl::game_server m_servers;

		mlk::tm::simple_timer m_stopwatch{0};

		bool m_refreshing_masters{false}, m_refreshing{false};

	public:
		server_browser(Ui::main_window& ui) :
			m_ui{ui}
		{ }

		void update()
		{
			m_masters.update();
			m_servers.update();
		}

		void init()
		{
			mlk::lout("server_browser", true) << "init. settings default masters. setting up events.";

			// setup default masters
			m_masters.add_master({"master1.teeworlds.com:8300"});
			m_masters.add_master({"master2.teeworlds.com:8300"});
			m_masters.add_master({"master3.teeworlds.com:8300"});
			m_masters.add_master({"master4.teeworlds.com:8300"});

			// setup events
			m_masters.on_finish = [this]{this->masters_finished();};
			m_servers.on_finish = [this]{this->servers_finished();};

			// ui events
			QObject::connect(m_ui.m_pb_srvb_refresh, SIGNAL(clicked()), this, SLOT(refresh()));
		}

	public slots:
		void refresh()
		{
			// reset ui
			m_ui.m_tw_srvb_list->clearContents();
			m_ui.m_tw_srvb_list->setRowCount(0);
			m_ui.m_lb_srvb_status->setText("Refreshing masters...");

			// request masterlist
			m_refreshing_masters = true;
			m_masters.request_list();
		}

	private:
		void masters_finished()
		{
			// master refresh finished

			m_refreshing_masters = false;
			m_refreshing = true;

			auto ips(m_masters.get_list());
			mlk::lout("server_browser") << "refreshed masters. got " << ips.size() << " ips.";
			m_ui.m_lb_srvb_status->setText(QString{"Refreshed masters, processing %1 servers..."}.arg(ips.size()));
			if(ips.empty())
				return;

			// make ready for server refreshing
			m_servers.reset();
			m_servers.add_masterlist(ips);
			m_servers.request_info();
			m_stopwatch.restart();
		}

		void servers_finished()
		{
			// server refresh finished

			m_refreshing = false;
			auto tm(m_stopwatch.elapsed_time());
			mlk::lout("server_browser") << "refreshed servers. (twl) processed " << m_servers.get_infos().size() << " servers in " << tm << "ms.";

			m_ui.m_tw_srvb_list->setSortingEnabled(false);
			for(auto& a : m_servers.get_infos())
			{
				m_ui.m_tw_srvb_list->insertRow(m_ui.m_tw_srvb_list->rowCount());
				auto* name(new QTableWidgetItem{a.name().c_str()});
				auto* type(new QTableWidgetItem{a.gametype().c_str()});
				auto* map(new QTableWidgetItem{a.mapname().c_str()});
				auto* players(new QTableWidgetItem{QString{"%1/%2"}.arg(a.numclients()).arg(a.maxclients())});
				auto* ping(new QTableWidgetItem{QString{"%1"}.arg(a.ping())});

				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 0, name);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 1, type);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 2, map);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 3, players);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 4, ping);
			}

			m_ui.m_tw_srvb_list->setSortingEnabled(true);
			m_ui.m_lb_srvb_status->setText("Servers refreshed.");
			mlk::lout("server_browser") << "ui took " << m_stopwatch.elapsed_time() - tm << " ms.";
		}
	};
}

#endif // TWSM_SERVER_BROWSER

<commit_msg>serverbrowser: changed text on 0 servers<commit_after>//
// Copyright (c) 2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef TWSM_SERVER_BROWSER
#define TWSM_SERVER_BROWSER

#include "ui_main_window.h"

#include <mlk/log/log.h>
#include <mlk/time/simple_timer.h>

#include <twl/network/network.hpp>

#include <QObject>
#include <QTableWidgetItem>

namespace Ui
{class main_window;}

namespace twsm
{
	class server_browser : public QObject
	{
		Q_OBJECT

		Ui::main_window& m_ui;

		twl::master_server m_masters;
		twl::game_server m_servers;

		mlk::tm::simple_timer m_stopwatch{0};

		bool m_refreshing_masters{false}, m_refreshing{false};

	public:
		server_browser(Ui::main_window& ui) :
			m_ui{ui}
		{ }

		void update()
		{
			m_masters.update();
			m_servers.update();
		}

		void init()
		{
			mlk::lout("server_browser", true) << "init. settings default masters. setting up events.";

			// setup default masters
			m_masters.add_master({"master1.teeworlds.com:8300"});
			m_masters.add_master({"master2.teeworlds.com:8300"});
			m_masters.add_master({"master3.teeworlds.com:8300"});
			m_masters.add_master({"master4.teeworlds.com:8300"});

			// setup events
			m_masters.on_finish = [this]{this->masters_finished();};
			m_servers.on_finish = [this]{this->servers_finished();};

			// ui events
			QObject::connect(m_ui.m_pb_srvb_refresh, SIGNAL(clicked()), this, SLOT(refresh()));
		}

	public slots:
		void refresh()
		{
			// reset ui
			m_ui.m_tw_srvb_list->clearContents();
			m_ui.m_tw_srvb_list->setRowCount(0);
			m_ui.m_lb_srvb_status->setText("Refreshing masters...");

			// request masterlist
			m_refreshing_masters = true;
			m_masters.request_list();
		}

	private:
		void masters_finished()
		{
			// master refresh finished

			m_refreshing_masters = false;
			m_refreshing = true;

			auto ips(m_masters.get_list());
			mlk::lout("server_browser") << "refreshed masters. got " << ips.size() << " ips.";
			if(ips.empty())
			{
				m_ui.m_lb_srvb_status->setText("Got no servers from masters. Stopping refreshing.");
				return;
			}

			m_ui.m_lb_srvb_status->setText(QString{"Refreshed masters, processing %1 servers..."}.arg(ips.size()));

			// make ready for server refreshing
			m_servers.reset();
			m_servers.add_masterlist(ips);
			m_servers.request_info();
			m_stopwatch.restart();
		}

		void servers_finished()
		{
			// server refresh finished

			m_refreshing = false;
			auto tm(m_stopwatch.elapsed_time());
			mlk::lout("server_browser") << "refreshed servers. (twl) processed " << m_servers.get_infos().size() << " servers in " << tm << "ms.";

			m_ui.m_tw_srvb_list->setSortingEnabled(false);
			for(auto& a : m_servers.get_infos())
			{
				m_ui.m_tw_srvb_list->insertRow(m_ui.m_tw_srvb_list->rowCount());
				auto* name(new QTableWidgetItem{a.name().c_str()});
				auto* type(new QTableWidgetItem{a.gametype().c_str()});
				auto* map(new QTableWidgetItem{a.mapname().c_str()});
				auto* players(new QTableWidgetItem{QString{"%1/%2"}.arg(a.numclients()).arg(a.maxclients())});
				auto* ping(new QTableWidgetItem{QString{"%1"}.arg(a.ping())});

				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 0, name);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 1, type);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 2, map);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 3, players);
				m_ui.m_tw_srvb_list->setItem(m_ui.m_tw_srvb_list->rowCount() - 1, 4, ping);
			}

			m_ui.m_tw_srvb_list->setSortingEnabled(true);
			m_ui.m_lb_srvb_status->setText("Servers refreshed.");
			mlk::lout("server_browser") << "ui took " << m_stopwatch.elapsed_time() - tm << " ms.";
		}
	};
}

#endif // TWSM_SERVER_BROWSER

<|endoftext|>


<commit_before>#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP

#include <type_traits>
#include "../config/config.h"

namespace entt {

/*! @brief Commonly used default traits for all types. */
struct basic_component_traits {
    /*! @brief Pointer stability, default is `std::false_type`. */
    using in_place_delete = std::false_type;
    /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
    using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
};

/**
 * @brief Common way to access various properties of components.
 * @tparam Type Type of component.
 */
template<typename Type, typename = void>
struct component_traits: basic_component_traits {
    static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
};

}

#endif
<commit_msg>component: added in_place_delete_v and ignore_if_empty_v<commit_after>#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP

#include <type_traits>
#include "../config/config.h"

namespace entt {

/*! @brief Commonly used default traits for all types. */
struct basic_component_traits {
    /*! @brief Pointer stability, default is `std::false_type`. */
    using in_place_delete = std::false_type;
    /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
    using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
};

/**
 * @brief Common way to access various properties of components.
 * @tparam Type Type of component.
 */
template<typename Type, typename = void>
struct component_traits: basic_component_traits {
    static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
};

/**
 * @brief Helper variable template.
 * @tparam Type Type of component.
 */
template<class Type>
inline constexpr bool in_place_delete_v = component_traits<Type>::in_place_delete::value;

/**
 * @brief Helper variable template.
 * @tparam Type Type of component.
 */
template<class Type>
inline constexpr bool ignore_if_empty_v = component_traits<Type>::ignore_if_empty::value;

}

#endif
<|endoftext|>