Listing 3: Compiling graphical primitives to send an accelerator card
class LineArray
{
BView& my_view;
BPoint curr_point;
rgb_color curr_color;
class LineParm // A compilation "unit" describing one line segment
{
BPoint from, to;
rgb_color color;
public:
LineParm(void) {} // this is an incomplete constructor: careful!
LineParm(const BPoint _from, const BPoint _to, rgb_color _color)
: from(_from), to(_to), color(_color) {}
BPoint q_from(void) const { return from; }
BPoint q_to(void) const { return to; }
void doAddLine(BView& view) const
{ view.AddLine(from,to,color); }
void offset_by(const BPoint pt) { from += pt; to += pt; }
friend ostream& operator << (ostream& os, LineParm& line_parm);
};
// An array of line segments...
enum {allocation_quantum =5};
LineParm * current_path;
int path_length;
int allocated;
LineParm path_preallocated[5];
void append_path(const BPoint from, const BPoint to);
public:
// "Compilation" classes
class line_to
{
friend class LineArray;
BPoint to_point;
public:
line_to(const BPoint& pt) : to_point(pt) {}
line_to(const float x, const float y) : to_point(x,y) {}
};
class rline_to
{
friend class LineArray;
BPoint to_point;
public:
rline_to(const BPoint& pt) : to_point(pt) {}
rline_to(const float x, const float y) : to_point(x,y) {}
};
class line_from_to
{
friend class LineArray;
BPoint from_point;
BPoint to_point;
public:
line_from_to(const BPoint& _from, const BPoint& _to)
: from_point(_from), to_point(_to) {}
};
// inline constructor/destructor
LineArray(BView& view) : my_view(view), curr_point(0,0),
curr_color(view.HighColor()),
current_path(path_preallocated),
allocated(
sizeof(path_preallocated)/sizeof(path_preallocated[0])),
path_length(0)
{}
~LineArray(void) { if( current_path != path_preallocated )
delete current_path; }
// Setting the current point of a path
LineArray& operator << (const BPoint point)
{ curr_point = point; return *this;}
// draw an outline of a rect
LineArray& operator << (const BRect point);
// Adding line segments to the path
LineArray& operator << (const line_to& lineto)
{ append_path(curr_point, lineto.to_point);
curr_point = lineto.to_point; return *this;}
LineArray& operator << (const rline_to& rlineto);
LineArray& operator << (const line_from_to& lineft)
{ append_path(lineft.from_point, lineft.to_point);
curr_point = lineft.to_point; return *this; }
void close_path(void); // Connect curr_point to the first pt
void stroke(void); // Stroke the path
// Manipulator procedures...
typedef LineArray& (*LineArrayManip)(LineArray&);
LineArray& operator << (const LineArrayManip manip)
{ return manip(*this); }
friend LineArray& endl(LineArray& larray)
{ larray.stroke(); return larray; }
// Dealing with the whole path
void offset_by(const BPoint pt);
// Print the whole path (in a human-readable form)
friend ostream& operator << (ostream& os, LineArray& line_array);
};
// Add a new segment to the path
void LineArray::append_path(const BPoint from, const BPoint to)
{
if( ++path_length > allocated )
{
LineParm * old_path = current_path;
current_path = new LineParm[allocated =
path_length+allocation_quantum];
cout << "reallocating path to " << allocated << " elems" << endl;
memcpy((void*)current_path,(void*)old_path,
sizeof(current_path[0])*(path_length-1));
if( old_path != path_preallocated )
delete old_path;
}
current_path[path_length-1] = LineParm(from,to,curr_color);
}
LineArray& LineArray::operator << (const rline_to& rlineto)
{
BPoint to = curr_point + rlineto.to_point;
append_path(curr_point, to);
curr_point = to;
return *this;
}
// Connect the curr_point to the first pt
void LineArray::close_path(void)
{
assert( path_length > 0 );
if( path_length == 1 ) // Nothing to close
return;
append_path(curr_point,current_path[0].q_from());
}
// Stroke the path
// This is the only place where BeginLineArray() etc. are
// called. And they're called in the right sequence!
void LineArray::stroke(void)
{
assert( path_length > 0 );
my_view.BeginLineArray(path_length);
for(register int i=0; i<path_length; i++)
current_path[i].doAddLine(my_view);
my_view.EndLineArray();
}
// Apply the simplest transform to the path
void LineArray::offset_by(const BPoint pt)
{
assert( path_length > 0 );
for(register int i=0; i<path_length; i++)
current_path[i].offset_by(pt);
curr_point += pt;
}
// Print the whole path (in a human-readable form)
ostream& operator << (ostream& os, LineArray::LineParm& line_parm)
{ return os << "line segment: from " << line_parm.from << " to "
<< line_parm.to << endl; }
ostream& operator << (ostream& os, LineArray& line_array)
{
if( line_array.path_length == 0 )
return os << "empty path" << endl;
os << "Line path of " << line_array.path_length
<< " line segments" << endl;
for(register int i=0; i<line_array.path_length; i++)
os << line_array.current_path[i];
return os << endl;
}
//------------------------------------------------------------------
// Here's how everything is used
static void test_line_array(void)
{
BView view;
LineArray lines(view);
lines << BPoint(10,10);
lines << LineArray::line_to(10,20);
lines << LineArray::rline_to(10,0);
lines << LineArray::rline_to(0,-10);
lines.close_path(); // connect to the first point
lines.stroke();
// Add more segments to the old path...
lines << BPoint(20,20) << LineArray::rline_to(-10,-10);
lines << LineArray::line_from_to(BPoint(10,20),BPoint(20,10));
lines.offset_by(BPoint(100,100));
lines.stroke();
cout << "The path last stroked was " << lines << endl;
}
static void test_line_array1(void)
{
BView view;
cout << "\n\ntesting an one-liner " << endl;
LineArray(view) << LineArray::line_from_to(BPoint(0,0),
BPoint(20,10)) << endl;
}
//End of File