ext/wxColor.cpp

Summary

Maintainability
Test Coverage
/*
 * wxColor.cpp
 *
 *  Created on: 15.02.2012
 *      Author: hanmac
 */

#include "wxColor.hpp"
#include "wxApp.hpp"

#define _self unwrap<wxColor*>(self)

VALUE rb_cWXColor;
ID rwxID_red,rwxID_blue,rwxID_green,rwxID_alpha;

template <>
VALUE wrap< wxColor >(const wxColor& color )
{
    if(!color.IsOk())
        return Qnil;
    return wrapTypedPtr(new wxColor(color), rb_cWXColor);
}
template <>
VALUE wrap< wxColor >(wxColor *color )
{
    return wrapTypedPtr(color, rb_cWXColor);
}

template <>
bool is_wrapable< wxColor >(const VALUE &vcolor)
{
    if(rb_obj_is_kind_of(vcolor, rb_cWXColor) || RB_FIXNUM_P(vcolor)){
        return true;
    }else if(rb_obj_is_kind_of(vcolor, rb_cString)){
        wxLogNull logNo;
        wxString name(unwrap<wxString>(vcolor));
        wxColor col(name);
        return col.IsOk();
    }
    else if(rb_respond_to(vcolor,rwxID_red) &&
        rb_respond_to(vcolor,rwxID_blue) &&
        rb_respond_to(vcolor,rwxID_green)){
        return true;
    }else
        return false;
}

template <>
wxColor* unwrap< wxColor* >(const VALUE &vcolor)
{
    return unwrapTypedPtr<wxColor>(vcolor, rb_cWXColor);
}

char to_col_part(const VALUE &val)
{
    if(RB_FIXNUM_P(val))
        return RB_NUM2CHR(val);
    else
        return NUM2DBL(val) * 256;
}

void set_color_part(char& cv,const VALUE &val, const ID &id)
{
    cv = to_col_part(rb_funcall(val,id,0));
}

void set_color_part_hash(char& cv,const VALUE &val, const ID &id)
{
    VALUE tmp;
    if((tmp = rb_hash_aref(val, RB_ID2SYM(id))) != Qnil)
        cv = to_col_part(tmp);
}

void set_color_part_array(char& cv,const VALUE &val, size_t idx)
{
    cv = to_col_part(RARRAY_AREF(val, idx));
}



template <>
wxColor unwrap< wxColor >(const VALUE &vcolor)
{
    //NULLColor is not wanted
    //    if(NIL_P(vcolor))
    //        return wxNullColour;

    if(RB_SYMBOL_P(vcolor)) {
        app_protected();
        wxSystemColour sys = unwrapenum<wxSystemColour>(vcolor);
        wxColor col = wxSystemSettings::GetColour(sys);
        if(!col.IsOk())
            not_valid(vcolor,rb_cWXColor);
        return col;
    }else if(rb_obj_is_kind_of(vcolor, rb_cString)){
        wxLogNull logNo;
        wxString name(unwrap<wxString>(vcolor));
        wxColor col(name);
        if(!col.IsOk())
            not_valid(vcolor,rb_cWXColor);
        return col;
    }else if(RB_FIXNUM_P(vcolor))
        return wxColor(RB_FIX2LONG(vcolor));
    else if(rb_obj_is_kind_of(vcolor, rb_cArray) && RARRAY_LEN(vcolor) >= 3 &&
        RARRAY_LEN(vcolor) <= 4){
        char red,green,blue,alpha(wxALPHA_OPAQUE);
        wxColor color;
        set_color_part_array(red, vcolor, 0);
        set_color_part_array(green, vcolor, 1);
        set_color_part_array(blue, vcolor, 2);

        if(RARRAY_LEN(vcolor) == 4) {
            set_color_part_array(alpha, vcolor, 3);
        }

        color.Set(red, green, blue, alpha);
        return color;
    }else if(rb_obj_is_kind_of(vcolor, rb_cHash)){
        char red,green,blue,alpha(wxALPHA_OPAQUE);
        wxColor color;

        set_color_part_hash(red, vcolor, rwxID_red);
        set_color_part_hash(green, vcolor, rwxID_green);
        set_color_part_hash(blue, vcolor, rwxID_blue);

        set_color_part_hash(alpha, vcolor, rwxID_alpha);

        color.Set(red, green, blue, alpha);
        return color;
    }else if(!rb_obj_is_kind_of(vcolor, rb_cWXColor) &&
        rb_respond_to(vcolor,rwxID_red) &&
        rb_respond_to(vcolor,rwxID_green) &&
        rb_respond_to(vcolor,rwxID_blue)){
        char red,green,blue,alpha(wxALPHA_OPAQUE);
        wxColor color;

        set_color_part(red, vcolor, rwxID_red);
        set_color_part(green, vcolor, rwxID_green);
        set_color_part(blue, vcolor, rwxID_blue);

        if(rb_respond_to(vcolor,rwxID_alpha)) {
            set_color_part(alpha, vcolor, rwxID_alpha);
        }

        color.Set(red, green, blue, alpha);

        return color;
    }else{
        wxColor *col = unwrap<wxColor*>(vcolor);
        if(!col || !col->IsOk())
            not_valid(vcolor,rb_cWXColor);
        return *col;
    }


}

