view src/shape_text.c @ 1223:ec964cf4c993

merge
author Thinker K.F. Li <thinker@codemud.net>
date Thu, 06 Jan 2011 09:39:47 +0800
parents a8d20bc8ce40
children
line wrap: on
line source

// -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*-
// vim: sw=4:ts=8:sts=4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "mb_graph_engine.h"
#include <pango/pangocairo.h>
#include "mb_types.h"
#include "mb_shapes.h"

#define ASSERT(x)
#define OK 0
#define ERR -1

typedef struct _sh_text {
    shape_t shape;
    char *data;
    co_aix x, y,w,h;
    co_aix d_x, d_y;		/* device x and y */
    co_aix font_size;
    co_aix d_font_size;
    mbe_font_face_t *face;
    mbe_scaled_font_t *scaled_font;
    int flags;
    PangoLayout *layout;
    int align;
    PangoAttrList *attrs;
} sh_text_t;

#define TXF_SCALE_DIRTY 0x1

static void sh_text_free(shape_t *shape) {
    sh_text_t *text = (sh_text_t *)shape;

    if(text->scaled_font)
	mbe_scaled_font_destroy(text->scaled_font);
    mbe_font_face_destroy(text->face);
}

static void sh_text_P_generate_layout(sh_text_t *text,mbe_t *cr);
shape_t *rdman_shape_text_new(redraw_man_t *rdman,
			      const char *txt, co_aix x, co_aix y,
			      co_aix font_size, mbe_font_face_t *face,PangoAttrList *attrs) {
    sh_text_t *text;

    text = (sh_text_t *)malloc(sizeof(sh_text_t));
    if(text == NULL)
	return NULL;

    memset(text, 0, sizeof(sh_text_t));
    mb_obj_init(text, MBO_TEXT);
    text->data = strdup(txt);
    if(text->data == NULL) {
	free(text);
	return NULL;
    }
    text->x = x;
    text->y = y;
    text->font_size = font_size;
    mbe_font_face_reference(face);
    text->face = face;
    text->flags |= TXF_SCALE_DIRTY;

    text->shape.free = sh_text_free;
    text->layout = NULL;
    text->attrs = attrs;
    text->align = TEXTALIGN_START;
    text->w = text->h = 0;

    rdman_man_shape(rdman, (shape_t *)text);

    return (shape_t *)text;
}

void sh_text_set_pos(shape_t *shape, co_aix x, co_aix y)
{
    sh_text_t *text = (sh_text_t *)shape;
    text->x = x;
    text->y = y;
}


void sh_text_get_pos(shape_t *shape, co_aix *x, co_aix *y)
{
    sh_text_t *text = (sh_text_t *)shape;
    *x = text->x;
    *y = text->y;
}

void sh_text_get_text(shape_t *shape, char *text,int size)
{
    sh_text_t *t = (sh_text_t *)shape;
    strncpy(text,t->data, size);
}

void sh_text_set_text(shape_t *shape, const char *txt) {
    sh_text_t *text = (sh_text_t *)shape;
    char *buf;

    buf = strdup(txt);
    if(text->data) free(text->data);
    text->data = buf;
}

void sh_text_set_color(shape_t *shape, unsigned int color)
{
    PangoAttribute *attr = pango_attr_foreground_new(TEXTCOLOR_RED(color)<<8,TEXTCOLOR_GREEN(color)<<8,TEXTCOLOR_BLUE(color)<<8);
    sh_text_t *text = (sh_text_t *)shape;
    attr->start_index = 0;
    attr->end_index = -1;
    pango_attr_list_change(text->attrs, attr);
}
void sh_text_set_bold(shape_t *shape,int bold)
{
    PangoAttribute *attr = pango_attr_weight_new(bold? PANGO_WEIGHT_BOLD:PANGO_WEIGHT_NORMAL);
    sh_text_t *text = (sh_text_t *)shape;
    attr->start_index = 0;
    attr->end_index = -1;
    pango_attr_list_change(text->attrs, attr);
}
void sh_text_set_italic(shape_t *shape,int italic)
{
    PangoAttribute *attr = pango_attr_style_new(italic? PANGO_STYLE_ITALIC:PANGO_STYLE_NORMAL);
    sh_text_t *text = (sh_text_t *)shape;
    attr->start_index = 0;
    attr->end_index = -1;
    pango_attr_list_change(text->attrs, attr);
}
void sh_text_set_underline(shape_t *shape,int underline)
{
    PangoAttribute *attr = pango_attr_underline_new(underline? PANGO_UNDERLINE_SINGLE:PANGO_UNDERLINE_NONE);
    sh_text_t *text = (sh_text_t *)shape;
    attr->start_index = 0;
    attr->end_index = -1;
    pango_attr_list_change(text->attrs, attr);
}
void sh_text_set_font(shape_t *shape,char *family)
{
    PangoAttribute *attr = pango_attr_family_new(family);
    sh_text_t *text = (sh_text_t *)shape;
    attr->start_index = 0;
    attr->end_index = -1;
    pango_attr_list_change(text->attrs, attr);
}

