<commit_before>#include "deviceinfo.h"
#include "log/logger.h"
#include "client.h"
#include "network/networkmanager.h"

#include <QCryptographicHash>
#include <QDir>
#include <fstab.h>
#include <unistd.h>
#include <QThread>
#include <QNetworkConfigurationManager>
#include <qnetworkinfo.h>
#include <qdeviceinfo.h>
#include <qstorageinfo.h>

LOGGER(DeviceInfo);

Q_GLOBAL_STATIC_WITH_ARGS(const QString, BATTERY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/BAT%1/")))

namespace
{
    static const char *FSEntries[] =
    {
        "/",
        "/boot",
        NULL
    };

    QByteArray uuidForDevice(const QString &device)
    {
        QByteArray uuid;

        QDir byUuidDir("/dev/disk/by-uuid");

        foreach (const QFileInfo &uuidFileInfo, byUuidDir.entryInfoList(QDir::Files))
        {
            if (device == uuidFileInfo.symLinkTarget())
            {
                uuid = uuidFileInfo.fileName().toUtf8();
                break;
            }
        }

        return uuid;
    }
}

DeviceInfo::DeviceInfo()
: d(NULL)
{
}

DeviceInfo::~DeviceInfo()
{
}

QString DeviceInfo::deviceId() const
{
    if (int ret = setfsent() != 1)
    {
        LOG_ERROR(QString("Error opening fstab: setfsent returned %1").arg(ret));
        return QString();
    }

    QByteArray uuid;

    for (const char **fsentry = FSEntries; *fsentry != NULL; ++fsentry)
    {
        fstab *tab = getfsfile(*fsentry);

        if (!tab)
        {
            continue;
        }

        uuid = QByteArray::fromRawData(tab->fs_spec, strlen(tab->fs_spec));

        if (uuid.indexOf("UUID=") == 0)
        {
            uuid.remove(0, 5);
            break;
        }
        else
        {
            // No UUID in fstab
            QString target;
            QFileInfo info;

            if (uuid.indexOf("LABEL=") == 0)
            {
                uuid.remove(0, 6);
                info = QFileInfo(QString("/dev/disk/by-label/%1").arg(QString::fromUtf8(uuid)));
            }
            else
            {
                info = QFileInfo(uuid);
            }

            uuid.clear();

            if (info.isSymLink())
            {
                target = info.symLinkTarget();
            }
            else
            {
                target = info.absoluteFilePath();
            }

            uuid = uuidForDevice(target);

            if (!uuid.isEmpty())
            {
                break;
            }
        }
    }

    endfsent();

    if (uuid.isEmpty())
    {
        LOG_ERROR("No HDD UID found!");
        return QString();
    }

    LOG_INFO(QString("HDD UUID: %1").arg(QString::fromLatin1(uuid)));

    QCryptographicHash hash(QCryptographicHash::Sha224);
    hash.addData(uuid);

    return QString::fromLatin1(hash.result().toHex());
}

qreal DeviceInfo::cpuUsage() const
{
    QFile file("/proc/stat");

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        return -1.0;
    }

    QString load = file.readLine();

    QStringList toks = load.split(" ");

    long idle1 = toks[5].toLong();
    long cpu1 = toks[2].toLong() + toks[3].toLong() + toks[4].toLong()
                + toks[6].toLong() + toks[7].toLong() + toks[8].toLong();

    // sleep, this is not good (180ms at the moment)
    QThread::usleep(180000);

    file.seek(0);
    load = file.readLine();
    file.close();

    toks = load.split(" ");

    long idle2 = toks[5].toLong();
    long cpu2 = toks[2].toLong() + toks[3].toLong() + toks[4].toLong()
                + toks[6].toLong() + toks[7].toLong() + toks[8].toLong();

    return (float)(cpu2 - cpu1) / ((cpu2 + idle2) - (cpu1 + idle1));
}

qint32 DeviceInfo::signalStrength() const
{
    return QNetworkInfo().networkSignalStrength(Client::instance()->networkManager()->connectionMode(), 0);
}

qint8 DeviceInfo::batteryLevel() const
{
    bool ok = false;

    // this gives us the percentage without needing to calculate anything
    QFile level(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("capacity"));

    if (level.open(QIODevice::ReadOnly))
    {
        int capacity = level.readAll().simplified().toInt(&ok);

        if (ok)
        {
            return capacity;
        }
    }

    QFile *remaining;
    QFile *maximum;

    QFile remainingCharge(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("charge_now"));
    QFile maximumCharge(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("charge_full"));
    // on some Linux systems different file are used for battery details
    QFile remainingEnergy(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("energy_now"));
    QFile maximumEnergy(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("energy_full"));

    if (!remainingCharge.open(QIODevice::ReadOnly) || !maximumCharge.open(QIODevice::ReadOnly))
    {
        if (!remainingEnergy.open(QIODevice::ReadOnly) || !maximumEnergy.open(QIODevice::ReadOnly))
        {
            return -1;
        }

        remaining = &remainingEnergy;
        maximum = &maximumEnergy;
    }
    else
    {
        remaining = &remainingCharge;
        maximum = &maximumCharge;
    }

    int capacityRemaining = remaining->readAll().simplified().toInt(&ok);

    if (!ok)
    {
        return -1;
    }

    int capacityMaximum = maximum->readAll().simplified().toInt(&ok);

    if (!ok)
    {
        return -1;
    }

    return capacityRemaining * 100 / capacityMaximum;
}

QString DeviceInfo::OSName() const
{
    return QDeviceInfo().operatingSystemName();
}

QString DeviceInfo::OSVersion() const
{
    return QDeviceInfo().version(QDeviceInfo::Os);
}

QString DeviceInfo::firmwareVersion() const
{
    return QDeviceInfo().version(QDeviceInfo::Firmware);
}

QString DeviceInfo::board() const
{
    return QDeviceInfo().boardName();
}

QString DeviceInfo::manufacturer() const
{
    return DeviceInfo().manufacturer();
}

QString DeviceInfo::model() const
{
    return DeviceInfo().model();
}

qlonglong DeviceInfo::availableDiskSpace() const
{
    QStorageInfo info;
    qlonglong diskSpace = 0;
    /*
     * The method allLogicalDrives() lists the device's mount points.
     * Some might appear twice (e.g. "/"), others not at all (e.g. "/boot").
     * The resulting disk space may therefore be slightly inaccurate.
     */
    QStringList drives = info.allLogicalDrives();

    drives.removeDuplicates();

    foreach (const QString &drive, drives)
    {
        if (info.driveType(drive) == QStorageInfo::InternalDrive)
        {
            diskSpace += info.availableDiskSpace(drive);
        }
    }

    return diskSpace;
}
<commit_msg>add signal strength for unix<commit_after>#include "deviceinfo.h"
#include "log/logger.h"
#include "client.h"
#include "network/networkmanager.h"

#include <QCryptographicHash>
#include <QDir>
#include <fstab.h>
#include <unistd.h>
#include <QThread>
#include <QNetworkConfigurationManager>
#include <qnetworkinfo.h>
#include <qdeviceinfo.h>
#include <qstorageinfo.h>

LOGGER(DeviceInfo);

Q_GLOBAL_STATIC_WITH_ARGS(const QString, BATTERY_SYSFS_PATH, (QLatin1String("/sys/class/power_supply/BAT%1/")))

namespace
{
    static const char *FSEntries[] =
    {
        "/",
        "/boot",
        NULL
    };

    QByteArray uuidForDevice(const QString &device)
    {
        QByteArray uuid;

        QDir byUuidDir("/dev/disk/by-uuid");

        foreach (const QFileInfo &uuidFileInfo, byUuidDir.entryInfoList(QDir::Files))
        {
            if (device == uuidFileInfo.symLinkTarget())
            {
                uuid = uuidFileInfo.fileName().toUtf8();
                break;
            }
        }

        return uuid;
    }
}

DeviceInfo::DeviceInfo()
: d(NULL)
{
}

DeviceInfo::~DeviceInfo()
{
}

QString DeviceInfo::deviceId() const
{
    if (int ret = setfsent() != 1)
    {
        LOG_ERROR(QString("Error opening fstab: setfsent returned %1").arg(ret));
        return QString();
    }

    QByteArray uuid;

    for (const char **fsentry = FSEntries; *fsentry != NULL; ++fsentry)
    {
        fstab *tab = getfsfile(*fsentry);

        if (!tab)
        {
            continue;
        }

        uuid = QByteArray::fromRawData(tab->fs_spec, strlen(tab->fs_spec));

        if (uuid.indexOf("UUID=") == 0)
        {
            uuid.remove(0, 5);
            break;
        }
        else
        {
            // No UUID in fstab
            QString target;
            QFileInfo info;

            if (uuid.indexOf("LABEL=") == 0)
            {
                uuid.remove(0, 6);
                info = QFileInfo(QString("/dev/disk/by-label/%1").arg(QString::fromUtf8(uuid)));
            }
            else
            {
                info = QFileInfo(uuid);
            }

            uuid.clear();

            if (info.isSymLink())
            {
                target = info.symLinkTarget();
            }
            else
            {
                target = info.absoluteFilePath();
            }

            uuid = uuidForDevice(target);

            if (!uuid.isEmpty())
            {
                break;
            }
        }
    }

    endfsent();

    if (uuid.isEmpty())
    {
        LOG_ERROR("No HDD UID found!");
        return QString();
    }

    LOG_INFO(QString("HDD UUID: %1").arg(QString::fromLatin1(uuid)));

    QCryptographicHash hash(QCryptographicHash::Sha224);
    hash.addData(uuid);

    return QString::fromLatin1(hash.result().toHex());
}

qint32 DeviceInfo::signalStrength() const
{
    return QNetworkInfo().networkSignalStrength(Client::instance()->networkManager()->connectionMode(), 0);
}

qreal DeviceInfo::cpuUsage() const
{
    QFile file("/proc/stat");

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        return -1.0;
    }

    QString load = file.readLine();

    QStringList toks = load.split(" ");

    long idle1 = toks[5].toLong();
    long cpu1 = toks[2].toLong() + toks[3].toLong() + toks[4].toLong()
                + toks[6].toLong() + toks[7].toLong() + toks[8].toLong();

    // sleep, this is not good (180ms at the moment)
    QThread::usleep(180000);

    file.seek(0);
    load = file.readLine();
    file.close();

    toks = load.split(" ");

    long idle2 = toks[5].toLong();
    long cpu2 = toks[2].toLong() + toks[3].toLong() + toks[4].toLong()
                + toks[6].toLong() + toks[7].toLong() + toks[8].toLong();

    return (float)(cpu2 - cpu1) / ((cpu2 + idle2) - (cpu1 + idle1));
}

qint32 DeviceInfo::signalStrength() const
{
    return QNetworkInfo().networkSignalStrength(Client::instance()->networkManager()->connectionMode(), 0);
}

qint8 DeviceInfo::batteryLevel() const
{
    bool ok = false;

    // this gives us the percentage without needing to calculate anything
    QFile level(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("capacity"));

    if (level.open(QIODevice::ReadOnly))
    {
        int capacity = level.readAll().simplified().toInt(&ok);

        if (ok)
        {
            return capacity;
        }
    }

    QFile *remaining;
    QFile *maximum;

    QFile remainingCharge(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("charge_now"));
    QFile maximumCharge(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("charge_full"));
    // on some Linux systems different file are used for battery details
    QFile remainingEnergy(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("energy_now"));
    QFile maximumEnergy(BATTERY_SYSFS_PATH()->arg(0) + QStringLiteral("energy_full"));

    if (!remainingCharge.open(QIODevice::ReadOnly) || !maximumCharge.open(QIODevice::ReadOnly))
    {
        if (!remainingEnergy.open(QIODevice::ReadOnly) || !maximumEnergy.open(QIODevice::ReadOnly))
        {
            return -1;
        }

        remaining = &remainingEnergy;
        maximum = &maximumEnergy;
    }
    else
    {
        remaining = &remainingCharge;
        maximum = &maximumCharge;
    }

    int capacityRemaining = remaining->readAll().simplified().toInt(&ok);

    if (!ok)
    {
        return -1;
    }

    int capacityMaximum = maximum->readAll().simplified().toInt(&ok);

    if (!ok)
    {
        return -1;
    }

    return capacityRemaining * 100 / capacityMaximum;
}

QString DeviceInfo::OSName() const
{
    return QDeviceInfo().operatingSystemName();
}

QString DeviceInfo::OSVersion() const
{
    return QDeviceInfo().version(QDeviceInfo::Os);
}

QString DeviceInfo::firmwareVersion() const
{
    return QDeviceInfo().version(QDeviceInfo::Firmware);
}

QString DeviceInfo::board() const
{
    return QDeviceInfo().boardName();
}

QString DeviceInfo::manufacturer() const
{
    return DeviceInfo().manufacturer();
}

QString DeviceInfo::model() const
{
    return DeviceInfo().model();
}

qlonglong DeviceInfo::availableDiskSpace() const
{
    QStorageInfo info;
    qlonglong diskSpace = 0;
    /*
     * The method allLogicalDrives() lists the device's mount points.
     * Some might appear twice (e.g. "/"), others not at all (e.g. "/boot").
     * The resulting disk space may therefore be slightly inaccurate.
     */
    QStringList drives = info.allLogicalDrives();

    drives.removeDuplicates();

    foreach (const QString &drive, drives)
    {
        if (info.driveType(drive) == QStorageInfo::InternalDrive)
        {
            diskSpace += info.availableDiskSpace(drive);
        }
    }

    return diskSpace;
}
<|endoftext|>


