aboutsummaryrefslogblamecommitdiffstats
path: root/widgets/misc/e-canvas-background.c
blob: 9ee7d440ce5e578ba0a974eda7e967e47312b9e2 (plain) (tree)


















                                                                           

                                                                



                   

                  

                   
                           

                    
                       
                          


                                

                                
 


                                                              















                                                            
      






                                                








                             




                                 
                                                        



                                                                            














































                                                                                  

                                                                                                    



























                                                                                   
                                                            


                                             
                                               











                                                                      
                             


                                                              
                        
                                       
                                                            

                                          



                                   

                                                                    


           



                                      







                                         

                                           
 



                                                                             







                                                                
                                 
                                                   










                                                                

                                                           





                                                                       

                                                                    

                      

                                                           
                      

                                                           
                      

                                                           
                      

                                                           


















                                                                                         



                                    
 

                               
                                           
 

                                 
                                                                              
                      

                                                          
                      

                                                               
                      

                                                          
                      

                                                          
                      

                                                          
                      

                                                          

                      
                                                                           




                      
                                 
 

                                                                      



                                    












                                                            

                                                                           
















                                                                         
                                       

                             

                                                                             


























































                                                                                            


                                                                




                                                                                                                


           
                                                  
 

                                                                               
        


                                                       






                                                    

                                                    







                                                                                  




                                                                                   










                                                                                  
                                                                                  





























                                                                                    





                                                                                  
                                                          
                                                              

 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* 
 * e-canvas-background.c - background color for canvas.
 * Copyright 2001, Ximian, Inc.
 *
 * Authors:
 *   Chris Lahey <clahey@ximian.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License, version 2, as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#include <config.h>

#include <math.h>
#include <stdio.h>
#include <string.h>

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>

#include <glib/gi18n.h>
#include "e-util/e-util.h"
#include "misc/e-canvas.h"
#include "misc/e-canvas-utils.h"
#include "misc/e-hsv-utils.h"

#include "e-canvas-background.h"

/* workaround for avoiding API broken */
#define ecb_get_type e_canvas_background_get_type
G_DEFINE_TYPE (ECanvasBackground, ecb, GNOME_TYPE_CANVAS_ITEM)

#define d(x)

struct _ECanvasBackgroundPrivate {
    guint rgba;     /* Fill color, RGBA */
    GdkColor color;     /* Fill color */
    GdkBitmap *stipple; /* Stipple for fill */
    GdkGC *gc;          /* GC for filling */
    double x1;
    double x2;
    double y1;
    double y2;

    guint needs_redraw : 1;
};

enum {
    STYLE_SET,
    LAST_SIGNAL
};

static guint ecb_signals [LAST_SIGNAL] = { 0, };

enum {
    PROP_0,
    PROP_FILL_COLOR,
    PROP_FILL_COLOR_GDK,
    PROP_FILL_COLOR_RGBA,
    PROP_FILL_STIPPLE,
    PROP_X1,
    PROP_X2,
    PROP_Y1,
    PROP_Y2,
};

static void
get_color(ECanvasBackground *ecb)
{
    GnomeCanvasItem *item = GNOME_CANVAS_ITEM (ecb);
    ecb->priv->color.pixel = gnome_canvas_get_color_pixel (item->canvas,
        GNOME_CANVAS_COLOR (ecb->priv->color.red >> 8,
                   ecb->priv->color.green>> 8,
                   ecb->priv->color.blue>> 8));
}

static void
ecb_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
    double   i2c [6];
    ArtPoint c1, c2, i1, i2;
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);

    /* Wrong BBox's are the source of redraw nightmares */

    gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (ecb), i2c);
    
    i1.x = ecb->priv->x1;
    i1.y = ecb->priv->y1;
    i2.x = ecb->priv->x2;
    i2.y = ecb->priv->y2;
    art_affine_point (&c1, &i1, i2c);
    art_affine_point (&c2, &i2, i2c);

    if (ecb->priv->x1 < 0)
        c1.x = -(double)UINT_MAX;

    if (ecb->priv->y1 < 0)
        c1.y = -(double)UINT_MAX;

    if (ecb->priv->x2 < 0)
        c2.x = (double)UINT_MAX;

    if (ecb->priv->y2 < 0)
        c2.y = (double)UINT_MAX;

    *x1 = c1.x;
    *y1 = c1.y;
    *x2 = c2.x + 1;
    *y2 = c2.y + 1;
}

