Commit 17a4fab9 authored by twanvl's avatar twanvl

Script support for AColors. All colors in script related code are now AColor.

parent 8c9af7aa
......@@ -24,6 +24,7 @@ Possible constants are:
| @123.5@ [[type:double]]
| @"abc"@ [[type:string]]
| @rgb(255,0,0)@ [[type:color]]
| @rgba(0,0,0,0)@ [[type:color]]
| @[a,b,c]@ [[type:list]]
Note: Strings, list and colors don't have to be constants, they can contain other code.
......
......@@ -16,7 +16,7 @@ A reference to a normal [[type:font]] for drawing text.
| @underline@ [[type:scriptable]] [[type:boolean]] @false@ Should the font be underlined?
| @color@ [[type:scriptable]] [[type:color]] @rgb(0,0,0)@ What color should text be drawn in?
| @shadow color@ [[type:scriptable]] [[type:color]] @"transparent"@ Color for a shadow below the text.
| @shadow displacement x@ [[type:double]] @0@ Relative position of the shadow in pixels. A shadow is only drawn if the displacement is nonzero.
| @shadow displacement x@ [[type:double]] @0@ Relative position of the shadow in pixels.
| @shadow displacement y@ [[type:double]] @0@ ^^^
| @shadow blur@ [[type:double]] @0@ How much should the shadow be blurred?
| @separator color@ [[type:color]] @rgba(0,0,0,128)@ Color for @"<sep-soft>"@ tags inserted by the [[fun:combined_editor]] function.
......
......@@ -642,7 +642,7 @@ KeywordParamValue::operator String() const {
KeywordParamValue::operator int() const { return *to_script(value); } // a bit of a hack
KeywordParamValue::operator double() const { return *to_script(value); }
KeywordParamValue::operator Color() const { return *to_script(value); }
KeywordParamValue::operator AColor() const { return *to_script(value); }
int KeywordParamValue::itemCount() const { return to_script(value)->itemCount(); }
ScriptValueP KeywordParamValue::getMember(const String& name) const {
......
......@@ -171,7 +171,7 @@ class KeywordParamValue : public ScriptValue {
virtual operator String() const;
virtual operator int() const;
virtual operator double() const;
virtual operator Color() const;
virtual operator AColor() const;
virtual int itemCount() const;
virtual ScriptValueP getMember(const String& name) const;
};
......
......@@ -24,13 +24,7 @@ template <> void Reader::handle(AColor& col) {
if (!col.Ok()) col = AColor(0,0,0,0);
}
template <> void Writer::handle(const AColor& col) {
if (col.alpha == 255) {
handle(String::Format(_("rgb(%u,%u,%u)"), col.Red(), col.Green(), col.Blue()));
} else if (col.alpha == 0) {
handle(_("transparent"));
} else {
handle(String::Format(_("rgba(%u,%u,%u,%u)"), col.Red(), col.Green(), col.Blue(), col.alpha));
}
handle(format_acolor(col));
}
......@@ -56,6 +50,16 @@ AColor parse_acolor(const String& v) {
}
}
String format_acolor(AColor col) {
if (col.alpha == 255) {
return String::Format(_("rgb(%u,%u,%u)"), col.Red(), col.Green(), col.Blue());
} else if (col.alpha == 0) {
return _("transparent");
} else {
return String::Format(_("rgba(%u,%u,%u,%u)"), col.Red(), col.Green(), col.Blue(), col.alpha);
}
}
// ----------------------------------------------------------------------------- : Color utility functions
Color lerp(const Color& a, const Color& b, double t) {
......
......@@ -35,6 +35,9 @@ Color parse_color(const String& value);
/// Parse a color with alpha
AColor parse_acolor(const String& value);
/// Convert an AColor to a string
String format_acolor(AColor col);
// ----------------------------------------------------------------------------- : Color utility functions
inline int bot(int x) { return max(0, x); } ///< bottom range check for color values
......
......@@ -29,6 +29,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
// Perform a ternary simple instruction, store the result in a (not in *a)
void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP& b, const ScriptValueP& c);
// Perform a quaternary simple instruction, store the result in a (not in *a)
void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptValueP& b, const ScriptValueP& c, const ScriptValueP& d);
ScriptValueP Context::eval(const Script& script, bool useScope) {
size_t stack_size = stack.size();
......@@ -172,6 +175,16 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
ScriptValueP b = stack.back(); stack.pop_back();
ScriptValueP& a = stack.back();
instrTernary(i.instr3, a, b, c);
// cout << "\t\t-> " << (String)*stack.back() << endl;
break;
}
// Simple instruction: quaternary
case I_QUATERNARY: {
ScriptValueP d = stack.back(); stack.pop_back();
ScriptValueP c = stack.back(); stack.pop_back();
ScriptValueP b = stack.back(); stack.pop_back();
ScriptValueP& a = stack.back();
instrQuaternary(i.instr4, a, b, c, d);
// cout << "\t\t-> " << (String)*stack.back() << endl;
break;
}
......@@ -370,6 +383,16 @@ void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP&
}
}
// ----------------------------------------------------------------------------- : Simple instructions : quaternary
void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptValueP& b, const ScriptValueP& c, const ScriptValueP& d) {
switch (i) {
case I_RGBA:
a = to_script(AColor((int)*a, (int)*b, (int)*c, (int)*d));
break;
}
}
// ----------------------------------------------------------------------------- : Simple instructions : object
void Context::makeObject(size_t n) {
......
......@@ -319,6 +319,15 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
a = dependency_dummy;
break;
}
// Simple instruction: quaternary
case I_QUATERNARY: {
ScriptValueP d = stack.back(); stack.pop_back();
ScriptValueP c = stack.back(); stack.pop_back();
ScriptValueP b = stack.back(); stack.pop_back();
ScriptValueP& a = stack.back();
a = dependency_dummy;
break;
}
}
}
} catch (...) {
......
......@@ -511,6 +511,18 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
parseOper(input, script, PREC_ALL); // b
expectToken(input, _(")"));
script.addInstruction(I_TERNARY, I_RGB);
} else if (token == _("rgba")) {
// rgba(r, g, b, a)
expectToken(input, _("("));
parseOper(input, script, PREC_ALL); // r
expectToken(input, _(","));
parseOper(input, script, PREC_ALL); // g
expectToken(input, _(","));
parseOper(input, script, PREC_ALL); // b
expectToken(input, _(","));
parseOper(input, script, PREC_ALL); // a
expectToken(input, _(")"));
script.addInstruction(I_QUATERNARY, I_RGBA);
} else if (token == _("min") || token == _("max")) {
// min(x,y,z,...)
unsigned int op = token == _("min") ? I_MIN : I_MAX;
......
......@@ -187,6 +187,11 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
case I_RGB: ret += _("rgb"); break;
}
break;
case I_QUATERNARY: ret += _("quaternary\t");
switch (i.instr3) {
case I_RGBA: ret += _("rgba"); break;
}
break;
}
// arg
switch (i.instr) {
......@@ -227,7 +232,9 @@ const Instruction* Script::backtraceSkip(const Instruction* instr, int to_skip)
case I_BINARY:
to_skip += 1; break; // nett stack effect 1-2 == -1
case I_TERNARY:
to_skip += 2; break; // nett stack effect 1-3 == -1
to_skip += 2; break; // nett stack effect 1-3 == -2
case I_QUATERNARY:
to_skip += 3; break; // nett stack effect 1-4 == -3
case I_CALL:
to_skip += instr->data; // arguments of call
break;
......
......@@ -41,6 +41,7 @@ enum InstructionType
, I_UNARY = -4 ///< pop 1 value, apply a function, push the result
, I_BINARY = -3 ///< pop 2 values, apply a function, push the result
, I_TERNARY = -2 ///< pop 3 values, apply a function, push the result
, I_QUATERNARY = -1 ///< pop 4 values, apply a function, push the result
};
/// Types of unary instructions (taking one argument from the stack)
......@@ -82,17 +83,23 @@ enum TernaryInstructionType
{ I_RGB ///< pop r,g,b, push a color value
};
/// Types of quaternary instructions (taking four arguments from the stack)
enum QuaternaryInstructionType
{ I_RGBA ///< pop r,g,b,a, push an acolor value
};
/// An instruction in a script, consists of the opcode and data
/** If the opcode is one of I_UNARY,I_BINARY,I_TERNARY,
/** If the opcode is one of I_UNARY,I_BINARY,I_TERNARY,I_QUATERNARY,
* Then the instr? member gives the actual instruction to perform
*/
struct Instruction {
InstructionType instr : 4;
union {
unsigned int data : 28;
UnaryInstructionType instr1 : 28;
BinaryInstructionType instr2 : 28;
TernaryInstructionType instr3 : 28;
unsigned int data : 28;
UnaryInstructionType instr1 : 28;
BinaryInstructionType instr2 : 28;
TernaryInstructionType instr3 : 28;
QuaternaryInstructionType instr4 : 28;
};
};
......
......@@ -12,6 +12,7 @@
#include <script/parser.hpp>
#include <script/script.hpp>
#include <script/value.hpp>
#include <gfx/color.hpp>
Alignment from_string(const String&);
......@@ -23,9 +24,11 @@ void store(const ScriptValueP& val, String& var) { var = val->toStr
void store(const ScriptValueP& val, int& var) { var = *val; }
void store(const ScriptValueP& val, double& var) { var = *val; }
void store(const ScriptValueP& val, bool& var) { var = static_cast<int>(*val); }
void store(const ScriptValueP& val, Color& var) { var = *val; }
void store(const ScriptValueP& val, Color& var) { var = (AColor)*val; }
void store(const ScriptValueP& val, AColor& var) { var = *val; }
void store(const ScriptValueP& val, Defaultable<String>& var) { var.assign(*val); }
void store(const ScriptValueP& val, Defaultable<Color>& var) { var.assign(*val); }
void store(const ScriptValueP& val, Defaultable<Color>& var) { var.assign((AColor)*val); }
void store(const ScriptValueP& val, Defaultable<AColor>& var) { var.assign(*val); }
void store(const ScriptValueP& val, Alignment& var) { var = from_string(val->toString()); }
// ----------------------------------------------------------------------------- : OptionalScript
......
......@@ -18,6 +18,7 @@
#include <script/parser.hpp>
#include <script/to_value.hpp>
class AColor;
DECLARE_POINTER_TYPE(Script);
// ----------------------------------------------------------------------------- : Store
......@@ -28,6 +29,7 @@ void store(const ScriptValueP& val, int& var);
void store(const ScriptValueP& val, double& var);
void store(const ScriptValueP& val, bool& var);
void store(const ScriptValueP& val, Color& var);
void store(const ScriptValueP& val, AColor& var);
void store(const ScriptValueP& val, Defaultable<String>& var);
void store(const ScriptValueP& val, Defaultable<Color>& var);
void store(const ScriptValueP& val, Alignment& var);
......
......@@ -56,7 +56,7 @@ class ScriptDelayedError : public ScriptValue {
virtual operator String() const;
virtual operator double() const;
virtual operator int() const;
virtual operator Color() const;
virtual operator AColor() const;
virtual int itemCount() const;
virtual const void* comparePointer() const;
// these can propagate the error
......@@ -207,7 +207,7 @@ class ScriptObject : public ScriptValue {
virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); }
virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); }
virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); }
virtual operator Color() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator Color(); }
virtual operator AColor() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator AColor(); }
virtual ScriptValueP getMember(const String& name) const {
GetMember gm(name);
gm.handle(*value);
......@@ -254,7 +254,8 @@ class ScriptObject : public ScriptValue {
inline ScriptValueP to_script(long v) { return to_script((int) v); }
ScriptValueP to_script(double v);
ScriptValueP to_script(const String& v);
ScriptValueP to_script(const Color& v);
ScriptValueP to_script(Color v);
ScriptValueP to_script(AColor v);
inline ScriptValueP to_script(bool v) { return v ? script_true : script_false; }
template <typename T>
inline ScriptValueP to_script(const vector<T>* v) { return new_intrusive1<ScriptCollection<vector<T> > >(v); }
......@@ -282,7 +283,8 @@ template <> inline String from_script<String> (const ScriptValueP& va
template <> inline int from_script<int> (const ScriptValueP& value) { return *value; }
template <> inline double from_script<double> (const ScriptValueP& value) { return *value; }
template <> inline bool from_script<bool> (const ScriptValueP& value) { return *value; }
template <> inline Color from_script<Color> (const ScriptValueP& value) { return *value; }
template <> inline Color from_script<Color> (const ScriptValueP& value) { return (AColor)*value; }
template <> inline AColor from_script<AColor> (const ScriptValueP& value) { return *value; }
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -18,7 +18,7 @@
ScriptValue::operator String() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("string" ))); }
ScriptValue::operator int() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("integer" ))); }
ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("double" ))); }
ScriptValue::operator Color() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); }
ScriptValue::operator AColor() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); }
ScriptValueP ScriptValue::eval(Context&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); }
ScriptValueP ScriptValue::getMember(const String& name) const { return delayError(_ERROR_2_("has no member", typeName(), name)); }
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
......@@ -38,7 +38,7 @@ String ScriptDelayedError::typeName() const { throw error; }
ScriptDelayedError::operator String() const { throw error; }
ScriptDelayedError::operator double() const { throw error; }
ScriptDelayedError::operator int() const { throw error; }
ScriptDelayedError::operator Color() const { throw error; }
ScriptDelayedError::operator AColor() const { throw error; }
int ScriptDelayedError::itemCount() const { throw error; }
const void* ScriptDelayedError::comparePointer() const { throw error; }
ScriptValueP ScriptDelayedError::getMember(const String&) const { return new_intrusive1<ScriptDelayedError>(error); }
......@@ -191,18 +191,12 @@ class ScriptString : public ScriptValue {
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("integer")));
}
}
virtual operator Color() const {
UInt r,g,b;
if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) {
return Color(r, g, b);
} else {
// color from database?
Color c(value);
if (!c.Ok()) {
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("color")));
}
return c;
virtual operator AColor() const {
AColor c = parse_acolor(value);
if (!c.Ok()) {
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("color")));
}
return c;
}
virtual int itemCount() const { return (int)value.size(); }
virtual ScriptValueP getMember(const String& name) const {
......@@ -225,23 +219,26 @@ ScriptValueP to_script(const String& v) {
// ----------------------------------------------------------------------------- : Color
// Color values
class ScriptColor : public ScriptValue {
// AColor values
class ScriptAColor : public ScriptValue {
public:
ScriptColor(const Color& v) : value(v) {}
ScriptAColor(const AColor& v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLOR; }
virtual String typeName() const { return _TYPE_("color"); }
virtual operator Color() const { return value; }
virtual operator AColor() const { return value; }
virtual operator int() const { return (value.Red() + value.Blue() + value.Green()) / 3; }
virtual operator String() const {
return String::Format(_("rgb(%u,%u,%u)"), value.Red(), value.Green(), value.Blue());
return format_acolor(value);
}
private:
Color value;
AColor value;
};
ScriptValueP to_script(const Color& v) {
return new_intrusive1<ScriptColor>(v);
ScriptValueP to_script(Color v) {
return new_intrusive1<ScriptAColor>(v);
}
ScriptValueP to_script(AColor v) {
return new_intrusive1<ScriptAColor>(v);
}
......
......@@ -10,6 +10,7 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <gfx/color.hpp>
class Context;
class Dependency;
......@@ -55,7 +56,7 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
/// Convert this value to a boolean
inline operator bool() const { return (int)*this; }
/// Convert this value to a color
virtual operator Color() const;
virtual operator AColor() const;
/// Explicit overload to convert to a string
/** This is sometimes necessary, because wxString has an int constructor,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment