1. Robert Johnstone
  2. liblayout

Commits

rjohnsto  committed 40dbc43

The styling system has been reworked. Clients now see actual RGBA values for paint, etc, instead of strings. Setter functions that take strings have been added.

  • Participants
  • Parent commits 6d08256
  • Branches default

Comments (0)

Files changed (7)

File asy.cpp

View file
 static void initialize_pens( std::ostream& out, css const& css )
 {
 	if ( css.has_stroke() ) {
-		long stroke = css.get_stroke_paint();
+		// extract paint information
+		short red = css.stroke & 0xFF;
+		short green = (css.stroke>>8) & 0xFF;
+		short blue = (css.stroke>>16) & 0xFF;
+		short alpha = (css.stroke>>24) & 0xFF;
+		assert( alpha < 0xFF );
+		
 		// set pen colour
-		out << "drawpen = rgb(" << (stroke & 0xFF) << ',' << ((stroke>>8)&0xFF) << ',' << ((stroke>>16)&0xFF) << ") + solid + beveljoin";
+		out << "drawpen = rgb(" << red << ',' << green << ',' << blue << ") + solid";
+		
 		// set pen width
-		if ( !css.get_stroke_width_inherit() ) {
-			assert( css.get_stroke_width() >= 0 );
-			out << " + " << css.get_stroke_width();
-		}
-		switch ( css.get_stroke_join() ) {
+		// stroke width less than zero indicates default for driver
+		if( css.stroke_width >= 0 );
+			out << " + " << css.stroke_width;
+		
+		// set pen join
+		switch ( css.stroke_join ) {
 			case css::join_miter: out << " + miterjoin"; break;
 			case css::join_round: out << " + roundjoin"; break;
 			case css::join_bevel: out << " + beveljoin"; break;
+			default: assert( false ); break;
 		};
 		out << ";\n";
 	}
 	}
 
 	if ( css.has_fill() ) {
-		long fill = css.get_fill_paint();
-		out << "fillpen = rgb(" << (fill & 0xFF) << ',' << ((fill>>8)&0xFF) << ',' << ((fill>>16)&0xFF) << ");\n";
+		// extract paint information
+		short red = css.fill & 0xFF;
+		short green = (css.fill>>8) & 0xFF;
+		short blue = (css.fill>>16) & 0xFF;
+		short alpha = (css.fill>>24) & 0xFF;
+		assert( alpha < 0xFF );
+		
+		// set pen colour
+		out << "fillpen = rgb(" << red << ',' << green << ',' << blue << ");\n";
 	}
 	else {
 		out << "fillpen = invisiblepen;\n";

File css.cpp

View file
 
 #include "layout.h"
 #include <assert.h>
+#include <ctype.h>
+#include <iostream>
 #include <stdexcept>
+#include <string>
+
+#define ALPHAMASK 0xFF000000
 
 using namespace liblayout;
 
 /***********************************************************************/
 
-static inline long rgb( short r, short g, short b )
+static inline css::color_t rgb( short r, short g, short b )
 { return ((long)b << 16) + ((long)g << 8 ) + r; };
 
-/***********************************************************************/
-
-css::css()
-{
-	fill_paint = rgb( 0, 0, 0 );
-	fill_opacity = 1;
-	fill_pattern = fill_solid;
-	stroke_paint = rgb( 0, 0, 0 ); 
-	stroke_width = INHERIT_WIDTH;
-	stroke_join = join_round;
-	stroke_miterlimit = INHERIT_WIDTH;
-	stroke_opacity = 1;
-}
-
-void css::set_fill_paint( char const* text )
-{
-	fill_paint = get_colour( text );
-}
-
-void css::set_fill_opacity( char const* text )
-{
-	fill_opacity = get_percent( text );
-}
-
-void css::set_stroke_paint( char const* text )
-{
-	stroke_paint = get_colour( text );
-}
-
-void css::set_stroke_width( char const* text )
-{
-	stroke_width = get_length( text );
-}
-
-void css::set_stroke_join( char const* text )
-{
-	switch (tolower(*text)) {
-		case 'm':
-			stroke_join = join_miter;
-			break;
-		case 'r':
-			stroke_join = join_round;
-			break;
-		case 'b':
-			stroke_join = join_bevel;
-			break;
-		default:
-			{
-			std::string msg;
-			msg.append( "The colour specification '" );
-			msg.append( text );
-			msg.append( "' could not be converted to an RGB value." );
-			throw std::runtime_error( msg );
-			}
-	}
-}
-
-void css::set_stroke_miterlimit( char const* text )
-{
-	stroke_width = get_length( text );
-}
-
-void css::set_stroke_opacity( char const* text )
-{
-	stroke_opacity = get_percent( text );
-}
-
-static inline short get_value( char t )
+static inline short get_hex_value( char t )
 {
 	// this is a precondition to calling this function
 	assert( isxdigit(t) );
 	return tolower(t)-'a' + 10;
 }
 
-static bool map_compare( std::string const& lhs, std::string const& rhs )
+static css::color_t get_colour( char const* text_ )
 {
-	
-}
+	assert( text_ );
 
-long css::get_colour( char const *text )
-{
-	assert( text );
-
+	typedef std::map<std::string,css::color_t> colourmap;
 	static bool is_initialized = false;
-	static std::map<std::string,long> colours;
+	static colourmap colours;
 
 	if ( ! is_initialized )
 	{
 		colours["cornsilk"] = rgb(255, 248, 220) ;
 		colours["crimson"] = rgb(220, 20, 60) ;
 		colours["cyan"] = rgb(0,255,255);
-		colours["gold"] = rgb(255, 215, 0) ;
+		colours["gold"] = rgb(255, 215, 0);
+		colours["gray"] = rgb(190, 190, 190);
+		colours["grey"] = rgb(190, 190, 190);
 		colours["green"] = rgb(0,255,0);
 		colours["red"] = rgb(255,0,0);
 
 
 		is_initialized = true;
    	}
-
-	// find match?
-	if ( colours.find(text) != colours.end() ) 
-		return colours[text];
-
-	if ( strlen(text) == 7 && text[0]=='#' && isxdigit(text[1]) && isxdigit(text[2]) 
+   	
+   	// make lower case version of string
+   	std::string text( text_ );
+   	std::transform( text.begin(), text.end(), text.begin(), tolower );
+   	
+   	// look up the name
+   	colourmap::const_iterator lp = colours.find(text);
+   	if ( lp != colours.end() ) return lp->second;
+   	
+   	// try RGB hex values
+	if ( text.size()==7 && text[0]=='#' && isxdigit(text[1]) && isxdigit(text[2]) 
 		&& isxdigit(text[3]) && isxdigit(text[4]) && isxdigit(text[5]) && isxdigit(text[6]) ) 
 	{
-		short r = (get_value( text[1] ) << 4 ) + get_value(text[2] );
-		short g = (get_value( text[3] ) << 4 ) + get_value(text[4] );
-		short b = (get_value( text[5] ) << 4 ) + get_value(text[6] );
+		short r = (get_hex_value(  text[1] ) << 4 ) + get_hex_value( text[2] );
+		short g = (get_hex_value(  text[3] ) << 4 ) + get_hex_value( text[4] );
+		short b = (get_hex_value(  text[5] ) << 4 ) + get_hex_value( text[6] );
 		return rgb(r,g,b);
 	}
-	else if ( strlen(text) == 5 && text[0]=='#' && isxdigit(text[1]) && isxdigit(text[2]) 
-		&& isxdigit(text[3]) && isxdigit(text[4]) ) 
+   	// try RGB hex values
+	if ( text.size()==4 && text[0]=='#' && isxdigit(text[1]) && isxdigit(text[2]) 
+		&& isxdigit(text[3]) ) 
 	{
-		short g = (get_value( text[1] ) << 4 ) + get_value(text[2] );
-		short b = (get_value( text[3] ) << 4 ) + get_value(text[4] );
-		return rgb(0,g,b);
+		short r = (get_hex_value(  text[1] ) << 4 ) + get_hex_value( text[1] );
+		short g = (get_hex_value(  text[2] ) << 4 ) + get_hex_value( text[2] );
+		short b = (get_hex_value(  text[3] ) << 4 ) + get_hex_value( text[3] );
+		return rgb(r,g,b);
 	}
-	else if ( strlen(text) == 3 && text[0]=='#' && isxdigit(text[1]) && isxdigit(text[2]) ) 
-	{
-		short b = (get_value( text[1] ) << 4 ) + get_value(text[2] );
-		return rgb(0,0,b);
+	
+	// no such name
+	std::string msg;
+	msg.append( "The colour specification '" );
+	msg.append( text );
+	msg.append( "' could not be converted to an RGB value." );
+	throw std::runtime_error( msg );	
+}
+/***********************************************************************/
+
+void css::set_fill( char const* text )
+{
+	color_t rgb = get_colour( text );
+	
+	// check if no colour was selected
+	if ( rgb<0 ) {
+		// set fill pattern to empty
+		fill_pattern = fill_empty;
 	}
-	else
-	{
-		std::string msg;
-
-		msg.append( "The colour specification '" );
-		msg.append( text );
-		msg.append( "' could not be converted to an RGB value." );
-		throw std::runtime_error( msg );
+	else {
+		assert( (rgb & ALPHAMASK) == 0 );
+		// set paint using alpha
+		fill = (fill & ALPHAMASK) | rgb;
+		// make sure that pattern is not empty
+		if( fill_pattern == fill_empty ) fill_pattern = fill_solid;
 	}
 }
 
-float css::get_percent( char const *text )
+void css::set_stroke( char const* text )
 {
-	assert( text );
+	color_t rgb = get_colour( text );
 	
-	// cheap implementation for now
-	
-	if ( !isdigit(*text) ) {
-		if ( text[0]!='.' || !isdigit(text[1]) ) {
-			std::string msg;
-			msg.append( "The percent specification '" );
-			msg.append( text );
-			msg.append( "' could not be converted to an floating point value." );
-			throw std::runtime_error( msg );
-		}
+	// check if no colour was selected
+	if ( rgb<0 ) {
+		// set stroke width less than zero
+		// this indicates there should be no stroke
+		stroke_width = -1;
 	}
-	float ret = atof( text );
-	if ( strchr( text, '%' ) ) ret *= 100;
-	return ret;
+	else {
+		assert( (rgb & ALPHAMASK) == 0 );
+		// set paint using alpha
+		stroke = (stroke & ALPHAMASK) | rgb;
+		// make sure width is not less than zero
+		stroke_width = 1;
+	}
 }
 
-
-float css::get_length( char const *text )
+void css::set_width( char const* text )
 {
-	assert( text );
-	
-	// cheap implementation for now
-	return atof( text );
+	stroke_width = atof( text );
 }
 
 #ifdef TEST_MODULE
-int main(int argc, char* argv[])
+int main( int argc, char* argv[] )
 {
-	assert( css::get_colour("red") == 0xff );
-	assert( css::get_colour("#ff0000") == 0xff );
-	assert( css::get_colour("green") == 0xff00 );
-	assert( css::get_colour("#ff00") == 0xff00 );
-	assert( css::get_colour("blue") == 0xff0000 );
-	assert( css::get_colour("#ff") == 0xff0000 );
-
-	return 0;
+	liblayout::css style;
+	
+	style.fill = 0xFFFFFFFF;
+	style.set_fill( "red" );
+	assert( style.fill == 0xFF0000FF );
+	style.fill = 0;
+	style.set_fill( "red" );
+	assert( style.fill == 0x000000FF );
 }
 #endif

File layout.h

View file
 		bool	is_file_gdsii( char const* filename );
 	}
 
-	class css
+	struct css
 	{
-	public:
+		// this should be a 32-bit size
+		typedef long color_t;
+	
 		enum join { join_miter, join_round, join_bevel, join_inherit };
-		enum pattern { fill_solid, fill_empty };
+		enum pattern { fill_empty=0, fill_solid };
 		enum { INVALID_WIDTH=-1, INHERIT_WIDTH=-2 };
 		
 		short		order;
-		
-		css();
-		
-		void		set_fill_paint( char const* );
-		void		set_fill_opacity( char const* );
-		void		set_stroke_paint( char const* );
-		void		set_stroke_width( char const* );
-		void		set_stroke_width_invalid() { stroke_width=INVALID_WIDTH; };
-		void		set_stroke_width_inherit() { stroke_width=INHERIT_WIDTH; };
-		void		set_stroke_join( char const* );
-		void		set_stroke_miterlimit( char const* );
-		void		set_stroke_opacity( char const* );
-		void		set_stroke_dasharray( char const* );
-		
-		long		get_fill_paint() const { return fill_paint; };
-		float		get_fill_opacity() const{ return fill_opacity; };
-		long		get_stroke_paint() const { return stroke_paint; };
-		float		get_stroke_width() const { return stroke_width; };
-		bool		get_stroke_width_inherit() const { return (stroke_width==INHERIT_WIDTH); };
-		join		get_stroke_join() const { return stroke_join; };
-		float		get_stroke_miterlimit() const { return stroke_miterlimit; };
-		bool		get_stroke_miterlimit_valid() const { return stroke_miterlimit>=0; };
-		float		get_stroke_opacity() const { return stroke_opacity; };
-		std::vector<float>& get_stroke_dasharray() { return stroke_dasharray; };
-		std::vector<float> const& get_stroke_dasharray() const { return stroke_dasharray; };
-		
-		bool		has_fill() const { return (fill_pattern != fill_empty); };
-		bool		has_stroke() const { return (stroke_width!=INVALID_WIDTH); };
-		
-		static long	get_colour( char const* text );
-		static float	get_percent( char const* text );
-		static float	get_length( char const* text );
-		
-	private:
-		long		fill_paint;
-		float		fill_opacity;
+		color_t		fill; // rgba
 		pattern		fill_pattern;
-		long		stroke_paint;
+		color_t		stroke; // rgba
 		float		stroke_width; // points
 		join		stroke_join;
 		float		stroke_miterlimit; // points
-		float		stroke_opacity;
-		std::vector<float> stroke_dasharray;
+		std::vector<float>	stroke_dasharray;
 		
+		void		set_fill( char const* );
+		void		set_stroke( char const* );
+		void		set_width( char const* );
+		
+		float		fill_opacity() const { return (0xFF - ((fill>>24)&0xFF))/255.0; };
+		float		stroke_opacity() const { return (0xFF - ((stroke>>24)&0xFF))/255.0; };
+		
+		bool		has_fill() const { return (fill_pattern!=fill_empty) && ((fill>>24)&0xFF)!=0xFF; };
+		bool		has_stroke() const { return (stroke_width>0) && ((stroke>>24)&0xFF)!=0xFF; };
+		
+		css() { order=0; fill=0; fill_pattern=fill_empty; stroke=0; stroke_width=1; stroke_join=join_bevel; stroke_miterlimit=0; };
 	};
 		
 	namespace svg

File ps.cpp

View file
 static void write_style_fill( std::ostream& out, css const& style )
 {
 	assert( style.has_fill() );
-	long clr = style.get_fill_paint();
-	float r = (clr & 0xFF)/255.0;
-	float g = ((clr>>8) & 0xFF)/255.0;
-	float b = ((clr>>16) & 0xFF)/255.0;
+	float r = (style.fill & 0xFF)/255.0;
+	float g = ((style.fill>>8) & 0xFF)/255.0;
+	float b = ((style.fill>>16) & 0xFF)/255.0;
 	out << r << ' ' << g << ' ' << b << " setrgbcolor";
 }
 
 static void write_style_stroke( std::ostream& out, css const& style )
 {
+	// set paint
 	assert( style.has_stroke() );
-	long clr = style.get_stroke_paint();
-	float r = (clr & 0xFF)/255.0;
-	float g = ((clr>>8) & 0xFF)/255.0;
-	float b = ((clr>>16) & 0xFF)/255.0;
+	float r = (style.stroke & 0xFF)/255.0;
+	float g = ((style.stroke>>8) & 0xFF)/255.0;
+	float b = ((style.stroke>>16) & 0xFF)/255.0;
 	out << r << ' ' << g << ' ' << b << " setrgbcolor ";
 
-	if ( !style.get_stroke_width_inherit() )
-		out << style.get_stroke_width() << " setlinewidth\n";
+	// set width
+	assert( style.stroke_width > 0 );
+	out << style.stroke_width << " setlinewidth ";
+	
+	// set join
+	switch( style.stroke_join ) {
+		case css::join_miter: out << " 0 setlinejoin "; break;
+		case css::join_round: out << " 1 setlinejoin "; break;
+		case css::join_bevel: out << " 2 setlinejoin "; break;
+		default: assert(false); break;
+	}
+	
+	// and finish the line
+	out << '\n';
 }
 
 static void write_style( std::ostream& out, css const& style )

File svg.cpp

View file
 using namespace liblayout;
 using namespace std;
 
+static void write_byte_hex( std::ostream& out, short value )
+{
+	char digit[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+	out << ((value >> 8) & 0xFF);
+	out << (value & 0xFF);
+}
+
 static void write_css( layout* view, svg::map_id_css const& layer_map, std::ostream& out )
 {
 	// get all the necessary layers
 	
 		out << "\tg.layer" << *lp << " {" << std::endl;
 		if( style.has_fill() ) {
-			out << "\t\tfill: " << style.get_fill_paint() << ';' << std::endl;
-			if ( style.get_fill_opacity() < 1 )
-				out << "\t\tfill-opacity: " << style.get_fill_opacity() << ';' << std::endl;
+			short red = style.fill & 0xFF;
+			short green = (style.fill>>8) & 0xFF;
+			short blue = (style.fill>>16) & 0xFF;
+			short alpha = (style.fill>>24) & 0xFF;
+			assert( alpha<0xFF );
+			
+			// fill colour
+			out << "\t\tfill: ";
+			write_byte_hex( out, red );
+			write_byte_hex( out, green );
+			write_byte_hex( out, blue );
+			out << ";\n";
+			
+			// fill transparency
+			if ( alpha>0 ) 
+				out << "\t\tfill-opacity: " << (1.0-alpha/255.0) << ";\n";
 		}
 		if ( style.has_stroke() ) {
-			out << "\t\tstroke: " << style.get_stroke_paint() << ';' << std::endl;
-			if( !style.get_stroke_width_inherit() )
-				out << "\t\tstroke-width: " << style.get_stroke_width() << ';' << std::endl;
+			short red = style.stroke & 0xFF;
+			short green = (style.stroke>>8) & 0xFF;
+			short blue = (style.stroke>>16) & 0xFF;
+			short alpha = (style.stroke>>24) & 0xFF;
+			assert( alpha<0xFF );
+			
+			// stroke colour
+			out << "\t\tstroke: ";
+			write_byte_hex( out, red );
+			write_byte_hex( out, green );
+			write_byte_hex( out, blue );
+			out << ";\n";
+			
+			// stroke transparency
+			if ( alpha>0 ) 
+				out << "\t\tstroke-opacity: " << (1.0-alpha/255.0) << ";\n";
+				
+			// stroke width
+			if ( style.stroke_width>=0 )
+				out << "\t\tstroke-width: " << style.stroke_width << ";\n";
 		}
 		out << "\t}" << std::endl;
 	}

File vrml.cpp

View file
 			
 		// do we have fill information?
 		if ( style.has_fill() ) {
-			long clr = style.get_fill_paint();
+			long clr = style.fill;
 			short r = clr & 0xff;
 			short g = (clr >> 8 ) & 0xff;
 			short b = (clr >> 16 ) & 0xff;
+			short a = (clr >> 24 ) & 0xff;
+			assert( a<0xFF );
 			out << "\tMaterial {\n";
-			out << "\t\tdiffuseColor " << r / 255.0 << " " << g / 255.0 << " " << b / 255.0 << "\n";
+			out << "\t\tdiffuseColor " << r / 255.0 << ' ' << g / 255.0 << ' ' << b / 255.0 << '\n';
+			if ( a>0 ) out << "\t\ttransparency " << a / 255.0 << '\n';
 			out << "\t}\n";
 		}
 	}

File wmf.cpp

View file
 	{
 		// create the pen
 		if ( lp->second.has_stroke() )
-			file.select_pen( file.create_pen( lp->second.get_stroke_paint() ) );
+			file.select_pen( file.create_pen( lp->second.stroke ) );
 		else
 			file.select_pen( file.create_pen( 0 ) );
 
 		if ( lp->second.has_fill() )
-			file.select_brush( file.create_brush( lp->second.get_fill_paint() ) );
+			file.select_brush( file.create_brush( lp->second.fill ) );
 		else
 			file.select_brush( file.create_null_brush() );
 	}