namespace RubyWX {
namespace Color {
DLL_LOCAL VALUE _alloc(VALUE self) {
    return wrapTypedPtr(new wxColor,self);
}

void define_const()
{
#if 0
    rb_mWX = rb_define_module("WX");
    rb_cWXColor = rb_define_class_under(rb_mWX,"Color",rb_cObject);
#endif

    if(rb_const_defined(rb_cWXColor,rb_intern("BLACK")))
        return;

    rb_define_const(rb_cWXColor,"BLACK",wrap(wxBLACK));
    rb_define_const(rb_cWXColor,"BLUE",wrap(wxBLUE));
    rb_define_const(rb_cWXColor,"CYAN",wrap(wxCYAN));
    rb_define_const(rb_cWXColor,"GREEN",wrap(wxGREEN));
    rb_define_const(rb_cWXColor,"YELLOW",wrap(wxYELLOW));
    rb_define_const(rb_cWXColor,"LIGHT_GREY",wrap(wxLIGHT_GREY));
    rb_define_const(rb_cWXColor,"RED",wrap(wxRED));
    rb_define_const(rb_cWXColor,"WHITE",wrap(wxWHITE));
}

DLL_LOCAL void init_values(wxColor *self, char &red, char &green, char &blue, char &alpha)
{
    if(self->IsOk()) {
        red = self->Red();
        green = self->Green();
        blue = self->Blue();
        alpha = self->Alpha();
    }
}

DLL_LOCAL char val_to_char(VALUE val)
{
    char cval(0);
    if(RB_FIXNUM_P(val))
        cval = RB_NUM2CHR(val);
    else
        cval = NUM2DBL(val) * 256;
    return cval;
}

#define attr(name,val) DLL_LOCAL VALUE _get##name(VALUE self)\
{\
    if(_self->IsOk())\
        return RB_CHR2FIX(_self->name());\
    else\
        return RB_CHR2FIX(0);\
}\
DLL_LOCAL VALUE _set##name(VALUE self,VALUE cval)\
{\
    rb_check_frozen(self);\
\
    char red(0), green(0), blue(0), alpha(0);\
    init_values(_self, red, green, blue, alpha);\
    val = val_to_char(cval);\
    _self->Set(red, green, blue, alpha);\
\
    return val;\
}

attr(Red,red)
attr(Green,green)
attr(Blue,blue)

DLL_LOCAL VALUE _getAlpha(VALUE self)
{
    if(_self->IsOk())
        return RB_CHR2FIX(_self->Alpha());
    else
        return RB_CHR2FIX(0);
}

DLL_LOCAL VALUE _setAlpha(VALUE self,VALUE val)
{
    rb_check_frozen(self);

    char red(0), green(0), blue(0), alpha(0);

    init_values(_self, red, green, blue, alpha);

    if(!RTEST(val))
        alpha = wxALPHA_OPAQUE;
    else if(val == Qtrue)
        alpha = wxALPHA_TRANSPARENT;
    else
        alpha = val_to_char(val);

    _self->Set(red, green, blue, alpha);
    return val;
}

DLL_LOCAL VALUE _tos(VALUE self)
{
    return wrap(wxToString(*_self));
}

DLL_LOCAL VALUE _get_name(VALUE self)
{
    if(wxColourDatabase *database = wxTheColourDatabase) {
        wxString name(database->FindName(*_self).MakeLower());
        if(name.empty())
            return Qnil;
        return wrap(name);
    }
    return Qnil;
}


DLL_LOCAL VALUE _set_name(VALUE self, VALUE name)
{
    if(wxColourDatabase *database = wxTheColourDatabase) {
        database->AddColour(unwrap<wxString>(name), unwrap<wxColor>(self));
    }else
        return Qnil;
    return self;
}

/*
 * call-seq:
 *   Color.new(red,green,blue[,alpha])
 *
 * creates a new Color Object.
*/
DLL_LOCAL VALUE _initialize(int argc,VALUE *argv,VALUE self)
{
    VALUE red,green,blue,alpha;
    rb_scan_args(argc, argv, "31",&red,&green,&blue,&alpha);
    _setRed(self,red);
    _setGreen(self,green);
    _setBlue(self,blue);
    _setAlpha(self, alpha);
    return self;
}

/* Document-method: initialize_copy
 * call-seq:
 *   initialize_copy(orig)
 *
 * Duplicate an object
*/
DLL_LOCAL VALUE _initialize_copy(VALUE self, VALUE other)
{
    VALUE result = rb_call_super(1,&other);
    _setRed(self,_getRed(other));
    _setGreen(self,_getGreen(other));
    _setBlue(self,_getBlue(other));
    _setAlpha(self,_getAlpha(other));
    return result;
}

/*
 * call-seq:
 *   inspect -> String
 *
 * Human-readable description.
 * ===Return value
 * String
*/
DLL_LOCAL VALUE _inspect(VALUE self)
{
    return rb_sprintf( "%s(%d, %d, %d, %d)",
        rb_obj_classname( self ),
        RB_FIX2INT(_getRed(self)),
        RB_FIX2INT(_getGreen(self)),
        RB_FIX2INT(_getBlue(self)),
        RB_FIX2INT(_getAlpha(self))
    );
}

/*
 * call-seq:
 *   marshal_dump -> Array
 *
 * Provides marshalling support for use by the Marshal library.
 * ===Return value
 * Array
 */
DLL_LOCAL VALUE _marshal_dump(VALUE self)
{
    VALUE ptr[4];
    ptr[0] = _getRed(self);
    ptr[1] = _getGreen(self);
    ptr[2] = _getBlue(self);
    ptr[3] = _getAlpha(self);
    return rb_ary_new4(4, ptr);
}

/*
 * call-seq:
 *   marshal_load(array) -> nil
 *
 * Provides marshalling support for use by the Marshal library.
 *
 *
 */
DLL_LOCAL VALUE _marshal_load(VALUE self, VALUE data)
{
    data = rb_Array(data);
    _setRed(self, RARRAY_AREF(data,0));
    _setGreen(self, RARRAY_AREF(data,1));
    _setBlue(self, RARRAY_AREF(data,2));
    _setAlpha(self, RARRAY_AREF(data,3));
    return Qnil;
}


/*
 * call-seq:
 *   hash -> Fixnum
 *
 * Generates a Fixnum hash value for this object.
 *
 *
 */
DLL_LOCAL VALUE _getHash(VALUE self)
{
    st_index_t h = rb_hash_start(_self->IsOk());
//  h = rb_hash_uint(h, (st_index_t)rb_ary_hash);
    if(_self->IsOk()) {
        h = rb_hash_uint(h, _self->Red());
        h = rb_hash_uint(h, _self->Green());
        h = rb_hash_uint(h, _self->Blue());
        h = rb_hash_uint(h, _self->Alpha());
    } else {
        h = rb_hash_uint(h, 0);
        h = rb_hash_uint(h, 0);
        h = rb_hash_uint(h, 0);
        h = rb_hash_uint(h, 0);
    }

    h = rb_hash_end(h);
    return RB_LONG2FIX(h);
}

struct equal_obj {
    wxColor* self;
    VALUE other;
};

VALUE _equal_block(equal_obj *obj)
{
    return wrap(*obj->self == unwrap<wxColor>(obj->other));
}

/*
 * call-seq:
 *   == color -> bool
 *
 * compares two colors.
 *
 *
 */
DLL_LOCAL VALUE _equal(VALUE self, VALUE other)
{
    equal_obj obj;
    obj.self = _self;
    obj.other = other;

    return rb_rescue(
        RUBY_METHOD_FUNC(_equal_block),(VALUE)&obj,
        RUBY_METHOD_FUNC(_equal_rescue),Qnil
    );
}


DLL_LOCAL VALUE _class_get(VALUE self, VALUE name)
{
    wxColor col;
    if(RB_SYMBOL_P(name)) {
        if(ruby_app_inited)
            col = wxSystemSettings::GetColour(unwrapenum<wxSystemColour>(name));
    }else if(wxColourDatabase *database = wxTheColourDatabase) {
        col = database->Find(unwrap<wxString>(name));
    }
    if(col.IsOk())
        return wrap(col);
    return Qnil;
}

DLL_LOCAL VALUE _class_set(VALUE self, VALUE name, VALUE color)
{
    if(wxColourDatabase *database = wxTheColourDatabase) {
        database->AddColour(unwrap<wxString>(name), unwrap<wxColor>(color));
    }else
        return Qnil;
    return color;
}

}
}


