// Ruminations in B sharp // Checking out some thoughts about the Be ToolBox, and how to make it prettier #include #include #include #include //------------------------------------------------------------------------------ // A simplified (and beautified!) BToolBox // I can't use libbe.so, still I need some of the ToolBox functionality // So I have to either implement or emulate it // I also add some convenience tricks and methods // Note, this is slightly different from what is // declared in InterfaceDefs.h: layout is the same, // but functionality is better... struct rgb_color { uchar red; uchar green; uchar blue; uchar alpha; rgb_color(void) {} // Incomplete constructor! Use w/care! rgb_color(uchar _red, uchar _green, uchar _blue, uchar _alpha) : red(_red), green(_green), blue(_blue), alpha(_alpha) {} }; inline ostream& operator << (ostream& os, rgb_color& color) { return os << "rgb_color {" << (int)color.red << ',' << (int)color.green << ',' << (int)color.blue << ',' << (int)color.alpha << "} "; } // Some operations on BPoints I need in the code below... BPoint& BPoint::operator+=(const BPoint& pt) { return x += pt.x, y += pt.y, *this; } BPoint BPoint::operator + (const BPoint& pt) const { return BPoint(x + pt.x, y + pt.y); } inline ostream& operator << (ostream& os, const BPoint pt) { return os << '(' << pt.x << ',' << pt.y << ')'; } // This is an emulation of BView from View.h class BView { public: BView(void) {} rgb_color HighColor(void) const { return rgb_color(255,255,255,0); } void BeginLineArray(long count) { cout << "BView emulator: BeginLineArray of " << count << endl; } void AddLine(BPoint pt0, BPoint pt1, rgb_color col) { cout << "BView emulator: AddLine from " << pt0 << " to " << pt1 << " of " << col << endl; } void EndLineArray(void) { cout << "BView emulator: EndLineArray" << endl << endl; } }; //------------------------------------------------------------------------------ // This is the class to simplify usage of LineArrays // The requirement is, calls to AddLine(), etc, must occur within // BeginLineArray()..EndLineArray(). Furthermore, when calling BeginLineArray(), // one must specify in advance how many calls to AddLine() will occur. This makes // code difficult to maintain: say, one has to always to remember to update the // count in BeginLineArray() when editing calls to AddLine(); // // The following set of classes does away with these headaches. The classes // reinforce the Begin/EndLineArray() policy, and make it simply *impossible* // to violate their usage patterns. // // Run-time overhead: near 0, as most of the methods are inline (and some of them // are merely syntactic sugar) // // Doesn't it remind of currentpath/lineto/stroke etc. PostScript thing? // But we make this "PostScript" implementation on the fly (partly at the // compilation time) 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;} LineArray& operator << (const BRect point); // draw an outline of a rect // 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 // In a more advanced version, that could be // void apply(const Transform& transform); // where class Transform has a method // BPoint Transform::operator () (const BPoint); // This transform is then applied to every point of the // 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 0 ); for(register int i=0; i