/*
 * GnomeCanvasItem::update method
 */
static void
ecb_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
    ArtPoint o1, o2;
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);

    if (GNOME_CANVAS_ITEM_CLASS (ecb_parent_class)->update)
        GNOME_CANVAS_ITEM_CLASS (ecb_parent_class)->update (item, affine, clip_path, flags);

    o1.x = item->x1;
    o1.y = item->y1;
    o2.x = item->x2;
    o2.y = item->y2;

    ecb_bounds (item, &item->x1, &item->y1, &item->x2, &item->y2);
    if (item->x1 != o1.x ||
        item->y1 != o1.y ||
        item->x2 != o2.x ||
        item->y2 != o2.y) {
        gnome_canvas_request_redraw (item->canvas, o1.x, o1.y, o2.x, o2.y);
        ecb->priv->needs_redraw = 1;
    }

    if (ecb->priv->needs_redraw) {
        gnome_canvas_request_redraw (item->canvas, item->x1, item->y1,
                         item->x2, item->y2);
        ecb->priv->needs_redraw = 0;
    }
}

/* Sets the stipple pattern for the text */
static void
set_stipple (ECanvasBackground *ecb, GdkBitmap *stipple, int use_value)
{
    if (use_value) {
        if (ecb->priv->stipple)
            g_object_unref (ecb->priv->stipple);

        ecb->priv->stipple = stipple;
        if (stipple)
            g_object_ref (stipple);
    }

    if (ecb->priv->gc) {
        if (stipple) {
            gdk_gc_set_stipple (ecb->priv->gc, stipple);
            gdk_gc_set_fill (ecb->priv->gc, GDK_STIPPLED);
        } else
            gdk_gc_set_fill (ecb->priv->gc, GDK_SOLID);
    }
}

static void
ecb_dispose (GObject *object)
{
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (object);

    if (ecb->priv) {
        if (ecb->priv->stipple)
            g_object_unref (ecb->priv->stipple);
        ecb->priv->stipple = NULL;

        g_free (ecb->priv);
        ecb->priv = NULL;
    }

    if (G_OBJECT_CLASS (ecb_parent_class)->dispose)
                G_OBJECT_CLASS (ecb_parent_class)->dispose (object);
}

static void
ecb_set_property (GObject *object,
          guint prop_id,
          const GValue *value,
          GParamSpec *pspec)
{
    GnomeCanvasItem *item;
    ECanvasBackground *ecb;

    GdkColor color = { 0, 0, 0, 0, };
    GdkColor *pcolor;
    gboolean color_changed = FALSE;

    item = GNOME_CANVAS_ITEM (object);
    ecb = E_CANVAS_BACKGROUND (object);

    switch (prop_id){
    case PROP_FILL_COLOR:
        if (g_value_get_string (value))
            gdk_color_parse (g_value_get_string (value), &color);

        ecb->priv->rgba = ((color.red & 0xff00) << 16 |
                   (color.green & 0xff00) << 8 |
                   (color.blue & 0xff00) |
                   0xff);
        color_changed = TRUE;
        break;

    case PROP_FILL_COLOR_GDK:
        pcolor = g_value_get_boxed (value);
        if (pcolor) {
            color = *pcolor;
        }

        ecb->priv->rgba = ((color.red & 0xff00) << 16 |
                   (color.green & 0xff00) << 8 |
                   (color.blue & 0xff00) |
                   0xff);
        color_changed = TRUE;
        break;

        case PROP_FILL_COLOR_RGBA:
        ecb->priv->rgba = g_value_get_uint (value);
        color.red = ((ecb->priv->rgba >> 24) & 0xff) * 0x101;
        color.green = ((ecb->priv->rgba >> 16) & 0xff) * 0x101;
        color.blue = ((ecb->priv->rgba >> 8) & 0xff) * 0x101;
        color_changed = TRUE;
        break;

    case PROP_FILL_STIPPLE:
        set_stipple (ecb, g_value_get_object (value), TRUE);
        break;

    case PROP_X1:
        ecb->priv->x1 = g_value_get_double (value);
        break;
    case PROP_X2:
        ecb->priv->x2 = g_value_get_double (value);
        break;
    case PROP_Y1:
        ecb->priv->y1 = g_value_get_double (value);
        break;
    case PROP_Y2:
        ecb->priv->y2 = g_value_get_double (value);
        break;
    }

    if (color_changed) {
        ecb->priv->color = color;

        if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(item)) {
            get_color (ecb);
            if (!item->canvas->aa) {
                gdk_gc_set_foreground (ecb->priv->gc, &ecb->priv->color);
            }
        }
    }

    ecb->priv->needs_redraw = 1;
    gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(ecb));
}

