Example #1
0
static gboolean
gnucash_grid_find_cell_by_pixel (GnucashGrid *grid, gint x, gint y,
                                 VirtualLocation *virt_loc)
{
    SheetBlock *block;
    SheetBlockStyle *style;
    CellDimensions *cd;
    gint row = 0;
    gint col = 0;

    g_return_val_if_fail (virt_loc != NULL, FALSE);

    block = gnucash_sheet_get_block (grid->sheet, virt_loc->vcell_loc);
    if (block == NULL)
        return FALSE;

    /* now make x, y relative to the block origin */
    x -= block->origin_x;
    y -= block->origin_y;

    style = block->style;
    if (style == NULL)
        return FALSE;

    do
    {
        cd = gnucash_style_get_cell_dimensions (style, row, 0);

        if (y >= cd->origin_y && y < cd->origin_y + cd->pixel_height)
            break;

        row++;
    }
    while (row < style->nrows);

    if (row == style->nrows)
        return FALSE;

    do
    {
        cd = gnucash_style_get_cell_dimensions (style, row, col);

        if (x >= cd->origin_x && x < cd->origin_x + cd->pixel_width)
            break;

        col++;
    }
    while (col < style->ncols);

    if (col == style->ncols)
        return FALSE;

    if (virt_loc)
        virt_loc->phys_row_offset = row;
    if (virt_loc)
        virt_loc->phys_col_offset = col;

    return TRUE;
}
Example #2
0
static void
gnucash_cursor_get_pixel_coords (GnucashCursor *cursor,
                                 gint *x, gint *y,
                                 gint *w, gint *h)
{
    GnucashSheet *sheet = cursor->sheet;
    VirtualCellLocation vcell_loc;
    CellDimensions *cd;
    VirtualCell *vcell;
    SheetBlock *block;
    gint col;

    vcell_loc.virt_row = cursor->row;
    vcell_loc.virt_col = cursor->col;

    block = gnucash_sheet_get_block (sheet, vcell_loc);
    if (!block)
        return;

    vcell = gnc_table_get_virtual_cell (sheet->table, vcell_loc);
    if (!vcell)
        return;

    for (col = 0; col < vcell->cellblock->num_cols; col++)
    {
        BasicCell *cell;

        cell = gnc_cellblock_get_cell (vcell->cellblock, 0, col);
        if (cell && cell->cell_name)
            break;
    }

    *y = block->origin_y;

    cd = gnucash_style_get_cell_dimensions (block->style, 0, col);
    if (cd)
        *x = cd->origin_x;
    else
        *x = block->origin_x;

    for (col = vcell->cellblock->num_cols - 1; col >= 0; col--)
    {
        BasicCell *cell;

        cell = gnc_cellblock_get_cell (vcell->cellblock, 0, col);
        if (cell && cell->cell_name)
            break;
    }

    *h = block->style->dimensions->height;

    cd = gnucash_style_get_cell_dimensions (block->style, 0, col);
    if (cd)
        *w = cd->origin_x + cd->pixel_width - *x;
    else
        *w = block->style->dimensions->width - *x;
}
Example #3
0
static int
find_resize_col (GncHeader *header, int col)
{
    SheetBlockStyle *style = header->style;
    CellDimensions *cd;
    int start = col;

    if (col < 0 || col >= style->ncols)
        return -1;

    /* skip to the right over zero-width columns */
    while ((col + 1 < style->ncols) &&
            (cd = gnucash_style_get_cell_dimensions (style, 0, col + 1)) &&
            (cd->pixel_width == 0))
        col++;

    /* now go back left till we have a resizable column */
    while (col >= start)
    {
        if (gnucash_style_col_is_resizable (style, col))
            return col;
        else
            col--;
    }

    /* didn't find a resizable column to the right of col */
    return -1;
}
Example #4
0
/*
 *  Returns FALSE if pointer not on a resize line, else returns
 *  TRUE. Returns the index of the column to the left in the col
 *  argument.
 */
