Click here to Skip to main content
15,885,953 members
Articles / Containers / Virtual Machine

An extendable report editor

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
3 Sep 2008CPOL3 min read 41K   2K   35  
An extendable report editor. You can simply add your own controls without recompiling the program or writing annoying plug-ins.
// ObjBoxList.cpp: implementation of the CObjBoxList class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ObjBoxList.h"
#include "misc.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CObjBoxList::CObjBoxList()
{
    this->index = NULL;
    this->top = 0;
	this->snag_to_grid = TRUE;
	this->grid_size = 5;
	this->is_modified = FALSE;
}
CObjBoxList::~CObjBoxList()
{
    this->Destroy();
}
int CObjBoxList::Init(long init_size)
{
    int i;
    this->top = 0;
    this->size = init_size;
    MALLOC(this->index,CObjBox * ,this->size);
    for(i = 0; i < this->size; i++)
        this->index[i] = NULL;
    return OK;
}
int CObjBoxList::Destroy()
{
    int i;
    if(this->index == NULL)
        return ERROR;
    for(i = 0; i < this->size; i++)
    {
        if(this->index[i])
        {
            this->index[i]->Destroy();
            DEL(this->index[i]);
        }
    }
    FREE(this->index);
    this->index=NULL;
    this->top=0;
    this->size=0;
    return OK;
}
int CObjBoxList::IsEmpty()
{
    if(this->top <= 0)
        return TRUE;
    else
        return FALSE;
}
int CObjBoxList::IsFull()
{
    if(this->top >= this->size)
        return TRUE;
    return FALSE;
}
int CObjBoxList::Push(CObjBox *node)
{
    CObjBox *p;
    p = this->PushEmpty();
    if(p == NULL)
        return ERROR;
    p->Copy(node);
    return OK;
}
int CObjBoxList::Pop(CObjBox *node)
{
    if(this->IsEmpty())
        return ERROR;
    this->top--;
    node->Copy(this->index[this->top]);
    this->index[this->top]->Destroy();
    DEL(this->index[this->top]);
    return OK;
}
int CObjBoxList::Print()
{
    int i;
    for(i = 0; i <this->top; i++)
    {
        this->index[i]->Print();
        LOG(",");
    }
    LOG("\n");
    LOG("size=%%ld\n",this->size);
    LOG("top=%%ld\n",this->top);
    LOG("bottom=%%ld\n",0);
    return OK;
}
long CObjBoxList::GetLen()
{
    return this->top;
}
long CObjBoxList::Search_Pos(CObjBox *node)
{
    int i;
    for(i=0;i<this->top;i++)
    {
        if(this->index[i]->Comp(node) == 0)
            return i;
    }
    return -1;
}