<commit_before>// Edge.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "stdafx.h"
#include "Edge.h"
#include "Face.h"
#include "Vertex.h"
#include "Solid.h"
#include "../interface/Tool.h"
#include "HeeksConfig.h"
#include "Gripper.h"
#include "../interface/PropertyLength.h"

CEdge::CEdge(const TopoDS_Edge &edge):m_topods_edge(edge), m_midpoint_calculated(false), m_temp_attr(0), m_vertex0(NULL), m_vertex1(NULL){
	GetCurveParams2(&m_start_u, &m_end_u, &m_isClosed, &m_isPeriodic);
	Evaluate(m_start_u, &m_start_x, &m_start_tangent_x);
	double t[3];
	Evaluate(m_end_u, &m_end_x, t);
	m_orientation = Orientation();
}

CEdge::~CEdge(){
}

void CEdge::glCommands(bool select, bool marked, bool no_color){
	if(!no_color){
		wxGetApp().glColorEnsuringContrast(HeeksColor(0, 0, 0));
	}

	if(Owner() && Owner()->Owner() && Owner()->Owner()->GetType() == SolidType)
	{
		// triangulate a face on the edge first
		TopTools_IndexedDataMapOfShapeListOfShape lface;
		TopExp::MapShapesAndAncestors(((CShape*)(Owner()->Owner()))->Shape(),TopAbs_EDGE,TopAbs_FACE,lface);
		const TopTools_ListOfShape& lfac = lface.FindFromKey(m_topods_edge);
		Standard_Integer nelem= lfac.Extent();
		if(nelem == 2){
			TopTools_ListIteratorOfListOfShape It;
			It.Initialize(lfac);
			TopoDS_Face Face1 = TopoDS::Face(It.Value());
			TopLoc_Location fL;
			Handle_Poly_Triangulation facing = BRep_Tool::Triangulation(Face1,fL);

			if(!facing.IsNull())
			{
				// Get polygon
				Handle_Poly_PolygonOnTriangulation polygon = BRep_Tool::PolygonOnTriangulation(m_topods_edge, facing, fL);
				gp_Trsf tr = fL;
				double m[16];
				extract_transposed(tr, m);
				glPushMatrix();
				glMultMatrixd(m);

				if (!polygon.IsNull())
				{
					glBegin(GL_LINE_STRIP);
					const TColStd_Array1OfInteger& Nodes = polygon->Nodes();
					const TColgp_Array1OfPnt& FNodes = facing->Nodes();
					int nnn = polygon->NbNodes();
					for (int nn = 1; nn <= nnn; nn++)
					{
						gp_Pnt v = FNodes(Nodes(nn));
						glVertex3d(v.X(), v.Y(), v.Z());
					}
					glEnd();
				}

				glPopMatrix();
			}
		}
	}
	else
	{
		bool glwidth_done = false;
		GLfloat save_depth_range[2];
		if(Owner() == NULL || Owner()->Owner() == NULL || Owner()->Owner()->GetType() != WireType)
		{
			BRepTools::Clean(m_topods_edge);
			double pixels_per_mm = wxGetApp().GetPixelScale();
			BRepMesh::Mesh(m_topods_edge, 1/pixels_per_mm);
			if(marked){
				glGetFloatv(GL_DEPTH_RANGE, save_depth_range);
				glDepthRange(0, 0);
				glLineWidth(2);
				glwidth_done = true;
			}
		}

		TopLoc_Location L;
		Handle(Poly_Polygon3D) Polyg = BRep_Tool::Polygon3D(m_topods_edge, L);
		if (!Polyg.IsNull()) {
			const TColgp_Array1OfPnt& Points = Polyg->Nodes();
			Standard_Integer po;
			glBegin(GL_LINE_STRIP);
			for (po = Points.Lower(); po <= Points.Upper(); po++) {
				gp_Pnt p = (Points.Value(po)).Transformed(L);
				glVertex3d(p.X(), p.Y(), p.Z());
			}
			glEnd();
		}

		if(glwidth_done)
		{
			glLineWidth(1);
			glDepthRange(save_depth_range[0], save_depth_range[1]);
		}
	}
}

void CEdge::GetBox(CBox &box){
}

void CEdge::GetGripperPositions(std::list<GripData> *list, bool just_for_endof){
	if(just_for_endof)
	{
		list->push_back(GripData(GripperTypeTranslate,m_start_x,m_start_y,m_start_z,NULL));
		list->push_back(GripData(GripperTypeTranslate,m_end_x,m_end_y,m_end_z,NULL));
	}
	else
	{
		// add a gripper in the middle, just to show the edge is selected
		if(!m_midpoint_calculated)
		{
			BRepAdaptor_Curve curve(m_topods_edge);
			double us = curve.FirstParameter();
			double ue = curve.LastParameter();
			double umiddle = (us+ue)/2;
			Evaluate(umiddle, m_midpoint, NULL);
		}

		list->push_back(GripData(GripperTypeTranslate,m_midpoint[0],m_midpoint[1],m_midpoint[2],NULL));
	}
}

class BlendTool:public Tool
{
public:
	CEdge* m_edge;

	BlendTool(CEdge* edge):m_edge(edge){}

	const wxChar* GetTitle(){return _("Blend");}
	wxString BitmapPath(){return _T("edgeblend");}
	const wxChar* GetToolTip(){return _T("Blend edge");}
	void Run(){
		double rad = 2.0;
		HeeksConfig config;
		config.Read(_T("EdgeBlendRadius"), &rad);
		if(wxGetApp().InputDouble(_("Enter Blend Radius"), _("Radius"), rad))
		{
			m_edge->Blend(rad);
			config.Write(_T("EdgeBlendRadius"), rad);
		}
	}
};

static BlendTool blend_tool(NULL);

void CEdge::GetTools(std::list<Tool*>* t_list, const wxPoint* p){
	if(Owner() && Owner()->Owner() && Owner()->Owner()->GetType() == SolidType)
		blend_tool.m_edge = this;
		t_list->push_back(&blend_tool);
}

void CEdge::Blend(double radius){
	try{
		if(Owner() && Owner()->Owner() && CShape::IsTypeAShape(Owner()->Owner()->GetType())){
			BRepFilletAPI_MakeFillet fillet(((CShape*)(Owner()->Owner()))->Shape());
			fillet.Add(radius, m_topods_edge);
			TopoDS_Shape new_shape = fillet.Shape();
			wxGetApp().StartHistory();
			wxGetApp().AddUndoably(new CSolid(*((TopoDS_Solid*)(&new_shape)), _("Solid with edge blend"), *(Owner()->Owner()->GetColor())), NULL, NULL);
			wxGetApp().DeleteUndoably(Owner()->Owner());
			wxGetApp().EndHistory();
		}
	}
	catch(wxChar *message)
	{
		wxMessageBox(wxString(_("A fatal error happened during Blend")) + _T(" -\n") + wxString(message));
	}
	catch(...)
	{
		wxMessageBox(_("A fatal error happened during Blend"));
	}
}

void CEdge::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyLength(_("length"), Length(), NULL));

	HeeksObj::GetProperties(list);
}

void CEdge::WriteXML(TiXmlNode *root)
{
	CShape::m_solids_found = true;
}

CFace* CEdge::GetFirstFace()
{
	if (m_faces.size()==0) return NULL;
	m_faceIt = m_faces.begin();
	return *m_faceIt;
}

CFace* CEdge::GetNextFace()
{
	if (m_faces.size()==0 || m_faceIt==m_faces.end()) return NULL;
	m_faceIt++;
	if (m_faceIt==m_faces.end()) return NULL;
	return *m_faceIt;
}

int CEdge::GetCurveType()
{
	// enum GeomAbs_CurveType
	// 0 - GeomAbs_Line
	// 1 - GeomAbs_Circle
	// 2 - GeomAbs_Ellipse
	// 3 - GeomAbs_Hyperbola
	// 4 - GeomAbs_Parabola
	// 5 - GeomAbs_BezierCurve
	// 6 - GeomAbs_BSplineCurve
	// 7 - GeomAbs_OtherCurve

	BRepAdaptor_Curve curve(m_topods_edge);
	GeomAbs_CurveType curve_type = curve.GetType();
	return curve_type;
}

void CEdge::GetCurveParams(double* start, double* end, double* uStart, double* uEnd, int* Reversed)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	double us = curve.FirstParameter();
	double ue = curve.LastParameter();
	if(uStart)*uStart = us;
	if(uEnd)*uEnd = ue;
	if(start)extract(curve.Value(us), start);
	if(end)extract(curve.Value(ue), end);
	if(Reversed)*Reversed = Orientation() ? 0:1;
}

void CEdge::GetCurveParams2(double *uStart, double *uEnd, int *isClosed, int *isPeriodic)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	*uStart = curve.FirstParameter();
	*uEnd = curve.LastParameter();
	if(isClosed)*isClosed = curve.IsClosed();
	if(isPeriodic)*isPeriodic = curve.IsPeriodic();
}

bool CEdge::InFaceSense(CFace* face)
{
	std::list<CFace*>::iterator FIt = m_faces.begin();
	std::list<bool>::iterator FSIt = m_face_senses.begin();
	for(;FIt != m_faces.end(); FIt++, FSIt++)
	{
		CFace* f = *FIt;
		bool sense = *FSIt;

		if(f == face)
		{
			bool eo = Orientation();
			return (sense == eo);
		}
	}

	return false; // shouldn't get here
}

void CEdge::Evaluate(double u, double *p, double *tangent)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	gp_Pnt P;
	gp_Vec V;
	curve.D1(u, P, V);
	extract(P, p);
	if(tangent)extract(V, tangent);
}

bool CEdge::GetLineParams(double *d6)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	if(curve.GetType() != GeomAbs_Line)return false;
	gp_Lin line = curve.Line();
	const gp_Pnt& pos = line.Location();
	const gp_Dir& dir = line.Direction();
	d6[0] = pos.X();
	d6[1] = pos.Y();
	d6[2] = pos.Z();
	d6[3] = dir.X();
	d6[4] = dir.Y();
	d6[5] = dir.Z();
	return true;
}

bool CEdge::GetCircleParams(double *d7)
{
	//center.x, center.y, center.z, axis.x, axis.y, axis.z, radius
	BRepAdaptor_Curve curve(m_topods_edge);
	if(curve.GetType() != GeomAbs_Circle)return false;
	gp_Circ c = curve.Circle();
	const gp_Pnt& pos = c.Location();
	const gp_Dir& dir = c.Axis().Direction();
	d7[0] = pos.X();
	d7[1] = pos.Y();
	d7[2] = pos.Z();
	d7[3] = dir.X();
	d7[4] = dir.Y();
	d7[5] = dir.Z();
	d7[6] = c.Radius();
	return true;
}

bool CEdge::Orientation()
{
	TopAbs_Orientation o = m_topods_edge.Orientation();
	return (o == TopAbs_FORWARD);
}

double CEdge::Length()
{
	BRepAdaptor_Curve c(m_topods_edge);
	double len = GCPnts_AbscissaPoint::Length( c );
	return len;
}

double CEdge::Length2(double uStart, double uEnd)
{
	BRepAdaptor_Curve c(m_topods_edge);
	double len = GCPnts_AbscissaPoint::Length( c, uStart, uEnd );
	return len;
}

void CEdge::FindVertices()
{
	CShape* body = GetParentBody();
	if(body)
	{
		int i = 0;
		for (TopExp_Explorer expVertex(m_topods_edge, TopAbs_VERTEX); expVertex.More() && i<2; expVertex.Next(), i++)
		{
			const TopoDS_Shape &V = expVertex.Current();
			for(HeeksObj* object = body->m_vertices->GetFirstChild(); object; object = body->m_vertices->GetNextChild())
			{
				CVertex* v = (CVertex*)object;
				if(v->Vertex().IsSame(V))
				{
					if(i == 0)m_vertex0 = v;
					else m_vertex1 = v;
					break;
				}
			}
		}
	}
}

CVertex* CEdge::GetVertex0()
{
	if(m_vertex0 == NULL)FindVertices();
	return m_vertex0;
}

CVertex* CEdge::GetVertex1()
{
	if(m_vertex1 == NULL)FindVertices();
	return m_vertex1;
}

CShape* CEdge::GetParentBody()
{
	if(Owner() == NULL)return NULL;
	if(Owner()->Owner() == NULL)return NULL;
	if(Owner()->Owner()->GetType() != SolidType)return NULL;
	return (CShape*)(Owner()->Owner());
}

<commit_msg>fixed a compile warning<commit_after>// Edge.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "stdafx.h"
#include "Edge.h"
#include "Face.h"
#include "Vertex.h"
#include "Solid.h"
#include "../interface/Tool.h"
#include "HeeksConfig.h"
#include "Gripper.h"
#include "../interface/PropertyLength.h"

CEdge::CEdge(const TopoDS_Edge &edge):m_topods_edge(edge), m_vertex0(NULL), m_vertex1(NULL), m_midpoint_calculated(false), m_temp_attr(0){
	GetCurveParams2(&m_start_u, &m_end_u, &m_isClosed, &m_isPeriodic);
	Evaluate(m_start_u, &m_start_x, &m_start_tangent_x);
	double t[3];
	Evaluate(m_end_u, &m_end_x, t);
	m_orientation = Orientation();
}