/*
 * Document-class: WX::Color
 *
 * This class represents an Color.
*/

/* Document-attr: red
 * returns the red value of Color.
 */
/* Document-attr: blue
 * returns the blue value of Color.
 */
/* Document-attr: green
 * returns the green value of Color.
 */
/* Document-attr: alpha
 * returns the alpha value of Color.
 */
/* Document-attr: name
 * returns the name of the Color or nil if no name found
 */

/* Document-const: BLACK
 * predefined Color constant.
 */
/* Document-const: BLUE
 * predefined Color constant.
 */
/* Document-const: CYAN
 * predefined Color constant.
 */
/* Document-const: GREEN
 * predefined Color constant.
 */
/* Document-const: YELLOW
 * predefined Color constant.
 */
/* Document-const: LIGHT_GREY
 * predefined Color constant.
 */
/* Document-const: RED
 * predefined Color constant.
 */
/* Document-const: WHITE
 * predefined Color constant.
 */
DLL_LOCAL void Init_WXColor(VALUE rb_mWX)
{
#if 0
    rb_mWX = rb_define_module("WX");
#endif
    using namespace RubyWX::Color;
    rb_cWXColor = rb_define_class_under(rb_mWX,"Color",rb_cObject);

#if 0
    rb_define_attr(rb_cWXColor,"red",1,1);
    rb_define_attr(rb_cWXColor,"green",1,1);
    rb_define_attr(rb_cWXColor,"blue",1,1);
    rb_define_attr(rb_cWXColor,"alpha",1,1);
    rb_define_attr(rb_cWXColor,"name",1,1);

    rb_define_const(rb_cWXColor,"BLACK",wrap(wxBLACK));
    rb_define_const(rb_cWXColor,"BLUE",wrap(wxBLUE));
    rb_define_const(rb_cWXColor,"CYAN",wrap(wxCYAN));
    rb_define_const(rb_cWXColor,"GREEN",wrap(wxGREEN));
    rb_define_const(rb_cWXColor,"YELLOW",wrap(wxYELLOW));
    rb_define_const(rb_cWXColor,"LIGHT_GREY",wrap(wxLIGHT_GREY));
    rb_define_const(rb_cWXColor,"RED",wrap(wxRED));
    rb_define_const(rb_cWXColor,"WHITE",wrap(wxWHITE));
#endif

    rb_define_alloc_func(rb_cWXColor,_alloc);

    rb_define_method(rb_cWXColor,"initialize",RUBY_METHOD_FUNC(_initialize),-1);
    rb_define_private_method(rb_cWXColor,"initialize_copy",RUBY_METHOD_FUNC(_initialize_copy),1);


    rb_define_attr_method(rb_cWXColor,"red",_getRed,_setRed);
    rb_define_attr_method(rb_cWXColor,"green",_getGreen,_setGreen);
    rb_define_attr_method(rb_cWXColor,"blue",_getBlue,_setBlue);
    rb_define_attr_method(rb_cWXColor,"alpha",_getAlpha,_setAlpha);

    rb_define_attr_method(rb_cWXColor,"name",_get_name,_set_name);

    rb_define_method(rb_cWXColor,"to_s",RUBY_METHOD_FUNC(_tos),0);
    rb_define_method(rb_cWXColor,"inspect",RUBY_METHOD_FUNC(_inspect),0);

    rb_define_method(rb_cWXColor,"marshal_dump",RUBY_METHOD_FUNC(_marshal_dump),0);
    rb_define_method(rb_cWXColor,"marshal_load",RUBY_METHOD_FUNC(_marshal_load),1);

    rb_define_method(rb_cWXColor,"==",RUBY_METHOD_FUNC(_equal),1);
    rb_define_alias(rb_cWXColor,"eql?","==");

    rb_define_method(rb_cWXColor,"hash",RUBY_METHOD_FUNC(_getHash),0);

    rb_define_singleton_method(rb_cWXColor,"[]",RUBY_METHOD_FUNC(_class_get),1);
    rb_define_singleton_method(rb_cWXColor,"[]=",RUBY_METHOD_FUNC(_class_set),2);

    rwxID_red = rb_intern("red");
    rwxID_blue = rb_intern("blue");
    rwxID_green = rb_intern("green");
    rwxID_alpha = rb_intern("alpha");

    registerType<wxColor>(rb_cWXColor, true);
    
    //*
    registerEnum<wxSystemColour>("wxSystemColour")
        ->add(wxSYS_COLOUR_SCROLLBAR,"scrollbar")
        ->add(wxSYS_COLOUR_DESKTOP,"desktop")
        ->add(wxSYS_COLOUR_ACTIVECAPTION,"active_caption")
        ->add(wxSYS_COLOUR_INACTIVECAPTION,"inactive_caption")
        ->add(wxSYS_COLOUR_MENU,"menu")
        ->add(wxSYS_COLOUR_WINDOW,"window")
        ->add(wxSYS_COLOUR_WINDOWFRAME,"window_frame")
        ->add(wxSYS_COLOUR_MENUTEXT,"menu_text")
        ->add(wxSYS_COLOUR_WINDOWTEXT,"window_text")
        ->add(wxSYS_COLOUR_CAPTIONTEXT,"caption_text")
        ->add(wxSYS_COLOUR_ACTIVEBORDER,"active_border")
        ->add(wxSYS_COLOUR_INACTIVEBORDER,"inactive_border")
        ->add(wxSYS_COLOUR_APPWORKSPACE,"app_workspace")
        ->add(wxSYS_COLOUR_HIGHLIGHT,"highlight")
        ->add(wxSYS_COLOUR_HIGHLIGHTTEXT,"highlight_text")
        ->add(wxSYS_COLOUR_BTNFACE,"btn_face")
        ->add(wxSYS_COLOUR_BTNSHADOW,"btn_shadow")
        ->add(wxSYS_COLOUR_GRAYTEXT,"gray_text")
        ->add(wxSYS_COLOUR_BTNTEXT,"btn_text")
        ->add(wxSYS_COLOUR_INACTIVECAPTIONTEXT,"inactive_captiontext")
        ->add(wxSYS_COLOUR_BTNHIGHLIGHT,"btn_highlight")
        ->add(wxSYS_COLOUR_3DDKSHADOW,"threeD_shadow")
        ->add(wxSYS_COLOUR_3DLIGHT,"threeD_light")
        ->add(wxSYS_COLOUR_INFOTEXT,"info_text")
        ->add(wxSYS_COLOUR_INFOBK,"info_background")
        ->add(wxSYS_COLOUR_LISTBOX,"listbox")
        ->add(wxSYS_COLOUR_HOTLIGHT,"hotlight")
        ->add(wxSYS_COLOUR_GRADIENTACTIVECAPTION,"gradient_active_caption")
        ->add(wxSYS_COLOUR_GRADIENTINACTIVECAPTION,"gradient_inactive_caption")
        ->add(wxSYS_COLOUR_MENUHILIGHT,"menu_highlight")
        ->add(wxSYS_COLOUR_MENUBAR,"menubar")
        ->add(wxSYS_COLOUR_LISTBOXTEXT,"listbox_text")
        ->add(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT,"listbox_highlight_text");
    //*/
}