CObjBox * CObjBoxList::Search(CObjBox *node)
{
	long pos = this->Search_Pos(node);
	if(pos >= 0 && pos < this->top)
		return this->index[pos];;
    return NULL;
}
CObjBox * CObjBoxList::GetTop()
{
    if(this->IsEmpty())
        return NULL;
    return this->index[this->top - 1];
}
int CObjBoxList::DelTop()
{
    if(this->IsEmpty())
        return ERROR;
    this->top--;
    this->index[this->top]->Destroy();
    DEL(this->index[this->top]);
    return OK;
}
int CObjBoxList::Clear()
{
    while(this->DelTop());
    return OK;
}
CObjBox *CObjBoxList::PushEmpty()
{
    if(this->IsFull())
    {
        REALLOC(this->index,CObjBox *,this->size * 2);
        this->size *= 2;
        for(int i = this->top; i < this->size; i++)
        {
            this->index[i] = 0;
        }
    }
    NEW(this->index[this->top] , CObjBox );
    this->index[this->top]->Init();
    this->top++;
    return this->index[this->top - 1];
}
CObjBox * CObjBoxList::GetElem(long index)
{
    if(index < 0 || index >= this->top)
        return NULL;
    return this->index[index];
}
int CObjBoxList::Sort(int order)
{
    long i,j,c;    
    CObjBox *pt;
    for(j=this->GetLen(); j > 0; j--)
    {
        for(i = 0; i < j - 1; i++)
        {
            if(order==0)
                c = index[i]->Comp(index[i+1]) > 0;
            else
                c = index[i]->Comp(index[i+1]) < 0;
            if(c)
            {
                pt = index[i];
                index[i] = index[i + 1];
                index[i + 1] = pt;                
            }
        }
    }
    return OK;
}
CObjBox * CObjBoxList::BSearch_CObjBox(CObjBox *node,int order)
{
    long i;
    i = this->BSearch(node,order);
    return this->GetElem(i);
}
long CObjBoxList::BSearch(CObjBox *node,int order)
{
    int find,pos;
    pos = this->BSearch_Pos(node,order,&find);
    if(find) return pos;
    return -1;
}
int CObjBoxList::InsertElem(long i, CObjBox *node)
{
    //insert a node at pos i
    CObjBox *new_node;
    ASSERT(i >= 0 && i <= this->top);
    //Add a new node
    new_node = this->PushEmpty(); 
    ASSERT(new_node);
    //copy value
    new_node->Copy(node);
    for(int k = this->top - 1; k >= i; k--)
    {
        this->index[k] = this->index[k - 1];
    }
    this->index[i] = new_node;
    return OK;
}
int CObjBoxList::DelElem(long i)
{
    CObjBox *p;
    ASSERT(i >= 0 && i < this->top);
    p = this->GetElem(i);
    DEL(p);
    for(int k = i; k < this->top; k++)
    {
        this->index[k] = this->index[k + 1];
    }
    this->top --;
    this->index[top] = NULL;
    return OK;
}
int CObjBoxList::InsOrdered(CObjBox *node, int order,int unique)
{
    int pos,find;
    pos = this->BSearch_Pos(node,order,&find);
    if(find && unique)
        return ERROR;
    return this->InsertElem(pos,node);
}
long CObjBoxList::BSearch_Pos(CObjBox *node, int order, int *find_flag)
{
    long low,high,mid,c;
    long flag = 0,pos = -1;
    ASSERT(order == 0 || order == 1);
    low = 0; high=this->GetLen() - 1;
    while(low<=high)
    {
        mid = (low+high)/2;
        if(node->Comp(this->index[mid]) == 0)
        {
            *find_flag = TRUE;
            return mid;
        }
        if(order == 0)
            c = this->index[mid]->Comp(node) > 0;
        else
            c = this->index[mid]->Comp(node) < 0;
        if(c)
            high = mid-1;
        else
            low = mid+1;
    }
    *find_flag = FALSE;
    return low;
}
//////////////////////////////////////////////////////////
//below is my own code
//////////////////////////////////////////////////////////
int CObjBoxList::SetCanvas(CCanvas *canvas)
{
	CObjBox *pobj;

	for(int i = 0; i< this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		pobj->SetCanvas(canvas);
	}

	return OK;
}

int CObjBoxList::PtInWhich(int x, int y)
{
	CObjBox *pobj;

	for(int i = this->GetLen() - 1; i >= 0; i--)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->PtInRect(x,y))
			return i;
	}

	return -1;
}

int CObjBoxList::SetSel(int i,BOOL flag)
{
	CObjBox *pobj;

	pobj = this->GetElem(i);
	if(pobj)
	{
		pobj->SetSel(flag);
		this->SelInSameGroup(pobj);
		return OK;
	}

	return ERROR;
}

int CObjBoxList::CancelAllSel()
{
	CObjBox *pobj;

	for(int i = 0; i< this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		pobj->SetSel(0);
	}

	return OK;
}

int CObjBoxList::GetSelNum()
{
	int c = 0;
	CObjBox *p;

	for(int i = 0; i< this->GetLen(); i++)
	{
		p = this->GetElem(i);
		ASSERT(p);

		if(p->selected)
			c++;
	}

	return c;
}

int CObjBoxList::GetFirstSel()
{
	CObjBox *p;

	for(int i = this->GetLen() - 1; i >= 0; i--)
	{
		p = this->GetElem(i);
		ASSERT(p);

		if(p->selected)
			return i;
	}

	return -1;
}