CEdge::~CEdge(){
}

void CEdge::glCommands(bool select, bool marked, bool no_color){
	if(!no_color){
		wxGetApp().glColorEnsuringContrast(HeeksColor(0, 0, 0));
	}

	if(Owner() && Owner()->Owner() && Owner()->Owner()->GetType() == SolidType)
	{
		// triangulate a face on the edge first
		TopTools_IndexedDataMapOfShapeListOfShape lface;
		TopExp::MapShapesAndAncestors(((CShape*)(Owner()->Owner()))->Shape(),TopAbs_EDGE,TopAbs_FACE,lface);
		const TopTools_ListOfShape& lfac = lface.FindFromKey(m_topods_edge);
		Standard_Integer nelem= lfac.Extent();
		if(nelem == 2){
			TopTools_ListIteratorOfListOfShape It;
			It.Initialize(lfac);
			TopoDS_Face Face1 = TopoDS::Face(It.Value());
			TopLoc_Location fL;
			Handle_Poly_Triangulation facing = BRep_Tool::Triangulation(Face1,fL);

			if(!facing.IsNull())
			{
				// Get polygon
				Handle_Poly_PolygonOnTriangulation polygon = BRep_Tool::PolygonOnTriangulation(m_topods_edge, facing, fL);
				gp_Trsf tr = fL;
				double m[16];
				extract_transposed(tr, m);
				glPushMatrix();
				glMultMatrixd(m);

				if (!polygon.IsNull())
				{
					glBegin(GL_LINE_STRIP);
					const TColStd_Array1OfInteger& Nodes = polygon->Nodes();
					const TColgp_Array1OfPnt& FNodes = facing->Nodes();
					int nnn = polygon->NbNodes();
					for (int nn = 1; nn <= nnn; nn++)
					{
						gp_Pnt v = FNodes(Nodes(nn));
						glVertex3d(v.X(), v.Y(), v.Z());
					}
					glEnd();
				}

				glPopMatrix();
			}
		}
	}
	else
	{
		bool glwidth_done = false;
		GLfloat save_depth_range[2];
		if(Owner() == NULL || Owner()->Owner() == NULL || Owner()->Owner()->GetType() != WireType)
		{
			BRepTools::Clean(m_topods_edge);
			double pixels_per_mm = wxGetApp().GetPixelScale();
			BRepMesh::Mesh(m_topods_edge, 1/pixels_per_mm);
			if(marked){
				glGetFloatv(GL_DEPTH_RANGE, save_depth_range);
				glDepthRange(0, 0);
				glLineWidth(2);
				glwidth_done = true;
			}
		}

		TopLoc_Location L;
		Handle(Poly_Polygon3D) Polyg = BRep_Tool::Polygon3D(m_topods_edge, L);
		if (!Polyg.IsNull()) {
			const TColgp_Array1OfPnt& Points = Polyg->Nodes();
			Standard_Integer po;
			glBegin(GL_LINE_STRIP);
			for (po = Points.Lower(); po <= Points.Upper(); po++) {
				gp_Pnt p = (Points.Value(po)).Transformed(L);
				glVertex3d(p.X(), p.Y(), p.Z());
			}
			glEnd();
		}

		if(glwidth_done)
		{
			glLineWidth(1);
			glDepthRange(save_depth_range[0], save_depth_range[1]);
		}
	}
}

void CEdge::GetBox(CBox &box){
}

void CEdge::GetGripperPositions(std::list<GripData> *list, bool just_for_endof){
	if(just_for_endof)
	{
		list->push_back(GripData(GripperTypeTranslate,m_start_x,m_start_y,m_start_z,NULL));
		list->push_back(GripData(GripperTypeTranslate,m_end_x,m_end_y,m_end_z,NULL));
	}
	else
	{
		// add a gripper in the middle, just to show the edge is selected
		if(!m_midpoint_calculated)
		{
			BRepAdaptor_Curve curve(m_topods_edge);
			double us = curve.FirstParameter();
			double ue = curve.LastParameter();
			double umiddle = (us+ue)/2;
			Evaluate(umiddle, m_midpoint, NULL);
		}

		list->push_back(GripData(GripperTypeTranslate,m_midpoint[0],m_midpoint[1],m_midpoint[2],NULL));
	}
}

class BlendTool:public Tool
{
public:
	CEdge* m_edge;

	BlendTool(CEdge* edge):m_edge(edge){}

	const wxChar* GetTitle(){return _("Blend");}
	wxString BitmapPath(){return _T("edgeblend");}
	const wxChar* GetToolTip(){return _T("Blend edge");}
	void Run(){
		double rad = 2.0;
		HeeksConfig config;
		config.Read(_T("EdgeBlendRadius"), &rad);
		if(wxGetApp().InputDouble(_("Enter Blend Radius"), _("Radius"), rad))
		{
			m_edge->Blend(rad);
			config.Write(_T("EdgeBlendRadius"), rad);
		}
	}
};

static BlendTool blend_tool(NULL);

void CEdge::GetTools(std::list<Tool*>* t_list, const wxPoint* p){
	if(Owner() && Owner()->Owner() && Owner()->Owner()->GetType() == SolidType)
		blend_tool.m_edge = this;
		t_list->push_back(&blend_tool);
}

void CEdge::Blend(double radius){
	try{
		if(Owner() && Owner()->Owner() && CShape::IsTypeAShape(Owner()->Owner()->GetType())){
			BRepFilletAPI_MakeFillet fillet(((CShape*)(Owner()->Owner()))->Shape());
			fillet.Add(radius, m_topods_edge);
			TopoDS_Shape new_shape = fillet.Shape();
			wxGetApp().StartHistory();
			wxGetApp().AddUndoably(new CSolid(*((TopoDS_Solid*)(&new_shape)), _("Solid with edge blend"), *(Owner()->Owner()->GetColor())), NULL, NULL);
			wxGetApp().DeleteUndoably(Owner()->Owner());
			wxGetApp().EndHistory();
		}
	}
	catch(wxChar *message)
	{
		wxMessageBox(wxString(_("A fatal error happened during Blend")) + _T(" -\n") + wxString(message));
	}
	catch(...)
	{
		wxMessageBox(_("A fatal error happened during Blend"));
	}
}

void CEdge::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyLength(_("length"), Length(), NULL));

	HeeksObj::GetProperties(list);
}

void CEdge::WriteXML(TiXmlNode *root)
{
	CShape::m_solids_found = true;
}

CFace* CEdge::GetFirstFace()
{
	if (m_faces.size()==0) return NULL;
	m_faceIt = m_faces.begin();
	return *m_faceIt;
}

CFace* CEdge::GetNextFace()
{
	if (m_faces.size()==0 || m_faceIt==m_faces.end()) return NULL;
	m_faceIt++;
	if (m_faceIt==m_faces.end()) return NULL;
	return *m_faceIt;
}

int CEdge::GetCurveType()
{
	// enum GeomAbs_CurveType
	// 0 - GeomAbs_Line
	// 1 - GeomAbs_Circle
	// 2 - GeomAbs_Ellipse
	// 3 - GeomAbs_Hyperbola
	// 4 - GeomAbs_Parabola
	// 5 - GeomAbs_BezierCurve
	// 6 - GeomAbs_BSplineCurve
	// 7 - GeomAbs_OtherCurve

	BRepAdaptor_Curve curve(m_topods_edge);
	GeomAbs_CurveType curve_type = curve.GetType();
	return curve_type;
}

void CEdge::GetCurveParams(double* start, double* end, double* uStart, double* uEnd, int* Reversed)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	double us = curve.FirstParameter();
	double ue = curve.LastParameter();
	if(uStart)*uStart = us;
	if(uEnd)*uEnd = ue;
	if(start)extract(curve.Value(us), start);
	if(end)extract(curve.Value(ue), end);
	if(Reversed)*Reversed = Orientation() ? 0:1;
}

void CEdge::GetCurveParams2(double *uStart, double *uEnd, int *isClosed, int *isPeriodic)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	*uStart = curve.FirstParameter();
	*uEnd = curve.LastParameter();
	if(isClosed)*isClosed = curve.IsClosed();
	if(isPeriodic)*isPeriodic = curve.IsPeriodic();
}

bool CEdge::InFaceSense(CFace* face)
{
	std::list<CFace*>::iterator FIt = m_faces.begin();
	std::list<bool>::iterator FSIt = m_face_senses.begin();
	for(;FIt != m_faces.end(); FIt++, FSIt++)
	{
		CFace* f = *FIt;
		bool sense = *FSIt;

		if(f == face)
		{
			bool eo = Orientation();
			return (sense == eo);
		}
	}

	return false; // shouldn't get here
}

void CEdge::Evaluate(double u, double *p, double *tangent)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	gp_Pnt P;
	gp_Vec V;
	curve.D1(u, P, V);
	extract(P, p);
	if(tangent)extract(V, tangent);
}

bool CEdge::GetLineParams(double *d6)
{
	BRepAdaptor_Curve curve(m_topods_edge);
	if(curve.GetType() != GeomAbs_Line)return false;
	gp_Lin line = curve.Line();
	const gp_Pnt& pos = line.Location();
	const gp_Dir& dir = line.Direction();
	d6[0] = pos.X();
	d6[1] = pos.Y();
	d6[2] = pos.Z();
	d6[3] = dir.X();
	d6[4] = dir.Y();
	d6[5] = dir.Z();
	return true;
}

bool CEdge::GetCircleParams(double *d7)
{
	//center.x, center.y, center.z, axis.x, axis.y, axis.z, radius
	BRepAdaptor_Curve curve(m_topods_edge);
	if(curve.GetType() != GeomAbs_Circle)return false;
	gp_Circ c = curve.Circle();
	const gp_Pnt& pos = c.Location();
	const gp_Dir& dir = c.Axis().Direction();
	d7[0] = pos.X();
	d7[1] = pos.Y();
	d7[2] = pos.Z();
	d7[3] = dir.X();
	d7[4] = dir.Y();
	d7[5] = dir.Z();
	d7[6] = c.Radius();
	return true;
}

bool CEdge::Orientation()
{
	TopAbs_Orientation o = m_topods_edge.Orientation();
	return (o == TopAbs_FORWARD);
}

double CEdge::Length()
{
	BRepAdaptor_Curve c(m_topods_edge);
	double len = GCPnts_AbscissaPoint::Length( c );
	return len;
}

double CEdge::Length2(double uStart, double uEnd)
{
	BRepAdaptor_Curve c(m_topods_edge);
	double len = GCPnts_AbscissaPoint::Length( c, uStart, uEnd );
	return len;
}

void CEdge::FindVertices()
{
	CShape* body = GetParentBody();
	if(body)
	{
		int i = 0;
		for (TopExp_Explorer expVertex(m_topods_edge, TopAbs_VERTEX); expVertex.More() && i<2; expVertex.Next(), i++)
		{
			const TopoDS_Shape &V = expVertex.Current();
			for(HeeksObj* object = body->m_vertices->GetFirstChild(); object; object = body->m_vertices->GetNextChild())
			{
				CVertex* v = (CVertex*)object;
				if(v->Vertex().IsSame(V))
				{
					if(i == 0)m_vertex0 = v;
					else m_vertex1 = v;
					break;
				}
			}
		}
	}
}

CVertex* CEdge::GetVertex0()
{
	if(m_vertex0 == NULL)FindVertices();
	return m_vertex0;
}

CVertex* CEdge::GetVertex1()
{
	if(m_vertex1 == NULL)FindVertices();
	return m_vertex1;
}

CShape* CEdge::GetParentBody()
{
	if(Owner() == NULL)return NULL;
	if(Owner()->Owner() == NULL)return NULL;
	if(Owner()->Owner()->GetType() != SolidType)return NULL;
	return (CShape*)(Owner()->Owner());
}

<|endoftext|>


<commit_before>#include "miniz_extension.hpp"

#if defined(_MSC_VER) || defined(__MINGW64__)
#include "boost/nowide/cstdio.hpp"
#endif

namespace Slic3r {

namespace {
bool open_zip(mz_zip_archive *zip, const char *fname, bool isread)
{
    if (!zip) return false;
    const char *mode = isread ? "rb" : "wb";

    FILE *f = nullptr;
#if defined(_MSC_VER) || defined(__MINGW64__)
    f = boost::nowide::fopen(fname, mode);
#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE)
    f = fopen64(fname, mode);
#else
    f = fopen(fname, mode);
#endif

    if (!f) {
        zip->m_last_error = MZ_ZIP_FILE_OPEN_FAILED;
        return false;
    }

    return isread ? mz_zip_reader_init_cfile(zip, f, 0, 0)
                  : mz_zip_writer_init_cfile(zip, f, 0);
}

bool close_zip(mz_zip_archive *zip, bool isread)
{
    bool ret = false;
    if (zip) {
        FILE *f = mz_zip_get_cfile(zip);
        ret     = bool(isread ? mz_zip_reader_end(zip)
                          : mz_zip_writer_end(zip));
        if (f) fclose(f);
    }
    return ret;
}
}

bool open_zip_reader(mz_zip_archive *zip, const std::string &fname)
{
    return open_zip(zip, fname.c_str(), true);
}

bool open_zip_writer(mz_zip_archive *zip, const std::string &fname)
{
    return open_zip(zip, fname.c_str(), false);
}

bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); }
bool close_zip_writer(mz_zip_archive *zip) { return close_zip(zip, false); }

}
<commit_msg>#3536 - Fixed PrusaSlicer not closing the file when trying to open an invalid 3mf (actually any zip) file<commit_after>#include "miniz_extension.hpp"