void sh_text_set_align(shape_t *shape,int align)
{
    sh_text_t *text = (sh_text_t *)shape;
    text->align = align;
}
void sh_text_set_width(shape_t *shape,int width)
{
    sh_text_t *text = (sh_text_t *)shape;
    text->w = width;
}
void sh_text_set_style(shape_t *shape,int begin,int end,mb_textstyle_t *format)
{
    PangoAttribute *attr;
    sh_text_t *text = (sh_text_t *)shape;

    if (end == -1) {
	end = strlen(text->data);
    } else
	end++;
    if (format->property & TEXTSTYLE_BOLD) {
	attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
	attr->start_index = begin;
	attr->end_index = end;
	pango_attr_list_change(text->attrs,attr);
    }
    if (format->property & TEXTSTYLE_ITALIC) {
	attr = pango_attr_style_new(PANGO_STYLE_ITALIC);
	attr->start_index = begin;
	attr->end_index = end;
	pango_attr_list_change(text->attrs,attr);
    }
    if (format->property & TEXTSTYLE_UNDERLINE) {
	attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
	attr->start_index = begin;
	attr->end_index = end;
	pango_attr_list_change(text->attrs,attr);
    }
    if (format->property & TEXTSTYLE_COLOR) {
	printf("color=%x\n", format->color);
	printf("red = %x\n",TEXTCOLOR_RED(format->color));
	printf("green = %x\n",TEXTCOLOR_GREEN(format->color));
	printf("blue = %x\n",TEXTCOLOR_BLUE(format->color));
	attr = pango_attr_foreground_new(TEXTCOLOR_RED(format->color)<<8,TEXTCOLOR_GREEN(format->color)<<8,TEXTCOLOR_BLUE(format->color)<<8);
	attr->start_index = begin;
	attr->end_index = end;
	pango_attr_list_change(text->attrs,attr);
    }
    if (format->property & TEXTSTYLE_FONT) {
	attr = pango_attr_family_new(format->font);
	attr->start_index = begin;
	attr->end_index = end;
	pango_attr_list_change(text->attrs,attr);
    }
    if (format->property & TEXTSTYLE_ALIGN) {
	// We can have one align style for the whole text only
	if (begin != 0 || (end != strlen(text->data)-1))
	    return;
	text->align = format->align;
    }
}

static int get_extents(sh_text_t *text, PangoRectangle *extents) {
    mbe_scaled_font_t *new_scaled;

    pango_layout_get_extents(text->layout, NULL, extents);
    pango_extents_to_pixels(extents,NULL);
    return OK;
}

void sh_text_transform(shape_t *shape) {
    sh_text_t *text;
    coord_t *coord;
    canvas_t *canvas;
    co_aix x, y;
    co_aix shw;
    PangoRectangle extents;
    co_aix poses[2][2];
    int r;

    text = (sh_text_t *)shape;

    text->d_font_size = coord_trans_size(shape->coord, text->font_size);

    coord = sh_get_coord(shape);
    canvas = _coord_get_canvas(coord);
    sh_text_P_generate_layout(text, (mbe_t *)canvas);

    x = text->x;
    y = text->y;
    coord_trans_pos(shape->coord, &x, &y);
    r = get_extents(text, &extents);

    //printf("x=%f y=%f text=%s ascent=%d,descent=%d,width=%d height=%d\n", x,y,text->data,PANGO_ASCENT(extents), PANGO_DESCENT(extents), extents.width, extents.height);
    ASSERT(r == OK);

    text->d_x = x-5;
    text->d_y = y-PANGO_DESCENT(extents)+5;
    shw = shape->stroke_width / 2;
    /* FIXME: It is unreasonable that a font exceed it's bbox.
     * We add 5 pixels in get right bbox.  But, it is unreasonable.
     */

    poses[0][0] = text->d_x + extents.x - shw;
    poses[0][1] = text->d_y + extents.y - shw;
    poses[1][0] = poses[0][0] + extents.width +  shape->stroke_width;
    poses[1][1] = poses[0][1] + extents.height +  shape->stroke_width;
    geo_from_positions(shape->geo, 2, poses);
    /*! \todo Support ratation for shape_text. */
}

static void sh_text_P_generate_layout(sh_text_t *text,mbe_t *cr)
{
    PangoAttribute *attr;
    PangoAttrList *attrlist;
    PangoFontDescription *desc;

    if (text->layout) {
        g_object_unref(text->layout);
    }
    text->layout = pango_cairo_create_layout(cr);
    desc = pango_font_description_from_string("Sans Bold");
    //mbe_set_source_rgb (cr, 0, 0, 0);
    pango_layout_set_font_description (text->layout, desc);
    if (text->w != 0)
        pango_layout_set_width(text->layout, text->w);
    pango_layout_set_text(text->layout,text->data,strlen(text->data));
    pango_layout_set_attributes(text->layout, text->attrs);
    if (text->align == TEXTALIGN_START)
	    pango_layout_set_alignment(text->layout, PANGO_ALIGN_LEFT);
    else if (text->align == TEXTALIGN_MIDDLE)
	    pango_layout_set_alignment(text->layout, PANGO_ALIGN_CENTER);
    else if (text->align == TEXTALIGN_END)
	    pango_layout_set_alignment(text->layout, PANGO_ALIGN_RIGHT);
    pango_cairo_update_layout(cr,text->layout);
    //printf("text=%s\n",text->data);
}
static void draw_text(sh_text_t *text, mbe_t *cr) {
    mbe_move_to(cr, text->d_x, text->d_y);
    pango_cairo_layout_path(cr,text->layout);
}


void sh_text_draw(shape_t *shape, mbe_t *cr) {
    draw_text((sh_text_t *)shape, cr);
}