int CObjBoxList::OffsetAllSel(int cx, int cy)
{
	CObjBox *pobj;

	for(int i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			this->SetModifyFlag(TRUE);
			pobj->Offset(cx,cy);
			pobj->CalcuResizeBoxPos();
		}
	}

	return OK;
}

int CObjBoxList::DelSel()
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			this->DelElem(i);
			this->SetModifyFlag(TRUE);
			i --; //DelElem will move the elements
		}
	}
	return OK;
}

int CObjBoxList::SetSel(int l, int t, int r, int b)
{
	CRect sel_rect;
	CObjBox *pobj;

	sel_rect.Init();
	sel_rect.SetRect(l,t,r,b);
	
	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->IsIntersect(&sel_rect))
		{
			pobj->SetSel(TRUE);
			this->SelInSameGroup(pobj);
		}
	}
	
	return OK;
}


int CObjBoxList::SwapObj(int i, int j)
{

	if(i == j)
		return OK;

	if( i < 0 || i >= this->GetLen())
		return ERROR;

	if( j < 0 || j >= this->GetLen())
		return ERROR;

	CObjBox *ptr = this->GetElem(i);
	this->index[i] = this->GetElem(j);
	this->index[j] = ptr;
	
	this->SetModifyFlag(TRUE);

	return OK;
}

int CObjBoxList::AlignSelLeft()
{
	int i,min_left;
	CObjBox *pobj;

	min_left = this->GetSelMinLeft();

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(pobj->GetWidth() > 0)
				pobj->SetLeft(min_left);
			else
				pobj->SetRight(min_left);
			this->SetModifyFlag(TRUE);
			pobj->CalcuResizeBoxPos();
		}
	}

	return OK;
}

int CObjBoxList::AlignSelRight()
{
	int i,max_right = MIN_INT;
	CObjBox *pobj;
	CRect rt;

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			rt.Copy(pobj);
			rt.Normalize();

			if(rt.right > max_right)
				max_right = rt.right;
		}
	}
	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(pobj->GetWidth() > 0)
				pobj->SetRight(max_right);
			else
				pobj->SetLeft(max_right);
			this->SetModifyFlag(TRUE);
			pobj->CalcuResizeBoxPos();
		}
	}

	return OK;
}

int CObjBoxList::AlignSelTop()
{
	int i,min_top;
	CObjBox *pobj;

	min_top = this->GetSelMinTop();

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(pobj->GetHeight() > 0)
				pobj->SetTop(min_top);
			else
				pobj->SetBottom(min_top);
			this->SetModifyFlag(TRUE);
			pobj->CalcuResizeBoxPos();
		}
	}

	return OK;
}
int CObjBoxList::AlignSelBottom()
{
	int i,max_bottom = MIN_INT;
	CObjBox *pobj;
	CRect rt;

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			rt.Copy(pobj);
			rt.Normalize();

			if(rt.bottom > max_bottom)
				max_bottom = rt.bottom;
		}
	}
	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(pobj->GetHeight() > 0)
				pobj->SetBottom(max_bottom);
			else
				pobj->SetTop(max_bottom);
			this->SetModifyFlag(TRUE);
			pobj->CalcuResizeBoxPos();
		}
	}

	return OK;
}

int CObjBoxList::GetUniqueGroupNum()
{
	static int i = 1000;
	return i++;
}

int CObjBoxList::GroupSel()
{
	int i,g;
	CObjBox *pobj;

	g = this->GetUniqueGroupNum();
	
	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			pobj->group_num = g;
			this->SetModifyFlag(TRUE);
		}
	}
	
	return OK;
}

int CObjBoxList::UngroupSel()
{
	CObjBox *pobj;

	for(int i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			pobj->group_num = 0;
			this->SetModifyFlag(TRUE);
		}
	}
	
	return OK;
}

int CObjBoxList::SelInSameGroup(CObjBox *pobj)
{
	ASSERT(pobj);
	
	if(pobj->group_num == 0)
		return ERROR;

	CObjBox *p;

	for(int i = 0; i<this->GetLen(); i++)
	{
		p = this->GetElem(i);
		ASSERT(p);

		if(pobj->group_num == p->group_num)
			p->SetSel(TRUE);
	}
	
	return OK;
}