static void
ecb_get_property (GObject *object,
          guint prop_id,
          GValue *value,
          GParamSpec *pspec)
{
    ECanvasBackground *ecb;

    ecb = E_CANVAS_BACKGROUND (object);

    switch (prop_id){
    case PROP_FILL_COLOR_GDK:
        g_value_set_boxed (value, gdk_color_copy (&ecb->priv->color));
        break;
        case PROP_FILL_COLOR_RGBA:
        g_value_set_uint (value, ecb->priv->rgba);
        break;
    case PROP_FILL_STIPPLE:
        g_value_set_object (value, ecb->priv->stipple);
        break;
    case PROP_X1:
        g_value_set_double (value, ecb->priv->x1);
        break;
    case PROP_X2:
        g_value_set_double (value, ecb->priv->x2);
        break;
    case PROP_Y1:
        g_value_set_double (value, ecb->priv->y1);
        break;
    case PROP_Y2:
        g_value_set_double (value, ecb->priv->y2);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static void
ecb_init (ECanvasBackground *ecb)
{
    ecb->priv               = g_new (ECanvasBackgroundPrivate, 1);

    ecb->priv->color.pixel  = 0;
    ecb->priv->color.red    = 0;
    ecb->priv->color.green  = 0;
    ecb->priv->color.blue   = 0;
    ecb->priv->stipple      = NULL;
    ecb->priv->gc           = NULL;
    ecb->priv->x1           = -1.0;
    ecb->priv->x2           = -1.0;
    ecb->priv->y1           = -1.0;
    ecb->priv->y2           = -1.0;
}

static void
ecb_realize (GnomeCanvasItem *item)
{
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
    
    if (GNOME_CANVAS_ITEM_CLASS (ecb_parent_class)->realize)
                GNOME_CANVAS_ITEM_CLASS (ecb_parent_class)->realize (item);

    ecb->priv->gc = gdk_gc_new (item->canvas->layout.bin_window);
    get_color (ecb);
    if (!item->canvas->aa)
        gdk_gc_set_foreground (ecb->priv->gc, &ecb->priv->color);

    set_stipple (ecb, NULL, FALSE);
    
    ecb->priv->needs_redraw = 1;
    gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ecb));
}

static void
ecb_unrealize (GnomeCanvasItem *item)
{
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);

    g_object_unref (ecb->priv->gc);
    ecb->priv->gc = NULL;

    if (GNOME_CANVAS_ITEM_CLASS (ecb_parent_class)->unrealize)
                GNOME_CANVAS_ITEM_CLASS (ecb_parent_class)->unrealize (item);
}

static void
ecb_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
{
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);
    int x1, x2, y1, y2;
    double i2c [6];
    ArtPoint upper_left, lower_right, ecb_base_point;
    
    /*
     * Find out our real position after grouping
     */
    gnome_canvas_item_i2c_affine (item, i2c);
    ecb_base_point.x = ecb->priv->x1;
    ecb_base_point.y = ecb->priv->y1;
    art_affine_point (&upper_left, &ecb_base_point, i2c);

    ecb_base_point.x = ecb->priv->x2;
    ecb_base_point.y = ecb->priv->y2;
    art_affine_point (&lower_right, &ecb_base_point, i2c);

    x1 = 0;
    y1 = 0;
    x2 = width;
    y2 = height;
    if (ecb->priv->x1 >= 0 && upper_left.x > x1)
        x1 = upper_left.x;
    if (ecb->priv->y1 >= 0 && upper_left.y > y1)
        y1 = upper_left.y;
    if (ecb->priv->x2 >= 0 && lower_right.x < x2)
        x2 = lower_right.x;
    if (ecb->priv->y2 >= 0 && lower_right.y < y2)
        y2 = lower_right.y;

    gdk_draw_rectangle (drawable, ecb->priv->gc, TRUE,
                x1, y1, x2 - x1, y2 - y1);
}