#if defined(_MSC_VER) || defined(__MINGW64__)
#include "boost/nowide/cstdio.hpp"
#endif

namespace Slic3r {

namespace {
bool open_zip(mz_zip_archive *zip, const char *fname, bool isread)
{
    if (!zip) return false;
    const char *mode = isread ? "rb" : "wb";

    FILE *f = nullptr;
#if defined(_MSC_VER) || defined(__MINGW64__)
    f = boost::nowide::fopen(fname, mode);
#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE)
    f = fopen64(fname, mode);
#else
    f = fopen(fname, mode);
#endif

    if (!f) {
        zip->m_last_error = MZ_ZIP_FILE_OPEN_FAILED;
        return false;
    }

    bool res = false;
    if (isread)
    {
        res = mz_zip_reader_init_cfile(zip, f, 0, 0);
        if (!res)
            // if we get here it means we tried to open a non-zip file
            // we need to close the file here because the call to mz_zip_get_cfile() made into close_zip() returns a null pointer
            // see: https://github.com/prusa3d/PrusaSlicer/issues/3536
            fclose(f);
    }
    else
        res = mz_zip_writer_init_cfile(zip, f, 0);

    return res;
}

bool close_zip(mz_zip_archive *zip, bool isread)
{
    bool ret = false;
    if (zip) {
        FILE *f = mz_zip_get_cfile(zip);
        ret     = bool(isread ? mz_zip_reader_end(zip)
                          : mz_zip_writer_end(zip));
        if (f) fclose(f);
    }
    return ret;
}
}

bool open_zip_reader(mz_zip_archive *zip, const std::string &fname)
{
    return open_zip(zip, fname.c_str(), true);
}

bool open_zip_writer(mz_zip_archive *zip, const std::string &fname)
{
    return open_zip(zip, fname.c_str(), false);
}

bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); }
bool close_zip_writer(mz_zip_archive *zip) { return close_zip(zip, false); }

}
<|endoftext|>


<commit_before>/*
 * tuya.cpp
 *
 * Implementation of Tuya cluster.
 *
 */

#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Helper to generate a new task with new task and req id based on a reference */
static void copyTaskReq(TaskItem &a, TaskItem &b)
{
    b.req.dstAddress() = a.req.dstAddress();
    b.req.setDstAddressMode(a.req.dstAddressMode());
    b.req.setSrcEndpoint(a.req.srcEndpoint());
    b.req.setDstEndpoint(a.req.dstEndpoint());
    b.req.setRadius(a.req.radius());
    b.req.setTxOptions(a.req.txOptions());
    b.req.setSendDelay(a.req.sendDelay());
    b.zclFrame.payload().clear();
}

/*! Handle packets related to Tuya 0xEF00 cluster.
    \param ind the APS level data indication containing the ZCL packet
    \param zclFrame the actual ZCL frame which holds the scene cluster reponse

    Taken from https://medium.com/@dzegarra/zigbee2mqtt-how-to-add-support-for-a-new-tuya-based-device-part-2-5492707e882d
 */

 // For Triple switch dp  = 257 258 259 (for on)
 // For thermostat dp = 514 (Changed temperature target after mode chnage)

void DeRestPluginPrivate::handleTuyaClusterIndication(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame)
{
    if (zclFrame.isDefaultResponse())
    {
        return;
    }

    bool update = false;

    LightNode *lightNode = getLightNodeForAddress(ind.srcAddress(), ind.srcEndpoint());
    Sensor *sensorNode = getSensorNodeForAddressAndEndpoint(ind.srcAddress(), ind.srcEndpoint());

    if ((!sensorNode) && (!lightNode))
    {
        return;
    }

    DBG_Printf(DBG_INFO, "Tuya : debug 8\n");

    if (zclFrame.commandId() == 0x00)
    {
        // 0x00 : Used to send command, so not used here
    }
    else if ( (zclFrame.commandId() == 0x01) || (zclFrame.commandId() == 0x02) )
    {
        // 0x01 Used to inform of changes in its state.
        // 0x02 Send after receiving a 0x00 command.

        DBG_Printf(DBG_INFO, "Tuya : debug 1 : size %d\n",static_cast<int>(zclFrame.payload().size()));

        if (zclFrame.payload().size() >= 7)
        {

            QDataStream stream(zclFrame.payload());
            stream.setByteOrder(QDataStream::LittleEndian);

            uint8_t status;
            uint8_t transid;
            int16_t dp;
            uint8_t fn;
            quint32 data = 0;
            quint8 dummy;
            quint8 length = 0;

            stream >> status;
            stream >> transid;
            stream >> dp;
            stream >> fn;

            //Convertion octet string to decimal value
            stream >> length;

            //security, it seem 4 is the maximum
            if (length > 4)
            {
                DBG_Printf(DBG_INFO, "Tuya debug : data length excess\n");
                length = 4;
            }

            for (; length > 0; length--)
            {
                stream >> dummy;
                data = data << 8;
                data = data + dummy;
            }

            DBG_Printf(DBG_INFO, "Tuya debug 4: status: %d transid: %d dp: %d fn: %d data %lld\n", status , transid , dp , fn , data);

            // Switch device 3 gang
            switch (dp)
            {
                case 0x0101:
                case 0x0102:
                case 0x0103:
                {
                    bool onoff = false;
                    if (data == 1) { onoff = true; }

                    {
                        uint ep = 0x01;
                        if (dp == 0x0102) { ep = 0x02; }
                        if (dp == 0x0103) { ep = 0x03; }

                        lightNode = getLightNodeForAddress(ind.srcAddress(), ep);

                        if (!lightNode)
                        {
                            return;
                        }

                        ResourceItem *item = lightNode->item(RStateOn);
                        if (item && item->toBool() != onoff)
                        {
                            item->setValue(onoff);
                            Event e(RLights, RStateOn, lightNode->id(), item);
                            enqueueEvent(e);

                            update = true;

                        }

                    }
                }
                break;
                case 0x0203: // Thermostat temperature
                {
                    qint16 temp = ((qint16)(data & 0xFFFF)) * 10;
                    ResourceItem *item = sensorNode->item(RStateTemperature);

                    if (item && item->toNumber() != temp)
                    {
                        item->setValue(temp);
                        Event e(RSensors, RStateTemperature, sensorNode->id(), item);
                        enqueueEvent(e);

                    }
                }
                break;
                case 0x0202: // Thermostat heatsetpoint
                {
                    qint16 temp = ((qint16)(data & 0xFFFF)) * 10;
                    ResourceItem *item = sensorNode->item(RConfigHeatSetpoint);

                    if (item && item->toNumber() != temp)
                    {
                        item->setValue(temp);
                        Event e(RSensors, RConfigHeatSetpoint, sensorNode->id(), item);
                        enqueueEvent(e);

                    }
                }
                break;
                case 0x0215: // battery
                {
                    quint8 bat = (qint8)(data & 0xFF);
                    if (bat > 100) { bat = 100; }
                    ResourceItem *item = sensorNode->item(RConfigBattery);

                    if (item && item->toNumber() != bat)
                    {
                        item->setValue(bat);
                        Event e(RSensors, RConfigBattery, sensorNode->id(), item);
                        enqueueEvent(e);
                    }
                }
                break;
                case 0x0114: // Valve state on / off
                {
                    bool onoff = false;
                    if (data == 1) { onoff = true; }

                    ResourceItem *item = sensorNode->item(RStateOn);

                    if (item && item->toBool() != onoff)
                    {
                        item->setValue(onoff);
                        Event e(RSensors, RStateOn, sensorNode->id(), item);
                        enqueueEvent(e);
                    }
                }
                break;
                case 0x404 : // mode
                {
                    QString mode;
                    if (data == 0) { mode = "off"; }
                    if (data == 1) { mode = "auto"; }
                    if (data == 2) { mode = "manual"; }
                    if (data == 3) { mode = "confort"; }
                    if (data == 4) { mode = "eco"; }
                    if (data == 5) { mode = "boost"; }
                    if (data == 6) { mode = "complex"; }

                    ResourceItem *item = sensorNode->item(RConfigMode);

                    if (item && item->toString() != mode)
                    {
                        item->setValue(mode);
                        Event e(RSensors, RConfigMode, sensorNode->id(), item);
                        enqueueEvent(e);
                    }
                }
                break;
                default:
                break;
            }

        }
        else
        {
            DBG_Printf(DBG_INFO, "Tuya : debug 2");
        }

    }
    else
    {
        return;
    }

    if (update)
    {
        if (lightNode)
        {
            // Update Node light
            updateEtag(lightNode->etag);
            updateEtag(gwConfigEtag);
            lightNode->setNeedSaveDatabase(true);
            saveDatabaseItems |= DB_LIGHTS;
        }
        if (sensorNode)
        {
            // Update Node Sensor
            //updateEtag(sensorNode->etag);
            //updateEtag(gwConfigEtag);
            //sensorNode->setNeedSaveDatabase(true);
            //queSaveDb(DB_SENSORS, DB_SHORT_SAVE_DELAY);
        }
    }

}