int CObjBoxList::PutSelToClipBoard()
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		pobj->is_copied =FALSE; // clear all copy flag

		if(pobj->selected)
			pobj->is_copied = TRUE;
	}

	return OK;
}

int CObjBoxList::IsClipBoardEmpty()
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->is_copied)
			return FALSE;
	}
	return OK;
}

int CObjBoxList::GetSelMinLeft()
{
	int i,min_left = MAX_INT;
	CObjBox *pobj;
	CRect rt;

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			rt.Copy(pobj);
			rt.Normalize();

			if(rt.left < min_left)
				min_left = rt.left;
		}
	}

	return min_left;
}

int CObjBoxList::GetSelMinTop()
{
	int i,min_top = MAX_INT;
	CObjBox *pobj;
	CRect rt;

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			rt.Copy(pobj);
			rt.Normalize();

			if(rt.top < min_top)
				min_top = rt.top;
		}
	}

	return min_top;
}

int CObjBoxList::GetCopiedMinTop()
{
	int i,min_top = MAX_INT;
	CObjBox *pobj;
	CRect rt;

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->is_copied)
		{
			rt.Copy(pobj);
			rt.Normalize();

			if(rt.top < min_top)
				min_top = rt.top;
		}
	}

	return min_top;
}

int CObjBoxList::GetCopiedMinLeft()
{
	int i,min_left = MAX_INT;
	CObjBox *pobj;
	CRect rt;

	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->is_copied)
		{
			rt.Copy(pobj);
			rt.Normalize();

			if(rt.left < min_left)
				min_left = rt.left;
		}
	}

	return min_left;
}

int CObjBoxList::Paste(int x, int y)
{
	int old_len = this->GetLen();
	int cx = x - this->GetCopiedMinLeft();
	int cy = y - this->GetCopiedMinTop();
		
	CObjBox *pobj,*pnew;

	this->CancelAllSel();

	for(int i = 0; i<old_len; i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->is_copied)
		{
			pnew = this->PushEmpty();
			ASSERT(pnew);
			pnew->Copy(pobj);
			pnew->SetSel(TRUE);
			pnew->Offset(cx,cy);
			pnew->CalcuResizeBoxPos();
			this->SetModifyFlag(TRUE);
		}
	}
	return OK;
}

int CObjBoxList::GetSelMaxWidth()
{
	CObjBox *pobj;
	int max_width = MIN_INT;

	for(int i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(abs(pobj->GetWidth() > max_width))
				max_width = abs(pobj->GetWidth());
		}
	}

	return max_width;
}

int CObjBoxList::GetSelMaxHeight()
{
	CObjBox *pobj;
	int max_width = MIN_INT;

	for(int i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(abs(pobj->GetHeight() > max_width))
				max_width = abs(pobj->GetHeight());
		}
	}

	return max_width;
}

int CObjBoxList::SameSelWidth()
{
	int max = this->GetSelMaxWidth();
	CObjBox *pobj;

	for(int i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(pobj->GetWidth() > 0)
				pobj->SetWidth(max);
			else
				pobj->SetWidth(-max);
			this->SetModifyFlag(TRUE);
			pobj->CalcuResizeBoxPos();
		}
	}
	return OK;
}
int CObjBoxList::SameSelHeight()
{
	int max = this->GetSelMaxHeight();
	CObjBox *pobj;

	for(int i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);

		if(pobj->selected)
		{
			if(pobj->GetHeight() > 0)
				pobj->SetHeight(max);
			else
				pobj->SetHeight(-max);
			this->SetModifyFlag(TRUE);
			pobj->CalcuResizeBoxPos();
		}
	}
	return OK;
}

int CObjBoxList::SameSelSize()
{
	this->SameSelHeight();
	this->SameSelWidth();

	return OK;
}
int CObjBoxList::Resize(int resize_obj,int resize_type,int x, int y,int is_square)
{
	CObjBox *pobj;
	
	int x1,y1,x2,y2;

	if(this->snag_to_grid)
	{
		x = x - x % this->grid_size;
		y = y - y % this->grid_size;
	}

	pobj = this->GetElem(resize_obj);
	ASSERT(pobj);

	pobj->GetResizePt(resize_type,&x1,&y1);
	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			this->SetModifyFlag(TRUE);
			pobj->GetResizePt(resize_type,&x2,&y2);
			pobj->Expand(resize_type,x+(x2 - x1),y + (y2 - y1),is_square);
			pobj->CalcuResizeBoxPos();

		}
	}

	return OK;
}

