Commit f436ff97 authored by Jody Goldberg's avatar Jody Goldberg Committed by Jody Goldberg

rewrite.

2002-03-12  Jody Goldberg <jody@gnome.org>

	* widget-editable-label.c : rewrite.

2002-03-12  Jody Goldberg <jody@gnome.org>

	* src/workbook-control-gui.c (cb_sheet_label_edit_finished) : renamed
	  from cb_sheet_label_changed and handle NULL text as cancel.
	(cb_sheet_label_edit_stopped) : deleted.
parent 0e816f89
......@@ -17,7 +17,6 @@ Release Critical
- Summary dialog is non-functional.
- Function selection dialog is broken, and it sucks.
- Go-to cell dialog is shot, make it a guru.
- rewrite editable-lable to be utf8 clean
1.2 Targets
-----------
......
2002-03-12 Jody Goldberg <jody@gnome.org>
* src/workbook-control-gui.c (cb_sheet_label_edit_finished) : renamed
from cb_sheet_label_changed and handle NULL text as cancel.
(cb_sheet_label_edit_stopped) : deleted.
* configure.in : Generate GNOME_Gnumeric.server.in
* Generate GNOME_Gnumeric.server : start to think about this.
......
......@@ -8,6 +8,7 @@ Andreas:
Jody:
* Fix XL import of external function names.
* plug item-bar leak.
* Rewrite editable-label to use gtkentry and to be utf8 clean.
Jukka:
* More solver improvements.
......
2002-03-12 Jody Goldberg <jody@gnome.org>
* src/workbook-control-gui.c (cb_sheet_label_edit_finished) : renamed
from cb_sheet_label_changed and handle NULL text as cancel.
(cb_sheet_label_edit_stopped) : deleted.
* configure.in : Generate GNOME_Gnumeric.server.in
* Generate GNOME_Gnumeric.server : start to think about this.
......
2002-03-12 Jody Goldberg <jody@gnome.org>
* src/workbook-control-gui.c (cb_sheet_label_edit_finished) : renamed
from cb_sheet_label_changed and handle NULL text as cancel.
(cb_sheet_label_edit_stopped) : deleted.
* configure.in : Generate GNOME_Gnumeric.server.in
* Generate GNOME_Gnumeric.server : start to think about this.
......
2002-03-12 Jody Goldberg <jody@gnome.org>
* widget-editable-label.c : rewrite.
2002-03-10 Jody Goldberg <jody@gnome.org>
* Release 1.1.1
......
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* A label that can be used to edit its text on demand.
* widget-editable-label.c: A label that can be used to edit its text on demand
* and provides control over its colour.
*
* Copyright (C) 2002 Jody Goldberg (jody@gnome.org)
*
* Author:
* Miguel de Icaza (miguel@kernel.org)
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as published
* by the Free Software Foundation.
*
* FIXME: add support for drawing the selection.
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <gnumeric-config.h>
#include <gnumeric.h>
......@@ -12,279 +26,143 @@
#include <style-color.h>
#include <gnm-marshalers.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkwindow.h>
#include <libgnomecanvas/gnome-canvas.h>
#include <libgnomecanvas/gnome-canvas-util.h>
#include <libgnomecanvas/gnome-canvas-line.h>
#include <libgnomecanvas/gnome-canvas-text.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
#include <gdk/gdkkeysyms.h>
#include <gal/util/e-util.h>
#define EDITABLE_LABEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST (k), EDITABLE_LABEL_TYPE)
struct _EditableLabel {
GnomeCanvas canvas;
GnomeCanvasItem *text_item;
StyleColor *color;
char *text;
GtkWidget *toplevel;
GtkWidget *entry;
GnomeCanvasItem *cursor;
GnomeCanvasItem *background;
GtkWidget *style_button;
GtkEntry entry;
GdkColor base, text;
char *unedited_text;
};
typedef struct {
GnomeCanvasClass parent_class;
GtkEntryClass entry;
gboolean (* text_changed) (EditableLabel *el, char const *newtext);
void (* editing_stopped) (EditableLabel *el);
gboolean (* edit_finished) (EditableLabel *el, char const *newtext);
} EditableLabelClass;
#define MARGIN 1
/* Signals we emit */
enum {
TEXT_CHANGED,
EDITING_STOPPED,
EDIT_FINISHED,
LAST_SIGNAL
};
static guint el_signals [LAST_SIGNAL] = { 0 };
static GnomeCanvasClass *el_parent_class;
static void el_stop_editing (EditableLabel *el);
static void el_change_text (EditableLabel *el, const char *text);
static void
el_entry_activate (GtkWidget *entry, EditableLabel *el)
{
gboolean accept = TRUE;
char const *text = gtk_entry_get_text (GTK_ENTRY (el->entry));
g_signal_emit (G_OBJECT (el), el_signals [TEXT_CHANGED], 0,
text, &accept);
#define BASE_TYPE GTK_TYPE_ENTRY
if (accept)
editable_label_set_text (el, text);
else
editable_label_set_text (el, el->text);
el_stop_editing (el);
}
static guint el_signals [LAST_SIGNAL] = { 0 };
static void
el_edit_sync (EditableLabel *el)
el_set_color_gdk (EditableLabel *el, GdkColor *base, GdkColor *text)
{
GnomeCanvasGroup *root_group = GNOME_CANVAS_GROUP (GNOME_CANVAS (el)->root);
GtkEntry *entry = GTK_ENTRY (el->entry);
GtkWidget *widget = GTK_WIDGET (el);
GnomeCanvasPoints *points;
GdkFont *font;
int cursor_pos;
char const *text;
text = gtk_entry_get_text (entry);
font = gtk_style_get_font (widget->style);
el_change_text (el, text);
cursor_pos = gtk_editable_get_position (GTK_EDITABLE (entry));
points = gnome_canvas_points_new (2);
points->coords [0] = gdk_text_width (font, text, cursor_pos) + MARGIN;
points->coords [1] = 1 + MARGIN;
points->coords [2] = points->coords [0];
points->coords [3] = font->ascent + font->descent - 1 - MARGIN;
/* Draw the cursor */
if (!el->cursor) {
el->cursor = gnome_canvas_item_new (
root_group, GNOME_TYPE_CANVAS_LINE,
"points", points,
"fill_color_gdk", &widget->style->fg [GTK_STATE_NORMAL],
NULL);
gnome_canvas_item_set (GNOME_CANVAS_ITEM (el->text_item),
"fill_color_gdk", &widget->style->fg [GTK_STATE_NORMAL],
NULL);
} else
gnome_canvas_item_set (
el->cursor,
"points", points,
NULL);
gnome_canvas_points_free (points);
if (!el->background) {
el->background = gnome_canvas_item_new (
root_group, GNOME_TYPE_CANVAS_RECT,
"x1", (double) 0,
"y1", (double) 0,
"x2", (double) gdk_string_measure (font, text) + MARGIN * 2,
"y2", (double) font->ascent + font->descent + MARGIN * 2,
"fill_color_gdk", &widget->style->base [GTK_STATE_NORMAL],
"outline_color_gdk", &widget->style->fg [GTK_STATE_NORMAL],
NULL);
/* Just a large enough number, to make sure it goes to the very back */
gnome_canvas_item_lower (el->background, 10);
} else
gnome_canvas_item_set (
el->background,
"x1", (double) 0,
"y1", (double) 0,
"x2", (double) gdk_string_measure (font, text) + MARGIN * 2,
"y2", (double) font->ascent + font->descent + MARGIN * 2,
"fill_color_gdk", &widget->style->base [GTK_STATE_NORMAL],
NULL);
GtkStyle *s = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (el)));
GdkColor tmp = s->base [GTK_STATE_NORMAL];
s->base [GTK_STATE_NORMAL] = *base;
*base = tmp;
tmp = s->text [GTK_STATE_NORMAL];
s->text [GTK_STATE_NORMAL] = *text;
*text = tmp;
gtk_widget_set_style (GTK_WIDGET (el), s);
gtk_style_unref (s);
}
static void
el_start_editing (EditableLabel *el, char const *text, gboolean select_text)
el_stop_editing (EditableLabel *el)
{
gtk_widget_grab_focus (GTK_WIDGET (el));
/* Create a GtkEntry to actually do the editing */
el->entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (el->entry), text);
g_signal_connect (G_OBJECT (el->entry), "activate",
GTK_SIGNAL_FUNC (el_entry_activate), el);
el->toplevel = gtk_window_new (GTK_WINDOW_POPUP);
gtk_container_add (GTK_CONTAINER (el->toplevel), el->entry);
gtk_widget_set_uposition (el->toplevel, 20000, 20000);
gtk_widget_show_all (el->toplevel);
gtk_grab_add (GTK_WIDGET (el));
if (el->unedited_text == NULL)
return;
if (select_text)
gtk_editable_select_region (GTK_EDITABLE (el->entry), 0, -1);
g_free (el->unedited_text);
el->unedited_text = NULL;
el_edit_sync (el);
el_set_color_gdk (el, &el->base, &el->text);
gtk_editable_set_editable (GTK_EDITABLE (el), FALSE);
gtk_editable_select_region (GTK_EDITABLE (el), 0, 0);
gtk_grab_remove (GTK_WIDGET (el));
}
static void
el_stop_editing (EditableLabel *el)
el_entry_activate (GtkEntry *entry, gpointer ignored)
{
if (el->toplevel) {
gtk_object_destroy (GTK_OBJECT (el->toplevel));
el->toplevel = NULL;
el->entry = NULL;
}
EditableLabel *el = EDITABLE_LABEL (entry);
gboolean reject = FALSE;
char const *text = gtk_entry_get_text (entry);
if (el->cursor) {
gtk_object_destroy (GTK_OBJECT (el->cursor));
el->cursor = NULL;
}
if (el->unedited_text == NULL)
return;
if (el->background) {
gtk_object_destroy (GTK_OBJECT (el->background));
el->background = NULL;
}
if (strcmp (el->unedited_text, text))
g_signal_emit (G_OBJECT (entry), el_signals [EDIT_FINISHED], 0,
text, &reject);
else
reject = FALSE;
editable_label_set_color (el, el->color);
gtk_grab_remove (GTK_WIDGET (el));
if (reject)
editable_label_set_text (el, el->unedited_text);
el_stop_editing (el);
}
static void
el_change_text (EditableLabel *el, const char *text)
el_start_editing (EditableLabel *el)
{
const char *item_text;
item_text = GNOME_CANVAS_TEXT (el->text_item)->text;
if (strcmp (text, item_text) == 0)
if (el->unedited_text != NULL)
return;
gnome_canvas_item_set (
GNOME_CANVAS_ITEM (el->text_item),
"text", text,
NULL);
gtk_widget_queue_resize (GTK_WIDGET (el));
el->unedited_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (el)));
g_signal_connect (G_OBJECT (el),
"activate",
G_CALLBACK (el_entry_activate), NULL);
gtk_editable_select_region (GTK_EDITABLE (el), 0, -1);
gtk_editable_set_editable (GTK_EDITABLE (el), TRUE);
el_set_color_gdk (el, &el->base, &el->text);
gtk_widget_grab_focus (GTK_WIDGET (el));
gtk_grab_add (GTK_WIDGET (el));
}
/*
* GtkObject destroy method override
*/
static void
el_destroy (GtkObject *object)
{
EditableLabel *el = EDITABLE_LABEL (object);
GtkObjectClass *base;
el_stop_editing (el);
if (el->text != NULL) {
g_free (el->text);
el->text = NULL;
}
editable_label_set_color (el, NULL);
if (el->style_button) {
gtk_widget_unref (el->style_button);
el->style_button = NULL;
}
((GtkObjectClass *)el_parent_class)->destroy (object);
base = g_type_class_peek (BASE_TYPE);
base->destroy (object);
}
/*
* GtkWidget size_request method override
*/
static void
el_size_request (GtkWidget *widget, GtkRequisition *requisition)
{
EditableLabel *el = EDITABLE_LABEL (widget);
double width, height;
if (!el->text_item || !GTK_WIDGET_REALIZED (widget)){
requisition->width = 1;
requisition->height = 1;
}
g_object_get (G_OBJECT (el->text_item),
"text_width", &width,
"text_height", &height,
NULL);
requisition->width = width + MARGIN * 2;
requisition->height = height + MARGIN * 2;
}
/*
* GtkWidget button_press_event method override
*/
static gint
el_button_press_event (GtkWidget *widget, GdkEventButton *button)
{
GtkWidgetClass *widget_class;
GtkWidgetClass *base;
EditableLabel *el = EDITABLE_LABEL (widget);
if (!el->text)
return FALSE;
if (el->entry && button->window != widget->window){
if (button->window != widget->window &&
button->window != el->entry.text_area) {
/* Accept the name change */
el_entry_activate (el->entry, el);
el_entry_activate (GTK_ENTRY (el), NULL);
gdk_event_put ((GdkEvent *)button);
return TRUE;
}
if (button->type == GDK_2BUTTON_PRESS) {
el_start_editing (el,
GNOME_CANVAS_TEXT (el->text_item)->text, TRUE);
el_start_editing (el);
return FALSE;
}
widget_class = g_type_class_peek (GNOME_TYPE_CANVAS);
if (widget_class && widget_class->button_press_event)
return widget_class->button_press_event (widget, button);
return FALSE;
if (el->unedited_text == NULL)
return FALSE;
base = g_type_class_peek (BASE_TYPE);
return base->button_press_event (widget, button);
}
/*
......@@ -293,166 +171,134 @@ el_button_press_event (GtkWidget *widget, GdkEventButton *button)
* If the label is being edited, we forward the event to the GtkEntry widget.
*/
static gint
el_key_press_event (GtkWidget *widget, GdkEventKey *event)
el_key_press_event (GtkWidget *w, GdkEventKey *event)
{
EditableLabel *el = EDITABLE_LABEL (widget);
GtkWidgetClass *base;
EditableLabel *el = EDITABLE_LABEL (w);
if (!el->entry)
if (el->unedited_text == NULL)
return FALSE;
if (event->keyval == GDK_Escape) {
gboolean dummy;
el_stop_editing (el);
el_change_text (el, el->text);
g_signal_emit (G_OBJECT (el), el_signals [EDITING_STOPPED], 0);
g_signal_emit (G_OBJECT (el), el_signals [EDIT_FINISHED], 0,
NULL, &dummy);
return TRUE;
}
gtk_widget_event (GTK_WIDGET (el->entry), (GdkEvent *) event);
/* The previous call could have killed the edition */
if (el->entry)
el_edit_sync (el);
return TRUE;
base = g_type_class_peek (BASE_TYPE);
return base->key_press_event (w, event);
}
static void
el_realize (GtkWidget *widget)
el_size_request (GtkWidget *el, GtkRequisition *req)
{
EditableLabel *el = EDITABLE_LABEL (widget);
PangoRectangle logical_rect;
PangoLayoutLine *line;
PangoLayout *layout;
GtkWidgetClass *base = g_type_class_peek (BASE_TYPE);
if (GTK_WIDGET_CLASS (el_parent_class)->realize)
(*GTK_WIDGET_CLASS (el_parent_class)->realize) (widget);
base->size_request (el, req);
layout = gtk_entry_get_layout (GTK_ENTRY (el));
line = pango_layout_get_lines (layout)->data;
pango_layout_line_get_extents (line, NULL, &logical_rect);
gnome_canvas_set_scroll_region (GNOME_CANVAS (el), 0, 0, 32000, 32000);
editable_label_set_color (el, el->color);
gnome_canvas_item_set (GNOME_CANVAS_ITEM (EDITABLE_LABEL (widget)->text_item),
"font_desc", widget->style->font_desc,
NULL);
req->width = logical_rect.width / PANGO_SCALE + 2*2;
}
static gint
el_expose_event (GtkWidget *widget, GdkEventExpose *event)
{
GtkWidgetClass *base = g_type_class_peek (BASE_TYPE);
base = g_type_class_peek (BASE_TYPE);
return base->expose_event (widget, event);
}
static void
el_class_init (EditableLabelClass *klass)
el_class_init (GtkObjectClass *object_class)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GnomeCanvasClass *canvas_class;
object_class = (GtkObjectClass *) klass;
widget_class = (GtkWidgetClass *) klass;
canvas_class = (GnomeCanvasClass *) klass;
el_parent_class = gtk_type_class (gnome_canvas_get_type ());
object_class->destroy = el_destroy;
widget_class->size_request = el_size_request;
widget_class = (GtkWidgetClass *) object_class;
widget_class->button_press_event = el_button_press_event;
widget_class->key_press_event = el_key_press_event;
widget_class->realize = el_realize;
widget_class->size_request = el_size_request;
widget_class->expose_event = el_expose_event;
el_signals [TEXT_CHANGED] = g_signal_new ("text_changed",
el_signals [EDIT_FINISHED] = g_signal_new ("edit_finished",
EDITABLE_LABEL_TYPE,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EditableLabelClass, text_changed),
G_STRUCT_OFFSET (EditableLabelClass, edit_finished),
(GSignalAccumulator) NULL, NULL,
gnm__BOOLEAN__POINTER,
G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
}
el_signals [EDITING_STOPPED] = g_signal_new ( "editing_stopped",
EDITABLE_LABEL_TYPE,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EditableLabelClass, editing_stopped),
(GSignalAccumulator) NULL, NULL,
gnm__VOID__VOID,
GTK_TYPE_NONE, 0);
static void
cb_el_changed (GtkWidget *w, gpointer ignored)
{
gtk_widget_queue_resize (w);
}
static void
el_init (GObject *obj)
{
g_signal_connect (obj, "changed", G_CALLBACK (cb_el_changed), NULL);
}
E_MAKE_TYPE (editable_label, "EditableLabel", EditableLabel,
el_class_init, NULL, GNOME_TYPE_CANVAS)
el_class_init, el_init, BASE_TYPE)
void
editable_label_set_text (EditableLabel *el, char const *text)
{
g_return_if_fail (el != NULL);
g_return_if_fail (text != NULL);
g_return_if_fail (IS_EDITABLE_LABEL (el));
/* This code is usually invoked with el->text as the name */
if (text != el->text) {
if (el->text)
g_free (el->text);
el->text = g_strdup (text);
}
if (el->text_item == NULL) {
GnomeCanvasGroup *root_group;
GtkWidget* text_color_widget;
el->style_button = text_color_widget = gtk_button_new ();
gtk_widget_ref (text_color_widget);
gtk_object_sink (GTK_OBJECT (text_color_widget));
gtk_widget_ensure_style (text_color_widget);
root_group = GNOME_CANVAS_GROUP (GNOME_CANVAS (el)->root);
el->text_item = gnome_canvas_item_new (
root_group, gnome_canvas_text_get_type (),
"anchor", GTK_ANCHOR_NORTH_WEST,
"text", text,
"x", (double) MARGIN,
"y", (double) MARGIN,
"fill_color_gdk",
&text_color_widget->style->text[GTK_STATE_NORMAL],
NULL);
gtk_widget_destroy (text_color_widget);
} else
el_change_text (el, text);
gtk_entry_set_text (GTK_ENTRY (el), text);
}
char const *
editable_label_get_text (EditableLabel const *el)
{
g_return_val_if_fail (IS_EDITABLE_LABEL (el), "");
return el->text;
return (el->unedited_text != NULL)
? el->unedited_text
: gtk_entry_get_text (GTK_ENTRY (el));
}
void
editable_label_set_color (EditableLabel *el, StyleColor *color)
editable_label_set_color (EditableLabel *el, GdkColor *color)
{
int contrast = color->red + color->green + color->blue;
GdkColor base = *color;
GdkColor text = (contrast >= 0x18000) ? gs_black : gs_white;
g_return_if_fail (IS_EDITABLE_LABEL (el));
g_return_if_fail (el->unedited_text == NULL);
if (color != NULL)
style_color_ref (color);
if (el->color != NULL)
style_color_unref (el->color);
el->color = color;
if (el->color != NULL) {
int contrast = el->color->color.red + el->color->color.green + el->color->color.blue;
GtkStyle *style = gtk_style_copy (GTK_WIDGET (el)->style);
style->bg [GTK_STATE_NORMAL] = el->color->color;
gtk_widget_set_style (GTK_WIDGET (el), style);
gtk_style_unref (style);
gnome_canvas_item_set (el->text_item,
"fill_color_gdk", (contrast >= 0x18000) ? &gs_black : &gs_white,
NULL);
}
/* ignore the current colors */
el_set_color_gdk (el, &base, &text);
}
GtkWidget *
editable_label_new (char const *text, StyleColor *color)
editable_label_new (char const *text, GdkColor *color)
{
GtkWidget *el;
EditableLabel *el = g_object_new (EDITABLE_LABEL_TYPE,
"has_frame", FALSE,
"editable", FALSE,
NULL);
el = g_object_new (EDITABLE_LABEL_TYPE, NULL);
GtkStyle *s = gtk_widget_get_default_style ();
el->base = s->bg [GTK_STATE_NORMAL];
el->text = s->fg [GTK_STATE_NORMAL];
/* assign the fg/bg and store base/text */
el_set_color_gdk (el, &el->base, &el->text);
if (text != NULL)
editable_label_set_text (EDITABLE_LABEL (el), text);
if (color != NULL)
editable_label_set_color (EDITABLE_LABEL (el), color);
editable_label_set_color (el, color);
if (text != NULL)
editable_label_set_text (el, text);
return el;
return GTK_WIDGET (el);
}
......@@ -11,11 +11,11 @@ G_BEGIN_DECLS
typedef struct _EditableLabel EditableLabel;
GType editable_label_get_type (void);
GtkWidget *editable_label_new (char const *text, StyleColor *color);
GType editable_label_get_type (void);
GtkWidget *editable_label_new (char const *text, GdkColor *color);
void editable_label_set_text (EditableLabel *el, char const *text);
char const *editable_label_get_text (EditableLabel const *el);
void editable_label_set_color (EditableLabel *el, StyleColor *color);
void editable_label_set_color (EditableLabel *el, GdkColor *color);
G_END_DECLS
......
......@@ -53,6 +53,7 @@
#include "value.h"
#include "validation.h"
#include "history.h"
#include "style-color.h"
#include "str.h"
#include "cell.h"
#include "formats.h"
......@@ -366,23 +367,16 @@ wbcg_edit_selection_descr_set (WorkbookControl *wbc, char const *text)
gtk_entry_set_text (GTK_ENTRY (wbcg->selection_descriptor), text);
}
/*
* Signal handler for EditableLabel's text_changed signal.
*/
static gboolean
cb_sheet_label_changed (EditableLabel *el,
const char *new_name, WorkbookControlGUI *wbcg)
{
gboolean ans = !cmd_rename_sheet (WORKBOOK_CONTROL (wbcg), NULL,
editable_label_get_text (el), new_name);
wbcg_focus_cur_scg (wbcg);
return ans;
}
static void
cb_sheet_label_edit_stopped (EditableLabel *el, WorkbookControlGUI *wbcg)
cb_sheet_label_edit_finished (EditableLabel *el, char const *new_name,
WorkbookControlGUI *wbcg)