// Tuya Devices
//
bool DeRestPluginPrivate::SendTuyaRequest(TaskItem &taskRef, TaskType taskType , qint16 Dp , QByteArray data )
{

    DBG_Printf(DBG_INFO, "Tuya debug 77\n");

    TaskItem task;
    copyTaskReq(taskRef, task);

    //Tuya task
    task.taskType = taskType;

    task.req.setClusterId(TUYA_CLUSTER_ID);
    task.req.setProfileId(HA_PROFILE_ID);

    task.zclFrame.payload().clear();
    task.zclFrame.setSequenceNumber(zclSeq++);
    task.zclFrame.setCommandId(0x00); // Command 0x00
    task.zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
            deCONZ::ZclFCDirectionClientToServer);

    // payload
    QDataStream stream(&task.zclFrame.payload(), QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    //Status always 0x00
    stream << (qint8) 0x00;
    //TransID , use 0
    stream << (qint8) 0x00;
    //Dp
    stream << (qint16) Dp;
    //Fn , always 0
    stream << (qint8) 0x00;
    // Data
    stream << (qint8) data.length(); // len
    for (uint i = 0; i < data.length(); i++)
    {
        stream << (quint8) data[i];
    }

    { // ZCL frame
        task.req.asdu().clear(); // cleanup old request data if there is any
        QDataStream stream(&task.req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        task.zclFrame.writeToStream(stream);
    }

    if (addTask(task))
    {
        taskToLocalData(task);
    }
    else
    {
        return false;
    }

    processTasks();

    return true;
}<commit_msg>Update tuya.cpp<commit_after>/*
 * tuya.cpp
 *
 * Implementation of Tuya cluster.
 *
 */

#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Helper to generate a new task with new task and req id based on a reference */
static void copyTaskReq(TaskItem &a, TaskItem &b)
{
    b.req.dstAddress() = a.req.dstAddress();
    b.req.setDstAddressMode(a.req.dstAddressMode());
    b.req.setSrcEndpoint(a.req.srcEndpoint());
    b.req.setDstEndpoint(a.req.dstEndpoint());
    b.req.setRadius(a.req.radius());
    b.req.setTxOptions(a.req.txOptions());
    b.req.setSendDelay(a.req.sendDelay());
    b.zclFrame.payload().clear();
}

/*! Handle packets related to Tuya 0xEF00 cluster.
    \param ind the APS level data indication containing the ZCL packet
    \param zclFrame the actual ZCL frame which holds the scene cluster reponse

    Taken from https://medium.com/@dzegarra/zigbee2mqtt-how-to-add-support-for-a-new-tuya-based-device-part-2-5492707e882d
 */

 // For Triple switch dp  = 257 258 259 (for on)
 // For thermostat dp = 514 (Changed temperature target after mode chnage)

void DeRestPluginPrivate::handleTuyaClusterIndication(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame)
{
    if (zclFrame.isDefaultResponse())
    {
        return;
    }

    bool update = false;

    LightNode *lightNode = getLightNodeForAddress(ind.srcAddress(), ind.srcEndpoint());
    Sensor *sensorNode = getSensorNodeForAddressAndEndpoint(ind.srcAddress(), ind.srcEndpoint());

    if ((!sensorNode) && (!lightNode))
    {
        return;
    }

    DBG_Printf(DBG_INFO, "Tuya : debug 8\n");

    if (zclFrame.commandId() == 0x00)
    {
        // 0x00 : Used to send command, so not used here
    }
    else if ( (zclFrame.commandId() == 0x01) || (zclFrame.commandId() == 0x02) )
    {
        // 0x01 Used to inform of changes in its state.
        // 0x02 Send after receiving a 0x00 command.

        DBG_Printf(DBG_INFO, "Tuya : debug 1 : size %d\n",static_cast<int>(zclFrame.payload().size()));

        if (zclFrame.payload().size() >= 7)
        {

            QDataStream stream(zclFrame.payload());
            stream.setByteOrder(QDataStream::LittleEndian);

            uint8_t status;
            uint8_t transid;
            int16_t dp;
            uint8_t fn;
            quint32 data = 0;
            quint8 dummy;
            quint8 length = 0;

            stream >> status;
            stream >> transid;
            stream >> dp;
            stream >> fn;

            //Convertion octet string to decimal value
            stream >> length;

            //security, it seem 4 is the maximum
            if (length > 4)
            {
                DBG_Printf(DBG_INFO, "Tuya debug : data length excess\n");
                length = 4;
            }

            for (; length > 0; length--)
            {
                stream >> dummy;
                data = data << 8;
                data = data + dummy;
            }

            DBG_Printf(DBG_INFO, "Tuya debug 4: status: %d transid: %d dp: %d fn: %d data %lld\n", status , transid , dp , fn , data);

            // Switch device 3 gang
            switch (dp)
            {
                case 0x0101:
                case 0x0102:
                case 0x0103:
                {
                    bool onoff = false;
                    if (data == 1) { onoff = true; }

                    {
                        uint ep = 0x01;
                        if (dp == 0x0102) { ep = 0x02; }
                        if (dp == 0x0103) { ep = 0x03; }

                        lightNode = getLightNodeForAddress(ind.srcAddress(), ep);

                        if (!lightNode)
                        {
                            return;
                        }

                        ResourceItem *item = lightNode->item(RStateOn);
                        if (item && item->toBool() != onoff)
                        {
                            item->setValue(onoff);
                            Event e(RLights, RStateOn, lightNode->id(), item);
                            enqueueEvent(e);

                            update = true;

                        }

                    }
                }
                break;
                case 0x0203: // Thermostat temperature
                {
                    qint16 temp = ((qint16)(data & 0xFFFF)) * 10;
                    ResourceItem *item = sensorNode->item(RStateTemperature);

                    if (item && item->toNumber() != temp)
                    {
                        item->setValue(temp);
                        Event e(RSensors, RStateTemperature, sensorNode->id(), item);
                        enqueueEvent(e);

                    }
                }
                break;
                case 0x0202: // Thermostat heatsetpoint
                {
                    qint16 temp = ((qint16)(data & 0xFFFF)) * 10;
                    ResourceItem *item = sensorNode->item(RConfigHeatSetpoint);

                    if (item && item->toNumber() != temp)
                    {
                        item->setValue(temp);
                        Event e(RSensors, RConfigHeatSetpoint, sensorNode->id(), item);
                        enqueueEvent(e);

                    }
                }
                break;
                case 0x0215: // battery
                {
                    quint8 bat = (qint8)(data & 0xFF);
                    if (bat > 100) { bat = 100; }
                    ResourceItem *item = sensorNode->item(RConfigBattery);

                    if (item && item->toNumber() != bat)
                    {
                        item->setValue(bat);
                        Event e(RSensors, RConfigBattery, sensorNode->id(), item);
                        enqueueEvent(e);
                    }
                }
                break;
                case 0x0114: // Valve state on / off
                {
                    bool onoff = false;
                    if (data == 1) { onoff = true; }

                    ResourceItem *item = sensorNode->item(RStateOn);

                    if (item && item->toBool() != onoff)
                    {
                        item->setValue(onoff);
                        Event e(RSensors, RStateOn, sensorNode->id(), item);
                        enqueueEvent(e);
                    }
                }
                break;
                case 0x404 : // mode
                {
                    QString mode;
                    if (data == 0) { mode = "off"; }
                    if (data == 1) { mode = "auto"; }
                    if (data == 2) { mode = "manual"; }
                    if (data == 3) { mode = "confort"; }
                    if (data == 4) { mode = "eco"; }
                    if (data == 5) { mode = "boost"; }
                    if (data == 6) { mode = "complex"; }

                    ResourceItem *item = sensorNode->item(RConfigMode);

                    if (item && item->toString() != mode)
                    {
                        item->setValue(mode);
                        Event e(RSensors, RConfigMode, sensorNode->id(), item);
                        enqueueEvent(e);
                    }
                }
                break;
                default:
                break;
            }

        }
        else
        {
            DBG_Printf(DBG_INFO, "Tuya : debug 2");
        }

    }
    else
    {
        return;
    }

    if (update)
    {
        if (lightNode)
        {
            // Update Node light
            updateEtag(lightNode->etag);
            updateEtag(gwConfigEtag);
            lightNode->setNeedSaveDatabase(true);
            saveDatabaseItems |= DB_LIGHTS;
        }
        if (sensorNode)
        {
            // Update Node Sensor
            //updateEtag(sensorNode->etag);
            //updateEtag(gwConfigEtag);
            //sensorNode->setNeedSaveDatabase(true);
            //queSaveDb(DB_SENSORS, DB_SHORT_SAVE_DELAY);
        }
    }

}

// Tuya Devices
//
bool DeRestPluginPrivate::SendTuyaRequest(TaskItem &taskRef, TaskType taskType , qint16 Dp , QByteArray data )
{

    DBG_Printf(DBG_INFO, "Tuya debug 77\n");

    TaskItem task;
    copyTaskReq(taskRef, task);

    //Tuya task
    task.taskType = taskType;

    task.req.setClusterId(TUYA_CLUSTER_ID);
    task.req.setProfileId(HA_PROFILE_ID);

    task.zclFrame.payload().clear();
    task.zclFrame.setSequenceNumber(zclSeq++);
    task.zclFrame.setCommandId(0x00); // Command 0x00
    task.zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
            deCONZ::ZclFCDirectionClientToServer);

    // payload
    QDataStream stream(&task.zclFrame.payload(), QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    //Status always 0x00
    stream << (qint8) 0x00;
    //TransID , use 0
    stream << (qint8) 0x00;
    //Dp
    stream << (qint16) Dp;
    //Fn , always 0
    stream << (qint8) 0x00;
    // Data
    stream << (qint8) data.length(); // len
    for (int i = 0; i < data.length(); i++)
    {
        stream << (quint8) data[i];
    }

    { // ZCL frame
        task.req.asdu().clear(); // cleanup old request data if there is any
        QDataStream stream(&task.req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        task.zclFrame.writeToStream(stream);
    }

    if (addTask(task))
    {
        taskToLocalData(task);
    }
    else
    {
        return false;
    }

    processTasks();

    return true;
}<|endoftext|>


<commit_before>#include "ffmpeg_video_source.h"
extern "C" {
#include <libavutil/imgutils.h>
}

namespace gg
{

VideoSourceFFmpeg::VideoSourceFFmpeg()
{
    // nop
}

VideoSourceFFmpeg::VideoSourceFFmpeg(std::string source_path,
                                     enum ColourSpace colour_space)
    : IVideoSource(colour_space)
    , src_filename(nullptr)
    , fmt_ctx(nullptr)
    , video_stream_idx(-1)
    , refcount(0)
    , video_stream(nullptr)
    , video_dec_ctx(nullptr)
    , _avframe(nullptr)
    , video_frame_count(0)
{
    int ret = 0;
    std::string error_msg = "";

    src_filename = const_cast<char *>(source_path.c_str());

    av_register_all();

    if (avformat_open_input(&fmt_ctx, src_filename, nullptr, nullptr) < 0)
    {
        error_msg.append("Could not open video source ")
                 .append(source_path);
        throw VideoSourceError(error_msg);
    }

    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0)
        throw VideoSourceError("Could not find stream information");

    if (open_codec_context(&video_stream_idx, fmt_ctx,
                           AVMEDIA_TYPE_VIDEO, error_msg) >= 0)
    {
        video_stream = fmt_ctx->streams[video_stream_idx];
        video_dec_ctx = video_stream->codec;

        /* allocate image where the decoded image will be put */
        width = video_dec_ctx->width;
        height = video_dec_ctx->height;
        pix_fmt = video_dec_ctx->pix_fmt;
        ret = av_image_alloc(video_dst_data, video_dst_linesize,
                             width, height, pix_fmt, 1);
        if (ret < 0)
            throw VideoSourceError("Could not allocate"
                                   " raw video buffer");
        video_dst_bufsize = ret;
    }
    else
        throw VideoSourceError(error_msg);

    // TODO
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (video_stream == nullptr)
        throw VideoSourceError("Could not find video stream in source");

    _avframe = av_frame_alloc();
    if (_avframe == nullptr)
        throw VideoSourceError("Could not allocate frame");

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&pkt);
    pkt.data = nullptr;
    pkt.size = 0;
}

VideoSourceFFmpeg::~VideoSourceFFmpeg()
{
    // TODO: is this part needed?
    int got_frame;
    /* flush cached frames */
    pkt.data = nullptr;
    pkt.size = 0;
    do
        decode_packet(&got_frame, 1);
    while (got_frame);

    avcodec_close(video_dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&_avframe);
    av_free(video_dst_data[0]);
    video_dst_bufsize = 0;
}

bool VideoSourceFFmpeg::get_frame_dimensions(int & width, int & height)
{
    // TODO
    return false;
}

bool VideoSourceFFmpeg::get_frame(VideoFrame & frame)
{
    if (av_read_frame(fmt_ctx, &pkt) < 0)
        return false;

    int ret = 0, got_frame;
    bool success = true;
    AVPacket orig_pkt = pkt;
    size_t passes = 0;
    do
    {
        ret = decode_packet(&got_frame, 0);
        if (ret < 0)
        {
            success = false;
            break;
        }
        pkt.data += ret;
        pkt.size -= ret;

        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(video_dst_data, video_dst_linesize,
                      (const uint8_t **)(_avframe->data), _avframe->linesize,
                      pix_fmt, width, height);

        passes++;
    }
    while (pkt.size > 0);
    av_packet_unref(&orig_pkt);

    if (not success)
        return false;

    // TODO - when are there multiple passes?
    if (passes != 1)
        return false;

    frame.init_from_specs(video_dst_data[0], video_dst_bufsize, width, height);
    return true;
}

double VideoSourceFFmpeg::get_frame_rate()
{
    // TODO
    return 0.0;
}

void VideoSourceFFmpeg::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceFFmpeg::get_full_frame()
{
    // TODO
}

int VideoSourceFFmpeg::open_codec_context(
        int * stream_idx, AVFormatContext * fmt_ctx,
        enum AVMediaType type, std::string & error_msg)
{
    int ret, stream_index;
    AVStream * st;
    AVCodecContext * dec_ctx = nullptr;
    AVCodec * dec = nullptr;
    AVDictionary * opts = nullptr;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, nullptr, 0);
    if (ret < 0)
    {
        error_msg.append("Could not find ")
                 .append(av_get_media_type_string(type))
                 .append(" stream in source ")
                 .append(src_filename);
        return ret;
    }
    else
    {
        stream_index = ret;
        st = fmt_ctx->streams[stream_index];

        /* find decoder for the stream */
        dec_ctx = st->codec;
        dec = avcodec_find_decoder(dec_ctx->codec_id);
        if (!dec)
        {
            error_msg.append("Failed to find ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return AVERROR(EINVAL);
        }

        /* Init the decoders, with or without reference counting */
        av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
        if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0)
        {
            error_msg.append("Failed to open ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return ret;
        }
        *stream_idx = stream_index;
    }

    return 0;
}

int VideoSourceFFmpeg::decode_packet(int * got_frame, int cached)
{
    int ret = 0;
    int decoded = pkt.size;
    *got_frame = 0;
    if (pkt.stream_index == video_stream_idx)
    {
        /* decode video frame */
        ret = avcodec_decode_video2(video_dec_ctx, _avframe, got_frame, &pkt);
        if (ret < 0)
            return ret;

        if (*got_frame)
        {
            if (_avframe->width != width or _avframe->height != height or
                _avframe->format != pix_fmt)
                return -1;
        }
    }
    /* If we use frame reference counting, we own the data and need
     * to de-reference it when we don't use it anymore */
    if (*got_frame and refcount)
        av_frame_unref(_avframe);
    return decoded;
}

}
<commit_msg>Issue #74: implemented get_frame_dimensions of VideoSourceFFmpeg<commit_after>#include "ffmpeg_video_source.h"
extern "C" {
#include <libavutil/imgutils.h>
}

namespace gg
{

VideoSourceFFmpeg::VideoSourceFFmpeg()
{
    // nop
}

VideoSourceFFmpeg::VideoSourceFFmpeg(std::string source_path,
                                     enum ColourSpace colour_space)
    : IVideoSource(colour_space)
    , src_filename(nullptr)
    , fmt_ctx(nullptr)
    , video_stream_idx(-1)
    , refcount(0)
    , video_stream(nullptr)
    , video_dec_ctx(nullptr)
    , _avframe(nullptr)
    , video_frame_count(0)
{
    int ret = 0;
    std::string error_msg = "";

    src_filename = const_cast<char *>(source_path.c_str());

    av_register_all();

    if (avformat_open_input(&fmt_ctx, src_filename, nullptr, nullptr) < 0)
    {
        error_msg.append("Could not open video source ")
                 .append(source_path);
        throw VideoSourceError(error_msg);
    }

    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0)
        throw VideoSourceError("Could not find stream information");

    if (open_codec_context(&video_stream_idx, fmt_ctx,
                           AVMEDIA_TYPE_VIDEO, error_msg) >= 0)
    {
        video_stream = fmt_ctx->streams[video_stream_idx];
        video_dec_ctx = video_stream->codec;

        /* allocate image where the decoded image will be put */
        width = video_dec_ctx->width;
        height = video_dec_ctx->height;
        pix_fmt = video_dec_ctx->pix_fmt;
        ret = av_image_alloc(video_dst_data, video_dst_linesize,
                             width, height, pix_fmt, 1);
        if (ret < 0)
            throw VideoSourceError("Could not allocate"
                                   " raw video buffer");
        video_dst_bufsize = ret;
    }
    else
        throw VideoSourceError(error_msg);