static double
ecb_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
       GnomeCanvasItem **actual_item)
{
    ECanvasBackground *ecb = E_CANVAS_BACKGROUND (item);

    if (ecb->priv->x1 >= 0 && ecb->priv->x1 > x)
        return 1.0;
    if (ecb->priv->x2 >= 0 && ecb->priv->x2 < x)
        return 1.0;
    if (ecb->priv->y1 >= 0 && ecb->priv->y1 > y)
        return 1.0;
    if (ecb->priv->y2 >= 0 && ecb->priv->y2 < y)
        return 1.0;
    *actual_item = item;

    return 0.0;
}

static void
ecb_style_set (ECanvasBackground *ecb, GtkStyle *previous_style)
{
    GnomeCanvasItem *item = GNOME_CANVAS_ITEM (ecb);
        
    if (GTK_WIDGET_REALIZED (item->canvas)) {
        gdk_gc_set_foreground (ecb->priv->gc, &GTK_WIDGET(item->canvas)->style->base[GTK_STATE_NORMAL]);
        gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ecb));
    }
}

static void
ecb_class_init (ECanvasBackgroundClass *ecb_class)
{
    GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS (ecb_class);
    GObjectClass *object_class = G_OBJECT_CLASS (ecb_class);
    
    object_class->dispose       = ecb_dispose;
    object_class->set_property  = ecb_set_property;
    object_class->get_property  = ecb_get_property;

    item_class->update          = ecb_update;
    item_class->realize         = ecb_realize;
    item_class->unrealize       = ecb_unrealize;
    item_class->draw            = ecb_draw;
    item_class->point           = ecb_point;

    ecb_class->style_set        = ecb_style_set;

    g_object_class_install_property (object_class, PROP_FILL_COLOR,
                     g_param_spec_string ("fill_color",
                                  _( "Fill color" ),
                                  _( "Fill color" ),
                                  NULL,
                                  G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_FILL_COLOR_GDK,
                     g_param_spec_boxed ("fill_color_gdk",
                                 _( "GDK fill color" ),
                                 _( "GDK fill color" ),
                                 GDK_TYPE_COLOR,
                                 G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_FILL_COLOR_RGBA,
                     g_param_spec_uint ("fill_color_rgba",
                                _( "GDK fill color" ),
                                _( "GDK fill color" ),
                                0, G_MAXUINT, 0,
                                G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_FILL_STIPPLE,
                     g_param_spec_object ("fill_stipple",
                                  _( "Fill stipple" ),
                                  _( "Fill stipple" ),
                                  GDK_TYPE_WINDOW,
                                  G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_X1,
                     g_param_spec_double ("x1",
                                  _( "X1" ),
                                  _( "X1" ),
                                  0.0, G_MAXDOUBLE, 0.0,
                                  G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_X2,
                     g_param_spec_double ("x2",
                                  _( "X2" ),
                                  _( "X2" ),
                                  0.0, G_MAXDOUBLE, 0.0,
                                  G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_Y1,
                     g_param_spec_double ("y1",
                                  _( "Y1" ),
                                  _( "Y1" ),
                                  0.0, G_MAXDOUBLE, 0.0,
                                  G_PARAM_READWRITE));

    g_object_class_install_property (object_class, PROP_Y2,
                     g_param_spec_double ("y2",
                                  _( "Y2" ),
                                  _( "Y2" ),
                                  0.0, G_MAXDOUBLE, 0.0,
                                  G_PARAM_READWRITE));
    ecb_signals [STYLE_SET] =
        g_signal_new ("style_set",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (ECanvasBackgroundClass, style_set),
                  NULL, NULL,
                  e_util_marshal_NONE__OBJECT,
                  G_TYPE_NONE, 1, GTK_TYPE_STYLE);
}