int CObjBoxList::PtInResizeBox(int x,int y,int *type)
{
	ASSERT(type);

	CObjBox *pobj;
	int t;

	*type = CResizeBox::TYPE_ERR;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			t = pobj->PtInResizeBox(x,y);
			if(t != CResizeBox::TYPE_ERR)
			{
				*type = t;
				break;
			}
		}
	}

	return i;
}

int CObjBoxList::CalAllDragOffset(int x, int y)
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			pobj->CalDragOffset(x,y);
		}
	}

	return OK;
}

int CObjBoxList::MoveSelToMouse(int x, int y)
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			pobj->SetPos(x-pobj->drag_offx,y-pobj->drag_offy);
			this->SetModifyFlag(TRUE);
			if(this->snag_to_grid)
				pobj->SnagToDrid(this->grid_size);
			pobj->CalcuResizeBoxPos();
		}
	}

	return OK;
}

int CObjBoxList::SaveToFile(CFileBase *file)
{
	ASSERT(file);
	
	int i;
	CObjBox *pobj;	
	CMem mem;

	LOCAL_MEM(mem);

	file->SetSize(0);
	file->Puts("<?xml version=\"1.0\" encoding=\"gb2312\"?>\r\n");
	file->Puts("<AllObjects>\r\n");
	for(i = 0; i<this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		pobj->i_xml_node->GetPath(&mem);
		file->Printf("<objbox xml_path=\"%s\" group=\"%d\">\r\n",mem.p,pobj->group_num);
		file->Printf("<rect left=\"%d\" top=\"%d\" right=\"%d\" bottom=\"%d\"/>\r\n",
					 pobj->left,pobj->top,pobj->right,pobj->bottom);
		file->Printf("<code>\r\n");
		file->Printf("<![CDATA[\r\n");
		file->WriteFile(pobj->mf_user_attrib);
		file->Printf("\r\n]]>\r\n");
		file->Printf("</code>\r\n");
		file->Printf("</objbox>\r\n");
	}
	file->Puts("</AllObjects>\r\n");

	this->SetModifyFlag(FALSE);

	return OK;
}

int CObjBoxList::SaveToFile(char *fn)
{
	CFile file;

	file.Init();
	ASSERT(file.OpenFile(fn,"wb+"));

	this->SaveToFile(&file);

	file.CloseFile();

	return OK;
}

int CObjBoxList::SetModifyFlag(BOOL flag)
{
	this->is_modified = flag;
	return OK;
}

int CObjBoxList::ToBack(int i)
{
	ASSERT(i >= 0 && i < this->GetLen());

	CObjBox *p = this->GetElem(i);

    for(int k = i ; k > 0; k--)
    {
        this->index[k] = this->index[k - 1];
		this->SetModifyFlag(TRUE);
    }
	
	this->index[0] = p;

	return OK;
}

int CObjBoxList::ToFront(int i)
{
	ASSERT(i >= 0 && i < this->GetLen());

	CObjBox *p = this->GetElem(i);

    for(int k = i; k < top - 1; k++)
    {
        this->index[k] = this->index[k + 1];
		this->SetModifyFlag(TRUE);
    }
	
	if(top > 0)
		this->index[top - 1] = p;

	return OK;
}

int CObjBoxList::SelectAll()
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		pobj->SetSel(TRUE);
	}

	return OK;
}

int CObjBoxList::NormalizeSel()
{
	CObjBox *pobj;

	for(int i = 0; i < this->GetLen(); i++)
	{
		pobj = this->GetElem(i);
		ASSERT(pobj);
		if(pobj->selected)
		{
			pobj->Normalize();
		}
	}

	return OK;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
China China
26 years old, 2 years work experience.

Comments and Discussions