    // TODO
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    if (video_stream == nullptr)
        throw VideoSourceError("Could not find video stream in source");

    _avframe = av_frame_alloc();
    if (_avframe == nullptr)
        throw VideoSourceError("Could not allocate frame");

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&pkt);
    pkt.data = nullptr;
    pkt.size = 0;
}

VideoSourceFFmpeg::~VideoSourceFFmpeg()
{
    // TODO: is this part needed?
    int got_frame;
    /* flush cached frames */
    pkt.data = nullptr;
    pkt.size = 0;
    do
        decode_packet(&got_frame, 1);
    while (got_frame);

    avcodec_close(video_dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&_avframe);
    av_free(video_dst_data[0]);
    video_dst_bufsize = 0;
}

bool VideoSourceFFmpeg::get_frame_dimensions(int & width, int & height)
{
    if (this->width > 0 and this->height > 0)
    {
        width = this->width;
        height = this->height;
        return true;
    }
    else
        return false;
}

bool VideoSourceFFmpeg::get_frame(VideoFrame & frame)
{
    if (av_read_frame(fmt_ctx, &pkt) < 0)
        return false;

    int ret = 0, got_frame;
    bool success = true;
    AVPacket orig_pkt = pkt;
    size_t passes = 0;
    do
    {
        ret = decode_packet(&got_frame, 0);
        if (ret < 0)
        {
            success = false;
            break;
        }
        pkt.data += ret;
        pkt.size -= ret;

        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(video_dst_data, video_dst_linesize,
                      (const uint8_t **)(_avframe->data), _avframe->linesize,
                      pix_fmt, width, height);

        passes++;
    }
    while (pkt.size > 0);
    av_packet_unref(&orig_pkt);

    if (not success)
        return false;

    // TODO - when are there multiple passes?
    if (passes != 1)
        return false;

    frame.init_from_specs(video_dst_data[0], video_dst_bufsize, width, height);
    return true;
}

double VideoSourceFFmpeg::get_frame_rate()
{
    // TODO
    return 0.0;
}

void VideoSourceFFmpeg::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceFFmpeg::get_full_frame()
{
    // TODO
}

int VideoSourceFFmpeg::open_codec_context(
        int * stream_idx, AVFormatContext * fmt_ctx,
        enum AVMediaType type, std::string & error_msg)
{
    int ret, stream_index;
    AVStream * st;
    AVCodecContext * dec_ctx = nullptr;
    AVCodec * dec = nullptr;
    AVDictionary * opts = nullptr;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, nullptr, 0);
    if (ret < 0)
    {
        error_msg.append("Could not find ")
                 .append(av_get_media_type_string(type))
                 .append(" stream in source ")
                 .append(src_filename);
        return ret;
    }
    else
    {
        stream_index = ret;
        st = fmt_ctx->streams[stream_index];

        /* find decoder for the stream */
        dec_ctx = st->codec;
        dec = avcodec_find_decoder(dec_ctx->codec_id);
        if (!dec)
        {
            error_msg.append("Failed to find ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return AVERROR(EINVAL);
        }

        /* Init the decoders, with or without reference counting */
        av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
        if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0)
        {
            error_msg.append("Failed to open ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return ret;
        }
        *stream_idx = stream_index;
    }

    return 0;
}

int VideoSourceFFmpeg::decode_packet(int * got_frame, int cached)
{
    int ret = 0;
    int decoded = pkt.size;
    *got_frame = 0;
    if (pkt.stream_index == video_stream_idx)
    {
        /* decode video frame */
        ret = avcodec_decode_video2(video_dec_ctx, _avframe, got_frame, &pkt);
        if (ret < 0)
            return ret;

        if (*got_frame)
        {
            if (_avframe->width != width or _avframe->height != height or
                _avframe->format != pix_fmt)
                return -1;
        }
    }
    /* If we use frame reference counting, we own the data and need
     * to de-reference it when we don't use it anymore */
    if (*got_frame and refcount)
        av_frame_unref(_avframe);
    return decoded;
}

}
<|endoftext|>


<commit_before>#if defined(HAVE_OPENCL)

#include "GpuNode.h"
#include "Logic/NodeFactory.h"

#include "Logic/Nodes/CV.h"

class GpuBayerToGrayNodeType : public GpuNodeType
{
public:
	GpuBayerToGrayNodeType()
		: _redGain(1.0)
		, _greenGain(1.0)
		, _blueGain(1.0)
		, _BayerCode(cvu::EBayerCode::RG)
	{
	}

	bool setProperty(PropertyID propId, const NodeProperty& newValue) override
	{
		switch(static_cast<pid>(propId))
		{
		case pid::BayerFormat:
			_BayerCode = newValue.toEnum().cast<cvu::EBayerCode>();
			return true;
		case pid::RedGain:
			_redGain = newValue.toDouble();
			return true;
		case pid::GreenGain:
			_greenGain = newValue.toDouble();
			return true;
		case pid::BlueGain:
			_blueGain = newValue.toDouble();
			return true;
		}

		return false;
	}

	NodeProperty property(PropertyID propId) const override
	{
		switch(static_cast<pid>(propId))
		{
		case pid::BayerFormat: return _BayerCode;
		case pid::RedGain: return _redGain;
		case pid::GreenGain: return _greenGain;
		case pid::BlueGain: return _blueGain;
		}

		return NodeProperty();
	}

	bool postInit() override
	{
		// On AMD up from AMD APP 2.7 which supports 1.2 OpenCL we can use templates and other c++ goodies
		string opts;
		if(_gpuComputeModule->device().platform().vendorEnum() == clw::EPlatformVendor::AMD
			&& _gpuComputeModule->device().platform().version() >= clw::EPlatformVersion::v1_2)
		{
			opts = "-DTEMPLATES_SUPPORTED -x clc++";
		}

		// Local version is a bit faster
		_kidConvertRG2Gray = _gpuComputeModule->registerKernel("convert_rg2gray_local", "bayer.cl", opts);
		_kidConvertGB2Gray = _gpuComputeModule->registerKernel("convert_gb2gray_local", "bayer.cl", opts);
		_kidConvertGR2Gray = _gpuComputeModule->registerKernel("convert_gr2gray_local", "bayer.cl", opts);
		_kidConvertBG2Gray = _gpuComputeModule->registerKernel("convert_bg2gray_local", "bayer.cl", opts);

		return _kidConvertRG2Gray != InvalidKernelID
			&& _kidConvertGB2Gray != InvalidKernelID
			&& _kidConvertGR2Gray != InvalidKernelID
			&& _kidConvertBG2Gray != InvalidKernelID;
	}

	ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
	{
		const clw::Image2D& input = reader.readSocket(0).getDeviceImageMono();
		clw::Image2D& output = writer.acquireSocket(0).getDeviceImageMono();

		int imageWidth = input.width();
		int imageHeight = input.height();

		if(imageWidth == 0 || imageHeight == 0)
			return ExecutionStatus(EStatus::Ok);

		clw::Kernel kernelConvertBayer2Gray;
		switch(_BayerCode)
		{
		case cvu::EBayerCode::RG:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertRG2Gray);
			break;
		case cvu::EBayerCode::GB:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertGB2Gray);
			break;
		case cvu::EBayerCode::GR:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertGR2Gray);
			break;
		case cvu::EBayerCode::BG:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertBG2Gray);
			break;
		}

		if(kernelConvertBayer2Gray.isNull())
			return ExecutionStatus(EStatus::Error, "Bad bayer code");

		// Ensure output image size is enough
		if(output.isNull() || output.width() != imageWidth || output.height() != imageHeight)
		{
			output = _gpuComputeModule->context().createImage2D(
				clw::EAccess::ReadWrite, clw::EMemoryLocation::Device,
				clw::ImageFormat(clw::EChannelOrder::R, clw::EChannelType::Normalized_UInt8),
				imageWidth, imageHeight);
		}

		cl_float3 gains = { (float) _redGain, (float) _greenGain, (float) _blueGain };
		int sharedWidth = 16 + 2;
		int sharedHeight = 16 + 2;

		kernelConvertBayer2Gray.setLocalWorkSize(16, 16);
		kernelConvertBayer2Gray.setRoundedGlobalWorkSize(imageWidth, imageHeight);
		kernelConvertBayer2Gray.setArg(0, input);
		kernelConvertBayer2Gray.setArg(1, output);
		kernelConvertBayer2Gray.setArg(2, gains);
		kernelConvertBayer2Gray.setArg(3, clw::LocalMemorySize(sharedWidth*sharedHeight*sizeof(float)));
		kernelConvertBayer2Gray.setArg(4, sharedWidth);
		kernelConvertBayer2Gray.setArg(5, sharedHeight);

		_gpuComputeModule->queue().asyncRunKernel(kernelConvertBayer2Gray);
		_gpuComputeModule->queue().finish();

		return ExecutionStatus(EStatus::Ok);
	}

	void configuration(NodeConfig& nodeConfig) const override
	{
		static const InputSocketConfig in_config[] = {
			{ ENodeFlowDataType::DeviceImageMono, "input", "Input", "" },
			{ ENodeFlowDataType::Invalid, "", "", "" }
		};
		static const OutputSocketConfig out_config[] = {
			{ ENodeFlowDataType::DeviceImageMono, "output", "Output", "" },
			{ ENodeFlowDataType::Invalid, "", "", "" }
		};
		static const PropertyConfig prop_config[] = {
			{ EPropertyType::Enum, "Bayer format", "item: BG, item: GB, item: RG, item: GR" },
			{ EPropertyType::Double, "Red gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Double, "Green gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Double, "Blue gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Unknown, "", "" }
		};

		nodeConfig.description = "Performs demosaicing from Bayer pattern image to RGB image";
		nodeConfig.pInputSockets = in_config;
		nodeConfig.pOutputSockets = out_config;
		nodeConfig.pProperties = prop_config;
		nodeConfig.module = "opencl";
	}

private:
	enum class pid
	{
		BayerFormat,
		RedGain,
		GreenGain,
		BlueGain,
	};

	double _redGain;
	double _greenGain;
	double _blueGain;
	cvu::EBayerCode _BayerCode;

private:
	KernelID _kidConvertRG2Gray;
	KernelID _kidConvertGB2Gray;
	KernelID _kidConvertGR2Gray;
	KernelID _kidConvertBG2Gray;
};

REGISTER_NODE("OpenCL/Format conversion/Gray de-bayer", GpuBayerToGrayNodeType)

#endif
<commit_msg>added OpenCL based RGB de-Bayer filter<commit_after>#if defined(HAVE_OPENCL)

#include "GpuNode.h"
#include "Logic/NodeFactory.h"

#include "Logic/Nodes/CV.h"

class GpuBayerToGrayNodeType : public GpuNodeType
{
public:
	GpuBayerToGrayNodeType()
		: _redGain(1.0)
		, _greenGain(1.0)
		, _blueGain(1.0)
		, _BayerCode(cvu::EBayerCode::RG)
	{
	}

	bool setProperty(PropertyID propId, const NodeProperty& newValue) override
	{
		switch(static_cast<pid>(propId))
		{
		case pid::BayerFormat:
			_BayerCode = newValue.toEnum().cast<cvu::EBayerCode>();
			return true;
		case pid::RedGain:
			_redGain = newValue.toDouble();
			return true;
		case pid::GreenGain:
			_greenGain = newValue.toDouble();
			return true;
		case pid::BlueGain:
			_blueGain = newValue.toDouble();
			return true;
		}

		return false;
	}

	NodeProperty property(PropertyID propId) const override
	{
		switch(static_cast<pid>(propId))
		{
		case pid::BayerFormat: return _BayerCode;
		case pid::RedGain: return _redGain;
		case pid::GreenGain: return _greenGain;
		case pid::BlueGain: return _blueGain;
		}

		return NodeProperty();
	}