static gboolean
pointer_on_resize_line (GncHeader *header, int x, int y, int *col)
{
    SheetBlockStyle *style = header->style;
    gboolean on_the_line = FALSE;
    CellDimensions *cd;
    int pixels = 0;
    int j;

    for (j = 0; j < style->ncols; j++)
    {
        cd = gnucash_style_get_cell_dimensions (style, 0, j);
        pixels += cd->pixel_width;
        if (x >= pixels - 1 && x <= pixels + 1)
            on_the_line = TRUE;
        if (x <= pixels + 1)
            break;
    }

    if (col != NULL)
        *col = j;

    return on_the_line;
}
Example #5
0
static void
gnc_header_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
                 int x, int y, int width, int height)
{
    GncHeader *header = GNC_HEADER(item);
    SheetBlockStyle *style = header->style;
    Table *table = header->sheet->table;
    VirtualLocation virt_loc;
    VirtualCell *vcell;
    CellDimensions *cd;
    GdkColor *bg_color;
    int xpaint, ypaint;
    const char *text;
    CellBlock *cb;
    guint32 argb, color_type;
    int i, j;
    int w, h;
    PangoLayout *layout;

    virt_loc.vcell_loc.virt_row = 0;
    virt_loc.vcell_loc.virt_col = 0;
    virt_loc.phys_row_offset = 0;
    virt_loc.phys_col_offset = 0;

    if (header->sheet->use_theme_colors)
    {
        color_type = gnc_table_get_gtkrc_bg_color (table, virt_loc,
                     NULL);
        bg_color = get_gtkrc_color(header->sheet, color_type);
    }
    else
    {
        argb = gnc_table_get_bg_color (table, virt_loc, NULL);
        bg_color = gnucash_color_argb_to_gdk (argb);
    }

    h = style->dimensions->height;
    h *= header->num_phys_rows;
    h /= header->style->nrows;

    gdk_gc_set_foreground (header->gc, bg_color);

    gdk_draw_rectangle (drawable, header->gc, TRUE, 0, 0,
                        style->dimensions->width, h);

    gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
    gdk_gc_set_foreground (header->gc, &gn_black);

    gdk_draw_rectangle (drawable, header->gc, FALSE, -x, -y,
                        style->dimensions->width, h);

    gdk_draw_line (drawable, header->gc, 0, h + 1,
                   style->dimensions->width, h + 1);

    gdk_gc_set_line_attributes (header->gc, 1, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
    gdk_gc_set_background (header->gc, &gn_white);
    gdk_gc_set_foreground (header->gc, &gn_black);
    /*font = gnucash_register_font;*/

    vcell = gnc_table_get_virtual_cell
            (table, table->current_cursor_loc.vcell_loc);
    cb = vcell ? vcell->cellblock : NULL;

    ypaint = -y;
    h = 0;

    for (i = 0; i < style->nrows; i++)
    {
        xpaint = -x;
        virt_loc.phys_row_offset = i;

        /* TODO: This routine is duplicated in several places.
           Can we abstract at least the cell drawing routine?
           That way we'll be sure everything is drawn
           consistently, and cut down on maintenance issues. */

        for (j = 0; j < style->ncols; j++)
        {
            /*                        gint x_offset, y_offset;*/
            GdkRectangle rect;
            BasicCell *cell;

            virt_loc.phys_col_offset = j;

            cd = gnucash_style_get_cell_dimensions (style, i, j);

            if (header->in_resize && (j == header->resize_col))
                w = header->resize_col_width;
            else
                w = cd->pixel_width;

            cell = gnc_cellblock_get_cell (cb, i, j);
            if (!cell || !cell->cell_name)
            {
                xpaint += w;
                continue;
            }

            h = cd->pixel_height;

            gdk_draw_rectangle (drawable, header->gc, FALSE,
                                xpaint, ypaint, w, h);

            virt_loc.vcell_loc =
                table->current_cursor_loc.vcell_loc;
            text = gnc_table_get_label (table, virt_loc);
            if (!text)
                text = "";

            layout = gtk_widget_create_pango_layout (GTK_WIDGET (header->sheet), text);

            /*y_offset = ((h / 2) +
                                    (((font->ascent + font->descent) / 2) -
                                     font->descent));
                        y_offset++;*/

            switch (gnc_table_get_align (table, virt_loc))
            {
            default:
            case CELL_ALIGN_LEFT:
                pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
                break;

            case CELL_ALIGN_RIGHT:
                pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
                break;

            case CELL_ALIGN_CENTER:
                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
                break;
            }

            rect.x = xpaint + CELL_HPADDING;
            rect.y = ypaint + 1;
            rect.width = MAX (0, w - (2 * CELL_HPADDING));
            rect.height = h - 2;

            gdk_gc_set_clip_rectangle (header->gc, &rect);

            gdk_draw_layout (drawable,
                             header->gc,
                             xpaint + CELL_HPADDING,
                             ypaint + 1,
                             layout);

            g_object_unref (layout);

            gdk_gc_set_clip_rectangle (header->gc, NULL);

            xpaint += w;
        }

        ypaint += h;
    }
}
Example #6
0
static gint
gnc_header_event (GnomeCanvasItem *item, GdkEvent *event)
{
    GncHeader *header = GNC_HEADER(item);
    GnomeCanvas *canvas = item->canvas;
    int x, y;
    int col;

    switch (event->type)
    {
    case GDK_MOTION_NOTIFY:

        gnome_canvas_w2c (canvas, event->motion.x, event->motion.y,
                          &x, &y);

        if (header->in_resize)
        {
            int change = x - header->resize_x;
            int new_width;

            if (!header->needs_ungrab)
            {
                gnome_canvas_item_grab (item,
                                        GDK_POINTER_MOTION_MASK |
                                        GDK_BUTTON_RELEASE_MASK,
                                        header->resize_cursor,
                                        event->button.time);
                header->needs_ungrab = TRUE;
            }

            new_width = header->resize_col_width + change;

            if (new_width >= 0)
            {
                header->resize_x = x;
                header->resize_col_width = new_width;
                gnc_header_request_redraw (header);
            }

            break;
        }

        if (pointer_on_resize_line(header, x, y, &col) &&
                gnucash_style_col_is_resizable (header->style, col))
            gdk_window_set_cursor (GTK_WIDGET(canvas)->window,
                                   header->resize_cursor);
        else
            gdk_window_set_cursor (GTK_WIDGET(canvas)->window,
                                   header->normal_cursor);
        break;

    case GDK_BUTTON_PRESS:
    {
        int col;

        if (event->button.button != 1)
            break;

        gnome_canvas_w2c (canvas, event->button.x, event->button.y,
                          &x, &y);

        if (pointer_on_resize_line (header, x, y, &col))
            col = find_resize_col (header, col);
        else
            col = -1;

        if (col > -1)
        {
            CellDimensions *cd;

            cd = gnucash_style_get_cell_dimensions
                 (header->style, 0, col);

            header->in_resize = TRUE;
            header->resize_col = col;
            header->resize_col_width = cd->pixel_width;
            header->resize_x = x;
        }

        break;
    }
    case GDK_BUTTON_RELEASE:
    {
        if (event->button.button != 1)
            break;

        gnome_canvas_w2c (canvas, event->button.x, event->button.y,
                          &x, &y);

        if (header->in_resize)
        {
            if (header->needs_ungrab)
            {
                gnome_canvas_item_ungrab (item,
                                          event->button.time);
                header->needs_ungrab = FALSE;

                gnc_header_resize_column
                (header,
                 header->resize_col,
                 header->resize_col_width);
            }
            header->in_resize = FALSE;
            header->resize_col = -1;
        }

        break;
    }

    case GDK_2BUTTON_PRESS:
    {
        gboolean on_line;
        int ptr_col;
        int resize_col;

        if (event->button.button != 1)
            break;

        gnome_canvas_w2c (canvas, event->button.x, event->button.y,
                          &x, &y);

        on_line = pointer_on_resize_line (header, x, y, &ptr_col);

        /* If we're on a resize line and the column to the right is zero
           width, resize that one. */
        if (on_line)
            resize_col = find_resize_col (header, ptr_col);
        else
            resize_col = ptr_col;

        if (resize_col > -1)
        {
            header->in_resize = FALSE;
            header->resize_col = -1;
            if (header->needs_ungrab)
            {
                gnome_canvas_item_ungrab (item,
                                          event->button.time);
                header->needs_ungrab = FALSE;
            }

            gnc_header_auto_resize_column (header, resize_col);
        }

    }
    break;

    default:
        break;
    }

    return TRUE;
}
static void
gnc_header_draw_offscreen (GncHeader *header)
{
    SheetBlockStyle *style = header->style;
    Table *table = header->sheet->table;
    VirtualLocation virt_loc;
    VirtualCell *vcell;
    guint32 color_type;
    GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET(header));
    GdkRGBA color;
    int row_offset;
    CellBlock *cb;
    int i;
    cairo_t *cr;

    virt_loc.vcell_loc.virt_row = 0;
    virt_loc.vcell_loc.virt_col = 0;
    virt_loc.phys_row_offset = 0;
    virt_loc.phys_col_offset = 0;

    gtk_style_context_save (stylectxt);

    // Get the background color type and apply the css class
    color_type = gnc_table_get_bg_color (table, virt_loc, NULL);
    gnucash_get_style_classes (header->sheet, stylectxt, color_type);

    if (header->surface)
        cairo_surface_destroy (header->surface);
    header->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                header->width,
                                                header->height);

    cr = cairo_create (header->surface);

    // Fill background color of header
    gtk_render_background (stylectxt, cr, 0, 0, header->width, header->height);

    gdk_rgba_parse (&color, "black");
    cairo_set_source_rgb (cr, color.red, color.green, color.blue);
    cairo_rectangle (cr, 0.5, 0.5, header->width - 1.0, header->height - 1.0);
    cairo_set_line_width (cr, 1.0);
    cairo_stroke (cr);

    // Draw bottom horizontal line, makes bottom line thicker
    cairo_move_to (cr, 0.5, header->height - 1.5);
    cairo_line_to (cr, header->width - 1.0, header->height - 1.5);
    cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
    cairo_set_line_width (cr, 1.0);
    cairo_stroke (cr);

    /*font = gnucash_register_font;*/

    vcell = gnc_table_get_virtual_cell
            (table, table->current_cursor_loc.vcell_loc);
    cb = vcell ? vcell->cellblock : NULL;
    row_offset = 0;

    for (i = 0; i < style->nrows; i++)
    {
        int col_offset = 0;
        int h = 0, j;
        virt_loc.phys_row_offset = i;

        /* TODO: This routine is duplicated in several places.
           Can we abstract at least the cell drawing routine?
           That way we'll be sure everything is drawn
           consistently, and cut down on maintenance issues. */

        for (j = 0; j < style->ncols; j++)
        {
            CellDimensions *cd;
            double text_x, text_y, text_w, text_h;
            BasicCell *cell;
            const char *text;
            int w;
            PangoLayout *layout;

            virt_loc.phys_col_offset = j;

            cd = gnucash_style_get_cell_dimensions (style, i, j);
            h = cd->pixel_height;
            if (header->in_resize && (j == header->resize_col))
                w = header->resize_col_width;
            else
                w = cd->pixel_width;

            cell = gnc_cellblock_get_cell (cb, i, j);
            if (!cell || !cell->cell_name)
            {
                col_offset += w;
                continue;
            }

            cairo_rectangle (cr, col_offset - 0.5, row_offset + 0.5, w, h);
            cairo_set_line_width (cr, 1.0);
            cairo_stroke (cr);

            virt_loc.vcell_loc =
                table->current_cursor_loc.vcell_loc;
            text = gnc_table_get_label (table, virt_loc);
            if (!text)
                text = "";

            layout = gtk_widget_create_pango_layout (GTK_WIDGET (header->sheet), text);
            switch (gnc_table_get_align (table, virt_loc))
            {
            default:
            case CELL_ALIGN_LEFT:
                pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
                break;

            case CELL_ALIGN_RIGHT:
                pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
                break;

            case CELL_ALIGN_CENTER:
                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
                break;
            }

            text_x = col_offset + CELL_HPADDING;
            text_y = row_offset + 1;
            text_w = MAX (0, w - (2 * CELL_HPADDING));
            text_h = h - 2;
            cairo_save (cr);
            cairo_rectangle (cr, text_x, text_y, text_w, text_h);
            cairo_clip (cr);

            gtk_render_layout (stylectxt, cr, text_x, text_y, layout);

            cairo_restore (cr);
            g_object_unref (layout);

            col_offset += w;
        }
        row_offset += h;
    }
    gtk_style_context_restore (stylectxt);

    cairo_destroy (cr);
}
static gint
gnc_header_event (GtkWidget *widget, GdkEvent *event)
{
    GncHeader *header = GNC_HEADER(widget);
    int x, y;
    int col;

    switch (event->type)
    {
    case GDK_MOTION_NOTIFY:
        x = event->motion.x;
        y = event->motion.y;

        if (header->in_resize)
        {
            int change = x - header->resize_x;
            int new_width = header->resize_col_width + change;

            if (new_width >= 0)
            {
                header->resize_x = x;
                header->resize_col_width = new_width;
                gnc_header_request_redraw (header);
            }

            break;
        }

        if (pointer_on_resize_line(header, x, y, &col) &&
                gnucash_style_col_is_resizable (header->style, col))
            gdk_window_set_cursor (gtk_widget_get_window (widget),
                                   header->resize_cursor);
        else
            gdk_window_set_cursor (gtk_widget_get_window (widget),
                                   header->normal_cursor);
        break;

    case GDK_BUTTON_PRESS:
    {
        int col;

        if (event->button.button != 1)
            break;

        x = event->button.x;
        y = event->button.y;

        if (pointer_on_resize_line (header, x, y, &col))
            col = find_resize_col (header, col);
        else
            col = -1;

        if (col > -1)
        {
            CellDimensions *cd;

            cd = gnucash_style_get_cell_dimensions
                 (header->style, 0, col);

            header->in_resize = TRUE;
            header->resize_col = col;
            header->resize_col_width = cd->pixel_width;
            header->resize_x = x;
        }
        break;
    }
    case GDK_BUTTON_RELEASE:
    {
        if (event->button.button != 1)
            break;

        x = event->button.x;
        y = event->button.y;

        if (header->in_resize)
        {
            gnc_header_resize_column
                (header,
                 header->resize_col,
                 header->resize_col_width);
            header->in_resize = FALSE;
            header->resize_col = -1;
            gnc_header_request_redraw (header);
        }
        break;
    }

    case GDK_2BUTTON_PRESS:
    {
        gboolean on_line;
        int ptr_col;
        int resize_col;

        if (event->button.button != 1)
            break;

        x = event->button.x;
        y = event->button.y;

        on_line = pointer_on_resize_line (header, x, y, &ptr_col);

        /* If we're on a resize line and the column to the right is zero
           width, resize that one. */
        if (on_line)
            resize_col = find_resize_col (header, ptr_col);
        else
            resize_col = ptr_col;

        if (resize_col > -1)
        {
            header->in_resize = FALSE;
            header->resize_col = -1;
            gnc_header_auto_resize_column (header, resize_col);
        }
    }
    break;

    default:
        break;
    }
    return FALSE;
}