diff --git a/doc/script/introduction.txt b/doc/script/introduction.txt index b98eac44..4ec20585 100644 --- a/doc/script/introduction.txt +++ b/doc/script/introduction.txt @@ -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. diff --git a/doc/type/font.txt b/doc/type/font.txt index 03e73382..f52bf454 100644 --- a/doc/type/font.txt +++ b/doc/type/font.txt @@ -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 @""@ tags inserted by the [[fun:combined_editor]] function. diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp index 368e087f..f9eb8b1e 100644 --- a/src/data/keyword.cpp +++ b/src/data/keyword.cpp @@ -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 { diff --git a/src/data/keyword.hpp b/src/data/keyword.hpp index 07d08433..6cc993f9 100644 --- a/src/data/keyword.hpp +++ b/src/data/keyword.hpp @@ -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; }; diff --git a/src/gfx/color.cpp b/src/gfx/color.cpp index 83f75692..58e06e68 100644 --- a/src/gfx/color.cpp +++ b/src/gfx/color.cpp @@ -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) { diff --git a/src/gfx/color.hpp b/src/gfx/color.hpp index 6d1d66a2..6b1d39b8 100644 --- a/src/gfx/color.hpp +++ b/src/gfx/color.hpp @@ -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 diff --git a/src/script/context.cpp b/src/script/context.cpp index 887375cb..c8499dce 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -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) { diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 88fd0fd0..7427df84 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -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 (...) { diff --git a/src/script/parser.cpp b/src/script/parser.cpp index 142def72..892c928c 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -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; diff --git a/src/script/script.cpp b/src/script/script.cpp index c629b6e3..39426111 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -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; diff --git a/src/script/script.hpp b/src/script/script.hpp index 712b58b9..5ac5a891 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -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; }; }; diff --git a/src/script/scriptable.cpp b/src/script/scriptable.cpp index 5440c701..caf96cc9 100644 --- a/src/script/scriptable.cpp +++ b/src/script/scriptable.cpp @@ -12,6 +12,7 @@ #include