	bool postInit() override
	{
		// On AMD up from AMD APP 2.7 which supports 1.2 OpenCL we can use templates and other c++ goodies
		string opts;
		if(_gpuComputeModule->device().platform().vendorEnum() == clw::EPlatformVendor::AMD
			&& _gpuComputeModule->device().platform().version() >= clw::EPlatformVersion::v1_2)
		{
			opts = "-DTEMPLATES_SUPPORTED -x clc++";
		}

		// Local version is a bit faster
		_kidConvertRG2Gray = _gpuComputeModule->registerKernel("convert_rg2gray_local", "bayer.cl", opts);
		_kidConvertGB2Gray = _gpuComputeModule->registerKernel("convert_gb2gray_local", "bayer.cl", opts);
		_kidConvertGR2Gray = _gpuComputeModule->registerKernel("convert_gr2gray_local", "bayer.cl", opts);
		_kidConvertBG2Gray = _gpuComputeModule->registerKernel("convert_bg2gray_local", "bayer.cl", opts);

		return _kidConvertRG2Gray != InvalidKernelID
			&& _kidConvertGB2Gray != InvalidKernelID
			&& _kidConvertGR2Gray != InvalidKernelID
			&& _kidConvertBG2Gray != InvalidKernelID;
	}

	ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
	{
		const clw::Image2D& input = reader.readSocket(0).getDeviceImageMono();
		clw::Image2D& output = writer.acquireSocket(0).getDeviceImageMono();

		int imageWidth = input.width();
		int imageHeight = input.height();

		if(imageWidth == 0 || imageHeight == 0)
			return ExecutionStatus(EStatus::Ok);

		clw::Kernel kernelConvertBayer2Gray;
		switch(_BayerCode)
		{
		case cvu::EBayerCode::RG:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertRG2Gray);
			break;
		case cvu::EBayerCode::GB:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertGB2Gray);
			break;
		case cvu::EBayerCode::GR:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertGR2Gray);
			break;
		case cvu::EBayerCode::BG:
			kernelConvertBayer2Gray = _gpuComputeModule->acquireKernel(_kidConvertBG2Gray);
			break;
		}

		if(kernelConvertBayer2Gray.isNull())
			return ExecutionStatus(EStatus::Error, "Bad bayer code");

		// Ensure output image size is enough
		if(output.isNull() || output.width() != imageWidth || output.height() != imageHeight)
		{
			output = _gpuComputeModule->context().createImage2D(
				clw::EAccess::ReadWrite, clw::EMemoryLocation::Device,
				clw::ImageFormat(clw::EChannelOrder::R, clw::EChannelType::Normalized_UInt8),
				imageWidth, imageHeight);
		}

		cl_float3 gains = { (float) _redGain, (float) _greenGain, (float) _blueGain };
		int sharedWidth = 16 + 2;
		int sharedHeight = 16 + 2;

		kernelConvertBayer2Gray.setLocalWorkSize(16, 16);
		kernelConvertBayer2Gray.setRoundedGlobalWorkSize(imageWidth, imageHeight);
		kernelConvertBayer2Gray.setArg(0, input);
		kernelConvertBayer2Gray.setArg(1, output);
		kernelConvertBayer2Gray.setArg(2, gains);
		kernelConvertBayer2Gray.setArg(3, clw::LocalMemorySize(sharedWidth*sharedHeight*sizeof(float)));
		kernelConvertBayer2Gray.setArg(4, sharedWidth);
		kernelConvertBayer2Gray.setArg(5, sharedHeight);

		_gpuComputeModule->queue().asyncRunKernel(kernelConvertBayer2Gray);
		_gpuComputeModule->queue().finish();

		return ExecutionStatus(EStatus::Ok);
	}

	void configuration(NodeConfig& nodeConfig) const override
	{
		static const InputSocketConfig in_config[] = {
			{ ENodeFlowDataType::DeviceImageMono, "input", "Input", "" },
			{ ENodeFlowDataType::Invalid, "", "", "" }
		};
		static const OutputSocketConfig out_config[] = {
			{ ENodeFlowDataType::DeviceImageMono, "output", "Output", "" },
			{ ENodeFlowDataType::Invalid, "", "", "" }
		};
		static const PropertyConfig prop_config[] = {
			{ EPropertyType::Enum, "Bayer format", "item: BG, item: GB, item: RG, item: GR" },
			{ EPropertyType::Double, "Red gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Double, "Green gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Double, "Blue gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Unknown, "", "" }
		};

		nodeConfig.description = "Performs demosaicing from Bayer pattern image to RGB image";
		nodeConfig.pInputSockets = in_config;
		nodeConfig.pOutputSockets = out_config;
		nodeConfig.pProperties = prop_config;
		nodeConfig.module = "opencl";
	}

private:
	enum class pid
	{
		BayerFormat,
		RedGain,
		GreenGain,
		BlueGain,
	};

	double _redGain;
	double _greenGain;
	double _blueGain;
	cvu::EBayerCode _BayerCode;

private:
	KernelID _kidConvertRG2Gray;
	KernelID _kidConvertGB2Gray;
	KernelID _kidConvertGR2Gray;
	KernelID _kidConvertBG2Gray;
};

class GpuBayerToRgbNodeType : public GpuNodeType
{
public:
	GpuBayerToRgbNodeType()
		: _redGain(1.0)
		, _greenGain(1.0)
		, _blueGain(1.0)
		, _BayerCode(cvu::EBayerCode::RG)
	{
	}

	bool setProperty(PropertyID propId, const NodeProperty& newValue) override
	{
		switch(static_cast<pid>(propId))
		{
		case pid::BayerFormat:
			_BayerCode = newValue.toEnum().cast<cvu::EBayerCode>();
			return true;
		case pid::RedGain:
			_redGain = newValue.toDouble();
			return true;
		case pid::GreenGain:
			_greenGain = newValue.toDouble();
			return true;
		case pid::BlueGain:
			_blueGain = newValue.toDouble();
			return true;
		}

		return false;
	}

	NodeProperty property(PropertyID propId) const override
	{
		switch(static_cast<pid>(propId))
		{
		case pid::BayerFormat: return _BayerCode;
		case pid::RedGain: return _redGain;
		case pid::GreenGain: return _greenGain;
		case pid::BlueGain: return _blueGain;
		}

		return NodeProperty();
	}

	bool postInit() override
	{
		// On AMD up from AMD APP 2.7 which supports 1.2 OpenCL we can use templates and other c++ goodies
		string opts;
		if(_gpuComputeModule->device().platform().vendorEnum() == clw::EPlatformVendor::AMD
			&& _gpuComputeModule->device().platform().version() >= clw::EPlatformVersion::v1_2)
		{
			opts = "-DTEMPLATES_SUPPORTED -x clc++";
		}

		// Local version is a bit faster
		_kidConvertRG2Rgb = _gpuComputeModule->registerKernel("convert_rg2rgb_local", "bayer.cl", opts);
		_kidConvertGB2Rgb = _gpuComputeModule->registerKernel("convert_gb2rgb_local", "bayer.cl", opts);
		_kidConvertGR2Rgb = _gpuComputeModule->registerKernel("convert_gr2rgb_local", "bayer.cl", opts);
		_kidConvertBG2Rgb = _gpuComputeModule->registerKernel("convert_bg2rgb_local", "bayer.cl", opts);

		return _kidConvertRG2Rgb != InvalidKernelID
			&& _kidConvertGB2Rgb != InvalidKernelID
			&& _kidConvertGR2Rgb != InvalidKernelID
			&& _kidConvertBG2Rgb != InvalidKernelID;
	}

	ExecutionStatus execute(NodeSocketReader& reader, NodeSocketWriter& writer) override
	{
		const clw::Image2D& input = reader.readSocket(0).getDeviceImageMono();
		clw::Image2D& output = writer.acquireSocket(0).getDeviceImageRgb();

		int imageWidth = input.width();
		int imageHeight = input.height();

		if(imageWidth == 0 || imageHeight == 0)
			return ExecutionStatus(EStatus::Ok);

		clw::Kernel kernelConvertBayer2Rgb;
		switch(_BayerCode)
		{
		case cvu::EBayerCode::RG:
			kernelConvertBayer2Rgb = _gpuComputeModule->acquireKernel(_kidConvertRG2Rgb);
			break;
		case cvu::EBayerCode::GB:
			kernelConvertBayer2Rgb = _gpuComputeModule->acquireKernel(_kidConvertGB2Rgb);
			break;
		case cvu::EBayerCode::GR:
			kernelConvertBayer2Rgb = _gpuComputeModule->acquireKernel(_kidConvertGR2Rgb);
			break;
		case cvu::EBayerCode::BG:
			kernelConvertBayer2Rgb = _gpuComputeModule->acquireKernel(_kidConvertBG2Rgb);
			break;
		}

		if(kernelConvertBayer2Rgb.isNull())
			return ExecutionStatus(EStatus::Error, "Bad bayer code");

		// Ensure output image size is enough
		if(output.isNull() || output.width() != imageWidth || output.height() != imageHeight)
		{
			output = _gpuComputeModule->context().createImage2D(
				clw::EAccess::ReadWrite, clw::EMemoryLocation::Device,
				clw::ImageFormat(clw::EChannelOrder::RGBA, clw::EChannelType::Normalized_UInt8),
				imageWidth, imageHeight);
		}

		cl_float3 gains = { (float) _redGain, (float) _greenGain, (float) _blueGain };
		int sharedWidth = 16 + 2;
		int sharedHeight = 16 + 2;

		kernelConvertBayer2Rgb.setLocalWorkSize(16, 16);
		kernelConvertBayer2Rgb.setRoundedGlobalWorkSize(imageWidth, imageHeight);
		kernelConvertBayer2Rgb.setArg(0, input);
		kernelConvertBayer2Rgb.setArg(1, output);
		kernelConvertBayer2Rgb.setArg(2, gains);
		kernelConvertBayer2Rgb.setArg(3, clw::LocalMemorySize(sharedWidth*sharedHeight*sizeof(float)));
		kernelConvertBayer2Rgb.setArg(4, sharedWidth);
		kernelConvertBayer2Rgb.setArg(5, sharedHeight);

		_gpuComputeModule->queue().asyncRunKernel(kernelConvertBayer2Rgb);
		_gpuComputeModule->queue().finish();

		return ExecutionStatus(EStatus::Ok);
	}

	void configuration(NodeConfig& nodeConfig) const override
	{
		static const InputSocketConfig in_config[] = {
			{ ENodeFlowDataType::DeviceImageMono, "input", "Input", "" },
			{ ENodeFlowDataType::Invalid, "", "", "" }
		};
		static const OutputSocketConfig out_config[] = {
			{ ENodeFlowDataType::DeviceImageRgb, "output", "Output", "" },
			{ ENodeFlowDataType::Invalid, "", "", "" }
		};
		static const PropertyConfig prop_config[] = {
			{ EPropertyType::Enum, "Bayer format", "item: BG, item: GB, item: RG, item: GR" },
			{ EPropertyType::Double, "Red gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Double, "Green gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Double, "Blue gain", "min:0.0, max:4.0, step:0.01" },
			{ EPropertyType::Unknown, "", "" }
		};

		nodeConfig.description = "Performs demosaicing from Bayer pattern image to RGB image";
		nodeConfig.pInputSockets = in_config;
		nodeConfig.pOutputSockets = out_config;
		nodeConfig.pProperties = prop_config;
		nodeConfig.module = "opencl";
	}

private:
	enum class pid
	{
		BayerFormat,
		RedGain,
		GreenGain,
		BlueGain,
	};

	double _redGain;
	double _greenGain;
	double _blueGain;
	cvu::EBayerCode _BayerCode;

private:
	KernelID _kidConvertRG2Rgb;
	KernelID _kidConvertGB2Rgb;
	KernelID _kidConvertGR2Rgb;
	KernelID _kidConvertBG2Rgb;
};

REGISTER_NODE("OpenCL/Format conversion/Gray de-bayer", GpuBayerToGrayNodeType)
REGISTER_NODE("OpenCL/Format conversion/RGB de-bayer", GpuBayerToRgbNodeType)

#endif
<|endoftext|>


<commit_before>// ================================================================================
// == This file is a part of TinkerBell UI Toolkit. (C) 2011-2013, Emil Segerås  ==
// ==                   See tinkerbell.h for more information.                   ==
// ================================================================================

#include "tb_window.h"
#include <assert.h>

namespace tinkerbell {

// == TBWindow ==========================================================================

TBWindow::TBWindow()
	: m_settings(WINDOW_SETTINGS_DEFAULT)
{
	SetSkinBg("TBWindow", WIDGET_INVOKE_INFO_NO_CALLBACKS);
	AddChild(&m_mover);
	AddChild(&m_resizer);
	m_mover.SetSkinBg("TBWindow.mover");
	m_mover.AddChild(&m_textfield);
	m_textfield.SetIgnoreInput(true);
	m_mover.AddChild(&m_close_button);
	m_close_button.SetSkinBg("TBWindow.close");
	m_close_button.SetIsFocusable(false);
	m_close_button.GetID().Set("TBWindow.close");
	SetIsGroupRoot(true);
}

TBWindow::~TBWindow()
{
	if (m_resizer.GetParent())		RemoveChild(&m_resizer);
	if (m_mover.GetParent())		RemoveChild(&m_mover);
	if (m_close_button.GetParent())	m_mover.RemoveChild(&m_close_button);
	m_mover.RemoveChild(&m_textfield);
}

void TBWindow::ResizeToFitContent(RESIZE_FIT fit)
{
	PreferredSize ps = GetPreferredSize();
	int new_w = ps.pref_w;
	int new_h = ps.pref_h;
	if (fit == RESIZE_FIT_MINIMAL)
	{
		new_w = ps.min_w;
		new_h = ps.min_h;
	}
	else if (fit == RESIZE_FIT_CURRENT_OR_NEEDED)
	{
		new_w = CLAMP(GetRect().w, ps.min_w, ps.max_w);
		new_h = CLAMP(GetRect().h, ps.min_h, ps.max_h);
	}
	if (GetParent())
	{
		new_w = MIN(new_w, GetParent()->GetRect().w);
		new_h = MIN(new_h, GetParent()->GetRect().h);
	}
	SetRect(TBRect(GetRect().x, GetRect().y, new_w, new_h));
}

void TBWindow::Close()
{
	Die();
}

bool TBWindow::IsActive()
{
	return GetState(WIDGET_STATE_SELECTED);
}

TBWindow *TBWindow::GetTopMostOtherWindow(bool only_activable_windows)
{
	TBWindow *other_window = nullptr;
	TBWidget *sibling = GetParent()->GetLastChild();
	while (sibling && !other_window)
	{
		if (sibling != this)
			other_window = TBSafeCast<TBWindow>(sibling);

		if (only_activable_windows && other_window && !(other_window->m_settings & WINDOW_SETTINGS_CAN_ACTIVATE))
			other_window = nullptr;

		sibling = sibling->GetPrev();
	}
	return other_window;
}

void TBWindow::Activate()
{
	if (!GetParent() || !(m_settings & WINDOW_SETTINGS_CAN_ACTIVATE))
		return;
	if (IsActive())
	{
		// Already active, but we may still have lost focus,
		// so ensure it comes back to us.
		EnsureFocus();
		return;
	}

	// Deactivate currently active window
	TBWindow *active_window = GetTopMostOtherWindow(true);
	if (active_window)
		active_window->DeActivate();

	// Activate this window

	SetZ(WIDGET_Z_TOP);
	SetWindowActiveState(true);
	EnsureFocus();
}

bool TBWindow::EnsureFocus()
{
	// If we already have focus, we're done.
	if (focused_widget && IsAncestorOf(focused_widget))
		return true;

	// Focus last focused widget (if we have one)
	bool success = false;
	if (m_last_focus.Get())
		success = m_last_focus.Get()->SetFocus(WIDGET_FOCUS_REASON_UNKNOWN);
	// We didn't have one or failed, so try focus any child.
	if (!success)
		success = SetFocusRecursive(WIDGET_FOCUS_REASON_UNKNOWN);
	return success;
}

void TBWindow::DeActivate()
{
	if (!IsActive())
		return;
	SetWindowActiveState(false);
}

void TBWindow::SetWindowActiveState(bool active)
{
	SetState(WIDGET_STATE_SELECTED, active);
	m_mover.SetState(WIDGET_STATE_SELECTED, active);
}

void TBWindow::SetSettings(WINDOW_SETTINGS settings)
{
	if (settings == m_settings)
		return;
	m_settings = settings;

	if (settings & WINDOW_SETTINGS_TITLEBAR)
	{
		if (!m_mover.GetParent())
			AddChild(&m_mover);
	}
	else if (!(settings & WINDOW_SETTINGS_TITLEBAR))
	{
		if (m_mover.GetParent())
			RemoveChild(&m_mover);
	}
	if (settings & WINDOW_SETTINGS_RESIZABLE)
	{
		if (!m_resizer.GetParent())
			AddChild(&m_resizer);
	}
	else if (!(settings & WINDOW_SETTINGS_RESIZABLE))
	{
		if (m_resizer.GetParent())
			RemoveChild(&m_resizer);
	}
	if (settings & WINDOW_SETTINGS_CLOSE_BUTTON)
	{
		if (!m_close_button.GetParent())
			AddChild(&m_close_button);
	}
	else if (!(settings & WINDOW_SETTINGS_CLOSE_BUTTON))
	{
		if (m_close_button.GetParent())
			RemoveChild(&m_close_button);
	}

	// FIX: invalidate layout / resize window!
	Invalidate();
}

int TBWindow::GetTitleHeight()
{
	if (m_settings & WINDOW_SETTINGS_TITLEBAR)
		return m_mover.GetPreferredSize().pref_h;
	return 0;
}

TBRect TBWindow::GetPaddingRect()
{
	TBRect padding_rect = TBWidget::GetPaddingRect();
	int title_height = GetTitleHeight();
	padding_rect.y += title_height;
	padding_rect.h -= title_height;
	return padding_rect;
}

PreferredSize TBWindow::OnCalculatePreferredSize()
{
	PreferredSize ps = OnCalculatePreferredContentSize();

	// Add window skin padding
	if (TBSkinElement *e = GetSkinBgElement())
	{
		ps.min_w += e->padding_left + e->padding_right;
		ps.pref_w += e->padding_left + e->padding_right;
		ps.min_h += e->padding_top + e->padding_bottom;
		ps.pref_h += e->padding_top + e->padding_bottom;
	}
	// Add window title bar height
	int title_height = GetTitleHeight();
	ps.min_h += title_height;
	ps.pref_h += title_height;
	return ps;
}

bool TBWindow::OnEvent(const TBWidgetEvent &ev)
{
	if (ev.target == &m_close_button)
	{
		if (ev.type == EVENT_TYPE_CLICK)
			Close();
		return true;
	}
	return false;
}

void TBWindow::OnAdded()
{
	// If we was added last, call Activate to update status etc.
	if (GetParent()->GetLastChild() == this)
		Activate();
}

void TBWindow::OnRemove()
{
	DeActivate();

	// Active the top most other window
	if (TBWindow *active_window = GetTopMostOtherWindow(true))
		active_window->Activate();
}

void TBWindow::OnChildAdded(TBWidget *child)
{
	m_resizer.SetZ(WIDGET_Z_TOP);
}

void TBWindow::OnResized(int old_w, int old_h)
{
	// Apply gravity on children
	TBWidget::OnResized(old_w, old_h);
	// Manually move our own decoration children
	// FIX: Put a layout in the TBMover so we can add things there nicely.
	int title_height = GetTitleHeight();
	m_mover.SetRect(TBRect(0, 0, GetRect().w, title_height));
	PreferredSize ps = m_resizer.GetPreferredSize();
	m_resizer.SetRect(TBRect(GetRect().w - ps.pref_w, GetRect().h - ps.pref_h, ps.pref_w, ps.pref_h));
	TBRect mover_rect = m_mover.GetPaddingRect();
	int button_size = mover_rect.h;
	m_close_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
	if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
		mover_rect.w -= button_size;
	m_textfield.SetRect(mover_rect);
}

}; // namespace tinkerbell
<commit_msg>Fixed bug in changing window settings.<commit_after>// ================================================================================
// == This file is a part of TinkerBell UI Toolkit. (C) 2011-2013, Emil Segerås  ==
// ==                   See tinkerbell.h for more information.                   ==
// ================================================================================

#include "tb_window.h"
#include <assert.h>

namespace tinkerbell {

// == TBWindow ==========================================================================

TBWindow::TBWindow()
	: m_settings(WINDOW_SETTINGS_DEFAULT)
{
	SetSkinBg("TBWindow", WIDGET_INVOKE_INFO_NO_CALLBACKS);
	AddChild(&m_mover);
	AddChild(&m_resizer);
	m_mover.SetSkinBg("TBWindow.mover");
	m_mover.AddChild(&m_textfield);
	m_textfield.SetIgnoreInput(true);
	m_mover.AddChild(&m_close_button);
	m_close_button.SetSkinBg("TBWindow.close");
	m_close_button.SetIsFocusable(false);
	m_close_button.GetID().Set("TBWindow.close");
	SetIsGroupRoot(true);
}

TBWindow::~TBWindow()
{
	if (m_resizer.GetParent())		RemoveChild(&m_resizer);
	if (m_mover.GetParent())		RemoveChild(&m_mover);
	if (m_close_button.GetParent())	m_mover.RemoveChild(&m_close_button);
	m_mover.RemoveChild(&m_textfield);
}

void TBWindow::ResizeToFitContent(RESIZE_FIT fit)
{
	PreferredSize ps = GetPreferredSize();
	int new_w = ps.pref_w;
	int new_h = ps.pref_h;
	if (fit == RESIZE_FIT_MINIMAL)
	{
		new_w = ps.min_w;
		new_h = ps.min_h;
	}
	else if (fit == RESIZE_FIT_CURRENT_OR_NEEDED)
	{
		new_w = CLAMP(GetRect().w, ps.min_w, ps.max_w);
		new_h = CLAMP(GetRect().h, ps.min_h, ps.max_h);
	}
	if (GetParent())
	{
		new_w = MIN(new_w, GetParent()->GetRect().w);
		new_h = MIN(new_h, GetParent()->GetRect().h);
	}
	SetRect(TBRect(GetRect().x, GetRect().y, new_w, new_h));
}

void TBWindow::Close()
{
	Die();
}

bool TBWindow::IsActive()
{
	return GetState(WIDGET_STATE_SELECTED);
}

TBWindow *TBWindow::GetTopMostOtherWindow(bool only_activable_windows)
{
	TBWindow *other_window = nullptr;
	TBWidget *sibling = GetParent()->GetLastChild();
	while (sibling && !other_window)
	{
		if (sibling != this)
			other_window = TBSafeCast<TBWindow>(sibling);

		if (only_activable_windows && other_window && !(other_window->m_settings & WINDOW_SETTINGS_CAN_ACTIVATE))
			other_window = nullptr;

		sibling = sibling->GetPrev();
	}
	return other_window;
}

void TBWindow::Activate()
{
	if (!GetParent() || !(m_settings & WINDOW_SETTINGS_CAN_ACTIVATE))
		return;
	if (IsActive())
	{
		// Already active, but we may still have lost focus,
		// so ensure it comes back to us.
		EnsureFocus();
		return;
	}

	// Deactivate currently active window
	TBWindow *active_window = GetTopMostOtherWindow(true);
	if (active_window)
		active_window->DeActivate();

	// Activate this window

	SetZ(WIDGET_Z_TOP);
	SetWindowActiveState(true);
	EnsureFocus();
}

bool TBWindow::EnsureFocus()
{
	// If we already have focus, we're done.
	if (focused_widget && IsAncestorOf(focused_widget))
		return true;

	// Focus last focused widget (if we have one)
	bool success = false;
	if (m_last_focus.Get())
		success = m_last_focus.Get()->SetFocus(WIDGET_FOCUS_REASON_UNKNOWN);
	// We didn't have one or failed, so try focus any child.
	if (!success)
		success = SetFocusRecursive(WIDGET_FOCUS_REASON_UNKNOWN);
	return success;
}

void TBWindow::DeActivate()
{
	if (!IsActive())
		return;
	SetWindowActiveState(false);
}

void TBWindow::SetWindowActiveState(bool active)
{
	SetState(WIDGET_STATE_SELECTED, active);
	m_mover.SetState(WIDGET_STATE_SELECTED, active);
}

void TBWindow::SetSettings(WINDOW_SETTINGS settings)
{
	if (settings == m_settings)
		return;
	m_settings = settings;

	if (settings & WINDOW_SETTINGS_TITLEBAR)
	{
		if (!m_mover.GetParent())
			AddChild(&m_mover);
	}
	else if (!(settings & WINDOW_SETTINGS_TITLEBAR))
	{
		if (m_mover.GetParent())
			RemoveChild(&m_mover);
	}
	if (settings & WINDOW_SETTINGS_RESIZABLE)
	{
		if (!m_resizer.GetParent())
			AddChild(&m_resizer);
	}
	else if (!(settings & WINDOW_SETTINGS_RESIZABLE))
	{
		if (m_resizer.GetParent())
			RemoveChild(&m_resizer);
	}
	if (settings & WINDOW_SETTINGS_CLOSE_BUTTON)
	{
		if (!m_close_button.GetParent())
			m_mover.AddChild(&m_close_button);
	}
	else if (!(settings & WINDOW_SETTINGS_CLOSE_BUTTON))
	{
		if (m_close_button.GetParent())
			m_mover.RemoveChild(&m_close_button);
	}

	// FIX: invalidate layout / resize window!
	Invalidate();
}

int TBWindow::GetTitleHeight()
{
	if (m_settings & WINDOW_SETTINGS_TITLEBAR)
		return m_mover.GetPreferredSize().pref_h;
	return 0;
}

TBRect TBWindow::GetPaddingRect()
{
	TBRect padding_rect = TBWidget::GetPaddingRect();
	int title_height = GetTitleHeight();
	padding_rect.y += title_height;
	padding_rect.h -= title_height;
	return padding_rect;
}

PreferredSize TBWindow::OnCalculatePreferredSize()
{
	PreferredSize ps = OnCalculatePreferredContentSize();

	// Add window skin padding
	if (TBSkinElement *e = GetSkinBgElement())
	{
		ps.min_w += e->padding_left + e->padding_right;
		ps.pref_w += e->padding_left + e->padding_right;
		ps.min_h += e->padding_top + e->padding_bottom;
		ps.pref_h += e->padding_top + e->padding_bottom;
	}
	// Add window title bar height
	int title_height = GetTitleHeight();
	ps.min_h += title_height;
	ps.pref_h += title_height;
	return ps;
}

bool TBWindow::OnEvent(const TBWidgetEvent &ev)
{
	if (ev.target == &m_close_button)
	{
		if (ev.type == EVENT_TYPE_CLICK)
			Close();
		return true;
	}
	return false;
}

void TBWindow::OnAdded()
{
	// If we was added last, call Activate to update status etc.
	if (GetParent()->GetLastChild() == this)
		Activate();
}

void TBWindow::OnRemove()
{
	DeActivate();

	// Active the top most other window
	if (TBWindow *active_window = GetTopMostOtherWindow(true))
		active_window->Activate();
}

void TBWindow::OnChildAdded(TBWidget *child)
{
	m_resizer.SetZ(WIDGET_Z_TOP);
}

void TBWindow::OnResized(int old_w, int old_h)
{
	// Apply gravity on children
	TBWidget::OnResized(old_w, old_h);
	// Manually move our own decoration children
	// FIX: Put a layout in the TBMover so we can add things there nicely.
	int title_height = GetTitleHeight();
	m_mover.SetRect(TBRect(0, 0, GetRect().w, title_height));
	PreferredSize ps = m_resizer.GetPreferredSize();
	m_resizer.SetRect(TBRect(GetRect().w - ps.pref_w, GetRect().h - ps.pref_h, ps.pref_w, ps.pref_h));
	TBRect mover_rect = m_mover.GetPaddingRect();
	int button_size = mover_rect.h;
	m_close_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
	if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
		mover_rect.w -= button_size;
	m_textfield.SetRect(mover_rect);
}

}; // namespace tinkerbell
<|endoftext|>