* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include <config.h>
#include <math.h>
#include <string.h>
#include "gtklabel.h"
+#include "gtkaccellabel.h"
+#include "gtkdnd.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
-#include "gtksignal.h"
#include "gtkwindow.h"
#include "gdk/gdkkeysyms.h"
#include "gtkclipboard.h"
-#include "gdk/gdki18n.h"
#include <pango/pango.h>
#include "gtkimagemenuitem.h"
#include "gtkintl.h"
#include "gtkseparatormenuitem.h"
+#include "gtktextutil.h"
#include "gtkmenuitem.h"
#include "gtknotebook.h"
#include "gtkstock.h"
#include "gtkbindings.h"
+#include "gtkprivate.h"
+#include "gtkalias.h"
+
+#define GTK_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_LABEL, GtkLabelPrivate))
+
+typedef struct
+{
+ gint wrap_width;
+ gint width_chars;
+ gint max_width_chars;
+}
+GtkLabelPrivate;
struct _GtkLabelSelectionInfo
{
GdkWindow *window;
gint selection_anchor;
gint selection_end;
- GdkGC *cursor_gc;
GtkWidget *popup_menu;
+
+ gint drag_start_x;
+ gint drag_start_y;
+
+ guint in_drag : 1;
};
enum {
PROP_JUSTIFY,
PROP_PATTERN,
PROP_WRAP,
+ PROP_WRAP_MODE,
PROP_SELECTABLE,
PROP_MNEMONIC_KEYVAL,
PROP_MNEMONIC_WIDGET,
PROP_CURSOR_POSITION,
- PROP_SELECTION_BOUND
+ PROP_SELECTION_BOUND,
+ PROP_ELLIPSIZE,
+ PROP_WIDTH_CHARS,
+ PROP_SINGLE_LINE_MODE,
+ PROP_ANGLE,
+ PROP_MAX_WIDTH_CHARS
};
static guint signals[LAST_SIGNAL] = { 0 };
-static void gtk_label_class_init (GtkLabelClass *klass);
-static void gtk_label_init (GtkLabel *label);
static void gtk_label_set_property (GObject *object,
guint prop_id,
const GValue *value,
static void gtk_label_unrealize (GtkWidget *widget);
static void gtk_label_map (GtkWidget *widget);
static void gtk_label_unmap (GtkWidget *widget);
-static gint gtk_label_button_press (GtkWidget *widget,
- GdkEventButton *event);
-static gint gtk_label_button_release (GtkWidget *widget,
- GdkEventButton *event);
-static gint gtk_label_motion (GtkWidget *widget,
- GdkEventMotion *event);
+
+static gboolean gtk_label_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean gtk_label_button_release (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean gtk_label_motion (GtkWidget *widget,
+ GdkEventMotion *event);
+static void gtk_label_grab_focus (GtkWidget *widget);
static void gtk_label_set_text_internal (GtkLabel *label,
static void gtk_label_recalculate (GtkLabel *label);
static void gtk_label_hierarchy_changed (GtkWidget *widget,
GtkWidget *old_toplevel);
+static void gtk_label_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen);
static void gtk_label_create_window (GtkLabel *label);
static void gtk_label_destroy_window (GtkLabel *label);
static void gtk_label_clear_layout (GtkLabel *label);
static void gtk_label_ensure_layout (GtkLabel *label);
+static void gtk_label_invalidate_wrap_width (GtkLabel *label);
static void gtk_label_select_region_index (GtkLabel *label,
gint anchor_index,
gint end_index);
gboolean group_cycling);
static void gtk_label_setup_mnemonic (GtkLabel *label,
guint last_key);
-static gboolean gtk_label_focus (GtkWidget *widget,
- GtkDirectionType direction);
+static void gtk_label_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time);
+
/* For selectable lables: */
static void gtk_label_move_cursor (GtkLabel *label,
static gint gtk_label_move_backward_word (GtkLabel *label,
gint start);
-static GtkMiscClass *parent_class = NULL;
-
+static GQuark quark_angle = 0;
-GtkType
-gtk_label_get_type (void)
-{
- static GtkType label_type = 0;
-
- if (!label_type)
- {
- static const GTypeInfo label_info =
- {
- sizeof (GtkLabelClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_label_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkLabel),
- 32, /* n_preallocs */
- (GInstanceInitFunc) gtk_label_init,
- };
-
- label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel", &label_info, 0);
- }
-
- return label_type;
-}
+G_DEFINE_TYPE (GtkLabel, gtk_label, GTK_TYPE_MISC)
static void
add_move_binding (GtkBindingSet *binding_set,
gtk_binding_entry_add_signal (binding_set, keyval, modmask,
"move_cursor", 3,
- GTK_TYPE_ENUM, step,
+ G_TYPE_ENUM, step,
G_TYPE_INT, count,
- G_TYPE_BOOLEAN, FALSE);
+ G_TYPE_BOOLEAN, FALSE);
/* Selection-extending version */
gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
"move_cursor", 3,
- GTK_TYPE_ENUM, step,
+ G_TYPE_ENUM, step,
G_TYPE_INT, count,
- G_TYPE_BOOLEAN, TRUE);
+ G_TYPE_BOOLEAN, TRUE);
}
static void
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GtkBindingSet *binding_set;
- parent_class = gtk_type_class (GTK_TYPE_MISC);
-
+ quark_angle = g_quark_from_static_string ("angle");
+
gobject_class->set_property = gtk_label_set_property;
gobject_class->get_property = gtk_label_get_property;
gobject_class->finalize = gtk_label_finalize;
widget_class->button_release_event = gtk_label_button_release;
widget_class->motion_notify_event = gtk_label_motion;
widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
+ widget_class->screen_changed = gtk_label_screen_changed;
widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
- widget_class->focus = gtk_label_focus;
+ widget_class->drag_data_get = gtk_label_drag_data_get;
+ widget_class->grab_focus = gtk_label_grab_focus;
class->move_cursor = gtk_label_move_cursor;
class->copy_clipboard = gtk_label_copy_clipboard;
signals[MOVE_CURSOR] =
- gtk_signal_new ("move_cursor",
- GTK_RUN_LAST | GTK_RUN_ACTION,
- GTK_CLASS_TYPE (object_class),
- GTK_SIGNAL_OFFSET (GtkLabelClass, move_cursor),
- _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
- GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
+ g_signal_new (I_("move_cursor"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkLabelClass, move_cursor),
+ NULL, NULL,
+ _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
+ G_TYPE_NONE, 3,
+ GTK_TYPE_MOVEMENT_STEP,
+ G_TYPE_INT,
+ G_TYPE_BOOLEAN);
signals[COPY_CLIPBOARD] =
- gtk_signal_new ("copy_clipboard",
- GTK_RUN_LAST | GTK_RUN_ACTION,
- GTK_CLASS_TYPE (object_class),
- GTK_SIGNAL_OFFSET (GtkLabelClass, copy_clipboard),
- _gtk_marshal_VOID__VOID,
- GTK_TYPE_NONE, 0);
+ g_signal_new (I_("copy_clipboard"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard),
+ NULL, NULL,
+ _gtk_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
signals[POPULATE_POPUP] =
- gtk_signal_new ("populate_popup",
- GTK_RUN_LAST,
- GTK_CLASS_TYPE (object_class),
- GTK_SIGNAL_OFFSET (GtkLabelClass, populate_popup),
- _gtk_marshal_VOID__OBJECT,
- GTK_TYPE_NONE, 1, GTK_TYPE_MENU);
-
- g_object_class_install_property (G_OBJECT_CLASS(object_class),
+ g_signal_new (I_("populate_popup"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_MENU);
+
+ g_object_class_install_property (gobject_class,
PROP_LABEL,
g_param_spec_string ("label",
- _("Label"),
- _("The text of the label."),
+ P_("Label"),
+ P_("The text of the label"),
NULL,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ATTRIBUTES,
g_param_spec_boxed ("attributes",
- _("Attributes"),
- _("A list of style attributes to apply to the text of the label."),
+ P_("Attributes"),
+ P_("A list of style attributes to apply to the text of the label"),
PANGO_TYPE_ATTR_LIST,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_USE_MARKUP,
- g_param_spec_boolean ("use_markup",
- _("Use markup"),
- _("The text of the label includes XML markup. See pango_parse_markup()."),
+ g_param_spec_boolean ("use-markup",
+ P_("Use markup"),
+ P_("The text of the label includes XML markup. See pango_parse_markup()"),
FALSE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_USE_UNDERLINE,
- g_param_spec_boolean ("use_underline",
- _("Use underline"),
- _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
+ g_param_spec_boolean ("use-underline",
+ P_("Use underline"),
+ P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
FALSE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_JUSTIFY,
g_param_spec_enum ("justify",
- _("Justification"),
- _("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that."),
+ P_("Justification"),
+ P_("The alignment of the lines in the text of the label relative to each other. This does NOT affect the alignment of the label within its allocation. See GtkMisc::xalign for that"),
GTK_TYPE_JUSTIFICATION,
GTK_JUSTIFY_LEFT,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PATTERN,
g_param_spec_string ("pattern",
- _("Pattern"),
- _("A string with _ characters in positions correspond to characters in the text to underline."),
+ P_("Pattern"),
+ P_("A string with _ characters in positions correspond to characters in the text to underline"),
NULL,
- G_PARAM_WRITABLE));
+ GTK_PARAM_WRITABLE));
g_object_class_install_property (gobject_class,
PROP_WRAP,
g_param_spec_boolean ("wrap",
- _("Line wrap"),
- _("If set, wrap lines if the text becomes too wide."),
+ P_("Line wrap"),
+ P_("If set, wrap lines if the text becomes too wide"),
FALSE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
+ /**
+ * GtkLabel:wrap-mode:
+ *
+ * If line wrapping is on (see the wrap property) this controls how
+ * the line wrapping is done. The default is %PANGO_WRAP_WORD which means
+ * wrap on word boundaries.
+ *
+ * Since: 2.10
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_WRAP_MODE,
+ g_param_spec_enum ("wrap-mode",
+ P_("Line wrap mode"),
+ P_("If wrap is set, controls how linewrapping is done"),
+ PANGO_TYPE_WRAP_MODE,
+ PANGO_WRAP_WORD,
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_SELECTABLE,
g_param_spec_boolean ("selectable",
- _("Selectable"),
- _("Whether the label text can be selected with the mouse."),
+ P_("Selectable"),
+ P_("Whether the label text can be selected with the mouse"),
FALSE,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_MNEMONIC_KEYVAL,
- g_param_spec_uint ("mnemonic_keyval",
- _("Mnemonic key"),
- _("The mnemonic accelerator key for this label."),
+ g_param_spec_uint ("mnemonic-keyval",
+ P_("Mnemonic key"),
+ P_("The mnemonic accelerator key for this label"),
0,
G_MAXUINT,
GDK_VoidSymbol,
- G_PARAM_READABLE));
+ GTK_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_MNEMONIC_WIDGET,
- g_param_spec_object ("mnemonic_widget",
- _("Mnemonic widget"),
- _("The widget to be activated when the label's mnemonic "
- "key is pressed."),
+ g_param_spec_object ("mnemonic-widget",
+ P_("Mnemonic widget"),
+ P_("The widget to be activated when the label's mnemonic "
+ "key is pressed"),
GTK_TYPE_WIDGET,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_CURSOR_POSITION,
- g_param_spec_int ("cursor_position",
- _("Cursor Position"),
- _("The current position of the insertion cursor in chars."),
+ g_param_spec_int ("cursor-position",
+ P_("Cursor Position"),
+ P_("The current position of the insertion cursor in chars"),
0,
G_MAXINT,
0,
- G_PARAM_READABLE));
+ GTK_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_SELECTION_BOUND,
- g_param_spec_int ("selection_bound",
- _("Selection Bound"),
- _("The position of the opposite end of the selection from the cursor in chars."),
+ g_param_spec_int ("selection-bound",
+ P_("Selection Bound"),
+ P_("The position of the opposite end of the selection from the cursor in chars"),
0,
G_MAXINT,
0,
- G_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_boxed ("cursor_color",
- _("Cursor color"),
- _("Color with which to draw insertion cursor"),
- GDK_TYPE_COLOR,
- G_PARAM_READABLE));
+ GTK_PARAM_READABLE));
+ /**
+ * GtkLabel:ellipsize:
+ *
+ * The preferred place to ellipsize the string, if the label does not have
+ * enough room to display the entire string, specified as a #PangoEllisizeMode.
+ *
+ * Note that setting this property to a value other than %PANGO_ELLIPSIZE_NONE
+ * has the side-effect that the label requests only enough space to display the
+ * ellipsis "...". In particular, this means that ellipsizing labels don't
+ * work well in notebook tabs, unless the tab's ::tab-expand property is set
+ * to %TRUE. Other means to set a label's width are
+ * gtk_widget_set_size_request() and gtk_label_set_width_chars().
+ *
+ * Since: 2.6
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ELLIPSIZE,
+ g_param_spec_enum ("ellipsize",
+ P_("Ellipsize"),
+ P_("The preferred place to ellipsize the string, if the label does not have enough room to display the entire string"),
+ PANGO_TYPE_ELLIPSIZE_MODE,
+ PANGO_ELLIPSIZE_NONE,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkLabel:width-chars:
+ *
+ * The desired width of the label, in characters. If this property is set to
+ * -1, the width will be calculated automatically, otherwise the label will
+ * request either 3 characters or the property value, whichever is greater.
+ * If the width-chars property is set to a positive value, then the
+ * max-width-chars property is ignored.
+ *
+ * Since: 2.6
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_WIDTH_CHARS,
+ g_param_spec_int ("width-chars",
+ P_("Width In Characters"),
+ P_("The desired width of the label, in characters"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkLabel:single-line-mode:
+ *
+ * Whether the label is in single line mode. In single line mode,
+ * the height of the label does not depend on the actual text, it
+ * is always set to ascent + descent of the font. This can be an
+ * advantage in situations where resizing the label because of text
+ * changes would be distracting, e.g. in a statusbar.
+ *
+ * Since: 2.6
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_SINGLE_LINE_MODE,
+ g_param_spec_boolean ("single-line-mode",
+ P_("Single Line Mode"),
+ P_("Whether the label is in single line mode"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkLabel:angle:
+ *
+ * The angle that the baseline of the label makes with the horizontal,
+ * in degrees, measured counterclockwise. An angle of 90 reads from
+ * from bottom to top, an angle of 270, from top to bottom. Ignored
+ * if the label is selectable, wrapped, or ellipsized.
+ *
+ * Since: 2.6
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_ANGLE,
+ g_param_spec_double ("angle",
+ P_("Angle"),
+ P_("Angle at which the label is rotated"),
+ 0.0,
+ 360.0,
+ 0.0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkLabel:max-width-chars:
+ *
+ * The desired maximum width of the label, in characters. If this property
+ * is set to -1, the width will be calculated automatically, otherwise the
+ * label will request space for no more than the requested number of
+ * characters. If the width-chars property is set to a positive value,
+ * then the max-width-chars property is ignored.
+ *
+ * Since: 2.6
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_MAX_WIDTH_CHARS,
+ g_param_spec_int ("max-width-chars",
+ P_("Maximum Width In Characters"),
+ P_("The desired maximum width of the label, in characters"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
/*
* Key bindings
*/
add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
GTK_MOVEMENT_WORDS, -1);
-
- add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
- GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
- add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
- GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
+ /* select all */
+ gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
+ "move_cursor", 3,
+ G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
+ G_TYPE_INT, -1,
+ G_TYPE_BOOLEAN, FALSE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
+ "move_cursor", 3,
+ G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
+ G_TYPE_INT, 1,
+ G_TYPE_BOOLEAN, TRUE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
+ "move_cursor", 3,
+ G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
+ G_TYPE_INT, -1,
+ G_TYPE_BOOLEAN, FALSE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
+ "move_cursor", 3,
+ G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
+ G_TYPE_INT, 1,
+ G_TYPE_BOOLEAN, TRUE);
+
+ /* unselect all */
+ gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
+ "move_cursor", 3,
+ G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
+ G_TYPE_INT, 0,
+ G_TYPE_BOOLEAN, FALSE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
+ "move_cursor", 3,
+ G_TYPE_ENUM, GTK_MOVEMENT_PARAGRAPH_ENDS,
+ G_TYPE_INT, 0,
+ G_TYPE_BOOLEAN, FALSE);
add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
GTK_MOVEMENT_WORDS, 1);
/* copy */
gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
"copy_clipboard", 0);
+
+ gtk_settings_install_property (g_param_spec_boolean ("gtk-label-select-on-focus",
+ P_("Select on focus"),
+ P_("Whether to select the contents of a selectable label when it is focused"),
+ TRUE,
+ GTK_PARAM_READWRITE));
+
+
+ g_type_class_add_private (class, sizeof (GtkLabelPrivate));
}
static void
GParamSpec *pspec)
{
GtkLabel *label;
- guint last_keyval;
label = GTK_LABEL (object);
- last_keyval = label->mnemonic_keyval;
switch (prop_id)
{
case PROP_WRAP:
gtk_label_set_line_wrap (label, g_value_get_boolean (value));
break;
+ case PROP_WRAP_MODE:
+ gtk_label_set_line_wrap_mode (label, g_value_get_enum (value));
+ break;
case PROP_SELECTABLE:
gtk_label_set_selectable (label, g_value_get_boolean (value));
break;
case PROP_MNEMONIC_WIDGET:
gtk_label_set_mnemonic_widget (label, (GtkWidget*) g_value_get_object (value));
break;
+ case PROP_ELLIPSIZE:
+ gtk_label_set_ellipsize (label, g_value_get_enum (value));
+ break;
+ case PROP_WIDTH_CHARS:
+ gtk_label_set_width_chars (label, g_value_get_int (value));
+ break;
+ case PROP_SINGLE_LINE_MODE:
+ gtk_label_set_single_line_mode (label, g_value_get_boolean (value));
+ break;
+ case PROP_ANGLE:
+ gtk_label_set_angle (label, g_value_get_double (value));
+ break;
+ case PROP_MAX_WIDTH_CHARS:
+ gtk_label_set_max_width_chars (label, g_value_get_int (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_WRAP:
g_value_set_boolean (value, label->wrap);
break;
+ case PROP_WRAP_MODE:
+ g_value_set_enum (value, label->wrap_mode);
+ break;
case PROP_SELECTABLE:
g_value_set_boolean (value, gtk_label_get_selectable (label));
break;
case PROP_CURSOR_POSITION:
if (label->select_info)
{
- gint offset = g_utf8_pointer_to_offset (label->label,
- label->label + label->select_info->selection_end);
+ gint offset = g_utf8_pointer_to_offset (label->text,
+ label->text + label->select_info->selection_end);
g_value_set_int (value, offset);
}
else
case PROP_SELECTION_BOUND:
if (label->select_info)
{
- gint offset = g_utf8_pointer_to_offset (label->label,
- label->label + label->select_info->selection_anchor);
+ gint offset = g_utf8_pointer_to_offset (label->text,
+ label->text + label->select_info->selection_anchor);
g_value_set_int (value, offset);
}
else
g_value_set_int (value, 0);
break;
+ case PROP_ELLIPSIZE:
+ g_value_set_enum (value, label->ellipsize);
+ break;
+ case PROP_WIDTH_CHARS:
+ g_value_set_int (value, gtk_label_get_width_chars (label));
+ break;
+ case PROP_SINGLE_LINE_MODE:
+ g_value_set_boolean (value, gtk_label_get_single_line_mode (label));
+ break;
+ case PROP_ANGLE:
+ g_value_set_double (value, gtk_label_get_angle (label));
+ break;
+ case PROP_MAX_WIDTH_CHARS:
+ g_value_set_int (value, gtk_label_get_max_width_chars (label));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
static void
gtk_label_init (GtkLabel *label)
{
+ GtkLabelPrivate *priv;
+
GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
-
+
+ priv = GTK_LABEL_GET_PRIVATE (label);
+ priv->width_chars = -1;
+ priv->max_width_chars = -1;
+ priv->wrap_width = -1;
label->label = NULL;
label->jtype = GTK_JUSTIFY_LEFT;
label->wrap = FALSE;
+ label->wrap_mode = PANGO_WRAP_WORD;
+ label->ellipsize = PANGO_ELLIPSIZE_NONE;
label->use_underline = FALSE;
label->use_markup = FALSE;
{
GtkLabel *label;
- label = gtk_type_new (GTK_TYPE_LABEL);
+ label = g_object_new (GTK_TYPE_LABEL, NULL);
if (str && *str)
gtk_label_set_text (label, str);
* Creates a new #GtkLabel, containing the text in @str.
*
* If characters in @str are preceded by an underscore, they are
- * underlined indicating that they represent a keyboard accelerator
- * called a mnemonic. The mnemonic key can be used to activate
- * another widget, chosen automatically, or explicitly using
+ * underlined. If you need a literal underscore character in a label, use
+ * '__' (two underscores). The first underlined character represents a
+ * keyboard accelerator called a mnemonic. The mnemonic key can be used
+ * to activate another widget, chosen automatically, or explicitly using
* gtk_label_set_mnemonic_widget().
*
* If gtk_label_set_mnemonic_widget()
{
GtkLabel *label;
- label = gtk_type_new (GTK_TYPE_LABEL);
+ label = g_object_new (GTK_TYPE_LABEL, NULL);
if (str && *str)
gtk_label_set_text_with_mnemonic (label, str);
* widget's ancestry.
*/
parent = widget->parent;
+
+ if (parent && GTK_IS_NOTEBOOK (parent))
+ return FALSE;
+
while (parent)
{
if (GTK_WIDGET_CAN_FOCUS (parent) ||
/* barf if there was nothing to activate */
g_warning ("Couldn't find a target for a mnemonic activation.");
- gdk_beep ();
-
+ gtk_widget_error_bell (widget);
+
return FALSE;
}
gtk_label_setup_mnemonic (GtkLabel *label,
guint last_key)
{
+ GtkWidget *widget = GTK_WIDGET (label);
GtkWidget *toplevel;
-
- if (last_key != GDK_VoidSymbol && label->mnemonic_window)
+ GtkWidget *mnemonic_menu;
+
+ mnemonic_menu = g_object_get_data (G_OBJECT (label), "gtk-mnemonic-menu");
+
+ if (last_key != GDK_VoidSymbol)
{
- gtk_window_remove_mnemonic (label->mnemonic_window,
- last_key,
- GTK_WIDGET (label));
- label->mnemonic_window = NULL;
+ if (label->mnemonic_window)
+ {
+ gtk_window_remove_mnemonic (label->mnemonic_window,
+ last_key,
+ widget);
+ label->mnemonic_window = NULL;
+ }
+ if (mnemonic_menu)
+ {
+ _gtk_menu_shell_remove_mnemonic (GTK_MENU_SHELL (mnemonic_menu),
+ last_key,
+ widget);
+ mnemonic_menu = NULL;
+ }
}
if (label->mnemonic_keyval == GDK_VoidSymbol)
- return;
-
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
+ goto done;
+
+ toplevel = gtk_widget_get_toplevel (widget);
if (GTK_WIDGET_TOPLEVEL (toplevel))
{
- gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
- label->mnemonic_keyval,
- GTK_WIDGET (label));
- label->mnemonic_window = GTK_WINDOW (toplevel);
+ GtkWidget *menu_shell;
+
+ menu_shell = gtk_widget_get_ancestor (widget,
+ GTK_TYPE_MENU_SHELL);
+
+ if (menu_shell)
+ {
+ _gtk_menu_shell_add_mnemonic (GTK_MENU_SHELL (menu_shell),
+ label->mnemonic_keyval,
+ widget);
+ mnemonic_menu = menu_shell;
+ }
+
+ if (!(menu_shell && GTK_IS_MENU (menu_shell)))
+ {
+ gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
+ label->mnemonic_keyval,
+ widget);
+ label->mnemonic_window = GTK_WINDOW (toplevel);
+ }
}
+
+ done:
+ g_object_set_data (G_OBJECT (label), I_("gtk-mnemonic-menu"), mnemonic_menu);
}
static void
GtkWidget *old_toplevel)
{
GtkLabel *label = GTK_LABEL (widget);
-
+
gtk_label_setup_mnemonic (label, label->mnemonic_keyval);
}
+static void
+label_shortcut_setting_apply (GtkLabel *label)
+{
+ gtk_label_recalculate (label);
+ if (GTK_IS_ACCEL_LABEL (label))
+ gtk_accel_label_refetch (GTK_ACCEL_LABEL (label));
+}
+
+static void
+label_shortcut_setting_traverse_container (GtkWidget *widget,
+ gpointer data)
+{
+ if (GTK_IS_LABEL (widget))
+ label_shortcut_setting_apply (GTK_LABEL (widget));
+ else if (GTK_IS_CONTAINER (widget))
+ gtk_container_forall (GTK_CONTAINER (widget),
+ label_shortcut_setting_traverse_container, data);
+}
+
+static void
+label_shortcut_setting_changed (GtkSettings *settings)
+{
+ GList *list, *l;
+
+ list = gtk_window_list_toplevels ();
+
+ for (l = list; l ; l = l->next)
+ {
+ GtkWidget *widget = l->data;
+
+ if (gtk_widget_get_settings (widget) == settings)
+ gtk_container_forall (GTK_CONTAINER (widget),
+ label_shortcut_setting_traverse_container, NULL);
+ }
+
+ g_list_free (list);
+}
+
+static void
+gtk_label_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen)
+{
+ GtkSettings *settings;
+ gboolean shortcuts_connected;
+
+ if (!gtk_widget_has_screen (widget))
+ return;
+
+ settings = gtk_widget_get_settings (widget);
+
+ shortcuts_connected =
+ GPOINTER_TO_INT (g_object_get_data (G_OBJECT (settings),
+ "gtk-label-shortcuts-connected"));
+
+ if (! shortcuts_connected)
+ {
+ g_signal_connect (settings, "notify::gtk-enable-mnemonics",
+ G_CALLBACK (label_shortcut_setting_changed),
+ NULL);
+ g_signal_connect (settings, "notify::gtk-enable-accels",
+ G_CALLBACK (label_shortcut_setting_changed),
+ NULL);
+
+ g_object_set_data (G_OBJECT (settings), "gtk-label-shortcuts-connected",
+ GINT_TO_POINTER (TRUE));
+ }
+
+ label_shortcut_setting_apply (GTK_LABEL (widget));
+}
+
+
+static void
+label_mnemonic_widget_weak_notify (gpointer data,
+ GObject *where_the_object_was)
+{
+ GtkLabel *label = data;
+
+ label->mnemonic_widget = NULL;
+ g_object_notify (G_OBJECT (label), "mnemonic-widget");
+}
/**
* gtk_label_set_mnemonic_widget:
g_return_if_fail (GTK_IS_WIDGET (widget));
if (label->mnemonic_widget)
- gtk_widget_unref (label->mnemonic_widget);
+ {
+ gtk_widget_remove_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
+ g_object_weak_unref (G_OBJECT (label->mnemonic_widget),
+ label_mnemonic_widget_weak_notify,
+ label);
+ }
label->mnemonic_widget = widget;
if (label->mnemonic_widget)
- gtk_widget_ref (label->mnemonic_widget);
+ {
+ g_object_weak_ref (G_OBJECT (label->mnemonic_widget),
+ label_mnemonic_widget_weak_notify,
+ label);
+ gtk_widget_add_mnemonic_label (label->mnemonic_widget, GTK_WIDGET (label));
+ }
+
+ g_object_notify (G_OBJECT (label), "mnemonic-widget");
}
/**
val = val != FALSE;
if (label->use_markup != val)
{
- g_object_notify (G_OBJECT (label), "use_markup");
label->use_markup = val;
+
+ g_object_notify (G_OBJECT (label), "use-markup");
}
}
val = val != FALSE;
if (label->use_underline != val)
{
- g_object_notify (G_OBJECT (label), "use_underline");
label->use_underline = val;
+
+ g_object_notify (G_OBJECT (label), "use-underline");
}
}
if (!label->use_markup && !label->use_underline)
{
- pango_attr_list_ref (attrs);
+ if (attrs)
+ pango_attr_list_ref (attrs);
if (label->effective_attrs)
pango_attr_list_unref (label->effective_attrs);
label->effective_attrs = attrs;
{
g_return_if_fail (GTK_IS_LABEL (label));
+ g_object_freeze_notify (G_OBJECT (label));
+
gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
gtk_label_set_use_markup_internal (label, FALSE);
gtk_label_set_use_underline_internal (label, FALSE);
gtk_label_recalculate (label);
+
+ g_object_thaw_notify (G_OBJECT (label));
}
/**
*
* Sets a #PangoAttrList; the attributes in the list are applied to the
* label text. The attributes set with this function will be ignored
- * if label->use_underline or label->use_markup is %TRUE.
+ * if the "use_underline" property or the "use_markup" property
+ * is %TRUE.
**/
void
gtk_label_set_attributes (GtkLabel *label,
with_uline ? &accel_char : NULL,
&error))
{
- g_warning ("Failed to set label from markup due to error parsing markup: %s",
+ g_warning ("Failed to set text from markup due to error parsing markup: %s",
error->message);
g_error_free (error);
return;
* @label: a #GtkLabel
* @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
*
- * Parses @str which is marked up with the Pango text markup language,
- * setting the label's text and attribute list based on the parse results.
+ * Parses @str which is marked up with the <link
+ * linkend="PangoMarkupFormat">Pango text markup language</link>, setting the
+ * label's text and attribute list based on the parse results. If the @str is
+ * external data, you may need to escape it with g_markup_escape_text() or
+ * g_markup_printf_escaped()<!-- -->:
+ * <informalexample><programlisting>
+ * char *markup;
+ * <!-- -->
+ * markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", str);
+ * gtk_label_set_markup (GTK_LABEL (label), markup);
+ * g_free (markup);
+ * </programlisting></informalexample>
**/
void
gtk_label_set_markup (GtkLabel *label,
{
g_return_if_fail (GTK_IS_LABEL (label));
+ g_object_freeze_notify (G_OBJECT (label));
+
gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
gtk_label_set_use_markup_internal (label, TRUE);
gtk_label_set_use_underline_internal (label, FALSE);
gtk_label_recalculate (label);
+
+ g_object_thaw_notify (G_OBJECT (label));
}
/**
* @label: a #GtkLabel
* @str: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
*
- * Parses @str which is marked up with the Pango text markup language,
+ * Parses @str which is marked up with the <link linkend="PangoMarkupFormat">Pango text markup language</link>,
* setting the label's text and attribute list based on the parse results.
* If characters in @str are preceded by an underscore, they are underlined
* indicating that they represent a keyboard accelerator called a mnemonic.
guint last_keyval;
g_return_if_fail (GTK_IS_LABEL (label));
+ g_object_freeze_notify (G_OBJECT (label));
+
last_keyval = label->mnemonic_keyval;
gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
gtk_label_set_use_markup_internal (label, TRUE);
gtk_label_recalculate (label);
gtk_label_setup_mnemonic (label, last_keyval);
+
+ g_object_thaw_notify (G_OBJECT (label));
}
/**
const gchar *pattern)
{
PangoAttrList *attrs;
+ gboolean enable_mnemonics;
+
g_return_if_fail (GTK_IS_LABEL (label));
-
- attrs = gtk_label_pattern_to_attrs (label, pattern);
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
+ "gtk-enable-mnemonics", &enable_mnemonics,
+ NULL);
+
+ if (enable_mnemonics && pattern)
+ attrs = gtk_label_pattern_to_attrs (label, pattern);
+ else
+ attrs = NULL;
if (label->effective_attrs)
pango_attr_list_unref (label->effective_attrs);
* @jtype: a #GtkJustification
*
* Sets the alignment of the lines in the text of the label relative to
- * each other. %GTK_JUSTIFY_CENTER is the default value when the
- * widget is first created with gtk_label_new().
+ * each other. %GTK_JUSTIFY_LEFT is the default value when the
+ * widget is first created with gtk_label_new(). If you instead want
+ * to set the alignment of the label as a whole, use
+ * gtk_misc_set_alignment() instead. gtk_label_set_justify() has no
+ * effect on labels containing only a single line.
**/
void
gtk_label_set_justify (GtkLabel *label,
return label->jtype;
}
+/**
+ * gtk_label_set_ellipsize:
+ * @label: a #GtkLabel
+ * @mode: a #PangoEllipsizeMode
+ *
+ * Sets the mode used to ellipsize (add an ellipsis: "...") to the text if there
+ * is not enough space to render the entire string.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_label_set_ellipsize (GtkLabel *label,
+ PangoEllipsizeMode mode)
+{
+ g_return_if_fail (GTK_IS_LABEL (label));
+ g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
+
+ if ((PangoEllipsizeMode) label->ellipsize != mode)
+ {
+ label->ellipsize = mode;
+
+ /* No real need to be this drastic, but easier than duplicating the code */
+ gtk_label_clear_layout (label);
+
+ g_object_notify (G_OBJECT (label), "ellipsize");
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+ }
+}
+
+/**
+ * gtk_label_get_ellipsize:
+ * @label: a #GtkLabel
+ *
+ * Returns the ellipsizing position of the label. See gtk_label_set_ellipsize().
+ *
+ * Return value: #PangoEllipsizeMode
+ *
+ * Since: 2.6
+ **/
+PangoEllipsizeMode
+gtk_label_get_ellipsize (GtkLabel *label)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
+
+ return label->ellipsize;
+}
+
+/**
+ * gtk_label_set_width_chars:
+ * @label: a #GtkLabel
+ * @n_chars: the new desired width, in characters.
+ *
+ * Sets the desired width in characters of @label to @n_chars.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_label_set_width_chars (GtkLabel *label,
+ gint n_chars)
+{
+ GtkLabelPrivate *priv;
+
+ g_return_if_fail (GTK_IS_LABEL (label));
+
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
+ if (priv->width_chars != n_chars)
+ {
+ priv->width_chars = n_chars;
+ g_object_notify (G_OBJECT (label), "width-chars");
+ gtk_label_invalidate_wrap_width (label);
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+ }
+}
+
+/**
+ * gtk_label_get_width_chars:
+ * @label: a #GtkLabel
+ *
+ * Retrieves the desired width of @label, in characters. See
+ * gtk_label_set_width_chars().
+ *
+ * Return value: the width of the label in characters.
+ *
+ * Since: 2.6
+ **/
+gint
+gtk_label_get_width_chars (GtkLabel *label)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (label), -1);
+
+ return GTK_LABEL_GET_PRIVATE (label)->width_chars;
+}
+
+/**
+ * gtk_label_set_max_width_chars:
+ * @label: a #GtkLabel
+ * @n_chars: the new desired maximum width, in characters.
+ *
+ * Sets the desired maximum width in characters of @label to @n_chars.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_label_set_max_width_chars (GtkLabel *label,
+ gint n_chars)
+{
+ GtkLabelPrivate *priv;
+
+ g_return_if_fail (GTK_IS_LABEL (label));
+
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
+ if (priv->max_width_chars != n_chars)
+ {
+ priv->max_width_chars = n_chars;
+
+ g_object_notify (G_OBJECT (label), "max-width-chars");
+ gtk_label_invalidate_wrap_width (label);
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+ }
+}
+
+/**
+ * gtk_label_get_max_width_chars:
+ * @label: a #GtkLabel
+ *
+ * Retrieves the desired maximum width of @label, in characters. See
+ * gtk_label_set_width_chars().
+ *
+ * Return value: the maximum width of the label in characters.
+ *
+ * Since: 2.6
+ **/
+gint
+gtk_label_get_max_width_chars (GtkLabel *label)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (label), -1);
+
+ return GTK_LABEL_GET_PRIVATE (label)->max_width_chars;
+}
+
/**
* gtk_label_set_line_wrap:
* @label: a #GtkLabel
* Toggles line wrapping within the #GtkLabel widget. %TRUE makes it break
* lines if text exceeds the widget's size. %FALSE lets the text get cut off
* by the edge of the widget if it exceeds the widget size.
+ *
+ * Note that setting line wrapping to %TRUE does not make the label
+ * wrap at its parent container's width, because GTK+ widgets
+ * conceptually can't make their requisition depend on the parent
+ * container's size. For a label that wraps at a specific position,
+ * set the label's width using gtk_widget_set_size_request().
**/
void
gtk_label_set_line_wrap (GtkLabel *label,
if (label->wrap != wrap)
{
label->wrap = wrap;
- g_object_notify (G_OBJECT (label), "wrap");
-
+
+ gtk_label_clear_layout (label);
gtk_widget_queue_resize (GTK_WIDGET (label));
+ g_object_notify (G_OBJECT (label), "wrap");
}
}
return label->wrap;
}
+/**
+ * gtk_label_set_line_wrap_mode:
+ * @label: a #GtkLabel
+ * @wrap_mode: the line wrapping mode
+ *
+ * If line wrapping is on (see gtk_label_set_line_wrap()) this controls how
+ * the line wrapping is done. The default is %PANGO_WRAP_WORD which means
+ * wrap on word boundaries.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_label_set_line_wrap_mode (GtkLabel *label,
+ PangoWrapMode wrap_mode)
+{
+ g_return_if_fail (GTK_IS_LABEL (label));
+
+ if (label->wrap_mode != wrap_mode)
+ {
+ label->wrap_mode = wrap_mode;
+ g_object_notify (G_OBJECT (label), "wrap-mode");
+
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+ }
+}
+
+/**
+ * gtk_label_get_line_wrap_mode:
+ * @label: a #GtkLabel
+ *
+ * Returns line wrap mode used by the label. See gtk_label_set_line_wrap_mode ().
+ *
+ * Return value: %TRUE if the lines of the label are automatically wrapped.
+ *
+ * Since: 2.10
+ */
+PangoWrapMode
+gtk_label_get_line_wrap_mode (GtkLabel *label)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+
+ return label->wrap_mode;
+}
+
+
void
gtk_label_get (GtkLabel *label,
gchar **str)
gtk_label_set_mnemonic_widget (label, NULL);
- GTK_OBJECT_CLASS (parent_class)->destroy (object);
+ GTK_OBJECT_CLASS (gtk_label_parent_class)->destroy (object);
}
static void
g_free (label->text);
if (label->layout)
- g_object_unref (G_OBJECT (label->layout));
+ g_object_unref (label->layout);
if (label->attrs)
pango_attr_list_unref (label->attrs);
g_free (label->select_info);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
}
static void
{
if (label->layout)
{
- g_object_unref (G_OBJECT (label->layout));
+ g_object_unref (label->layout);
label->layout = NULL;
}
}
+static gint
+get_label_char_width (GtkLabel *label)
+{
+ GtkLabelPrivate *priv;
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+ gint char_width, digit_width, char_pixels, w;
+
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
+ context = pango_layout_get_context (label->layout);
+ metrics = pango_context_get_metrics (context, GTK_WIDGET (label)->style->font_desc,
+ pango_context_get_language (context));
+
+ char_width = pango_font_metrics_get_approximate_char_width (metrics);
+ digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
+ char_pixels = MAX (char_width, digit_width);
+ pango_font_metrics_unref (metrics);
+
+ if (priv->width_chars < 0)
+ {
+ PangoRectangle rect;
+
+ pango_layout_set_width (label->layout, -1);
+ pango_layout_get_extents (label->layout, NULL, &rect);
+
+ w = char_pixels * MAX (priv->max_width_chars, 3);
+ w = MIN (rect.width, w);
+ }
+ else
+ {
+ /* enforce minimum width for ellipsized labels at ~3 chars */
+ w = char_pixels * MAX (priv->width_chars, 3);
+ }
+
+ return w;
+}
+
+static void
+gtk_label_invalidate_wrap_width (GtkLabel *label)
+{
+ GtkLabelPrivate *priv;
+
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
+ priv->wrap_width = -1;
+}
+
+static gint
+get_label_wrap_width (GtkLabel *label)
+{
+ GtkLabelPrivate *priv;
+
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
+ if (priv->wrap_width < 0)
+ {
+ if (priv->width_chars > 0 || priv->max_width_chars > 0)
+ priv->wrap_width = get_label_char_width (label);
+ else
+ {
+ PangoLayout *layout;
+
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
+ "This long string gives a good enough length for any line to have.");
+ pango_layout_get_size (layout, &priv->wrap_width, NULL);
+ g_object_unref (layout);
+ }
+ }
+
+ return priv->wrap_width;
+}
+
static void
gtk_label_ensure_layout (GtkLabel *label)
{
GtkWidget *widget;
PangoRectangle logical_rect;
- gint rwidth, rheight;
+ gboolean rtl;
widget = GTK_WIDGET (label);
- rwidth = label->misc.xpad * 2;
- rheight = label->misc.ypad * 2;
+ rtl = gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL;
if (!label->layout)
{
PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
+ gdouble angle = gtk_label_get_angle (label);
+
+ if (angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
+ {
+ /* We rotate the standard singleton PangoContext for the widget,
+ * depending on the fact that it's meant pretty much exclusively
+ * for our use.
+ */
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+
+ pango_matrix_rotate (&matrix, angle);
+
+ pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
+
+ label->have_transform = TRUE;
+ }
+ else
+ {
+ if (label->have_transform)
+ pango_context_set_matrix (gtk_widget_get_pango_context (widget), NULL);
+
+ label->have_transform = FALSE;
+ }
label->layout = gtk_widget_create_pango_layout (widget, label->text);
switch (label->jtype)
{
case GTK_JUSTIFY_LEFT:
- align = PANGO_ALIGN_LEFT;
+ align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
break;
case GTK_JUSTIFY_RIGHT:
- align = PANGO_ALIGN_RIGHT;
+ align = rtl ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
break;
case GTK_JUSTIFY_CENTER:
align = PANGO_ALIGN_CENTER;
break;
case GTK_JUSTIFY_FILL:
/* FIXME: This just doesn't work to do this */
- align = PANGO_ALIGN_LEFT;
+ align = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
pango_layout_set_justify (label->layout, TRUE);
break;
default:
}
pango_layout_set_alignment (label->layout, align);
+ pango_layout_set_ellipsize (label->layout, label->ellipsize);
+ pango_layout_set_single_paragraph_mode (label->layout, label->single_line_mode);
- if (label->wrap)
+ if (label->ellipsize)
+ pango_layout_set_width (label->layout,
+ widget->allocation.width * PANGO_SCALE);
+ else if (label->wrap)
{
GtkWidgetAuxInfo *aux_info;
gint longest_paragraph;
gint width, height;
+
+ pango_layout_set_wrap (label->layout, label->wrap_mode);
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (aux_info && aux_info->width > 0)
pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
else
{
+ GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
+ gint wrap_width;
+
pango_layout_set_width (label->layout, -1);
pango_layout_get_extents (label->layout, NULL, &logical_rect);
/* Try to guess a reasonable maximum width */
longest_paragraph = width;
-
- width = MIN (width,
- PANGO_SCALE * gdk_string_width (gtk_style_get_font (GTK_WIDGET (label)->style),
- "This long string gives a good enough length for any line to have."));
+
+ wrap_width = get_label_wrap_width (label);
+ width = MIN (width, wrap_width);
width = MIN (width,
- PANGO_SCALE * (gdk_screen_width () + 1) / 2);
+ PANGO_SCALE * (gdk_screen_get_width (screen) + 1) / 2);
pango_layout_set_width (label->layout, width);
pango_layout_get_extents (label->layout, NULL, &logical_rect);
+ width = logical_rect.width;
height = logical_rect.height;
/* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
pango_layout_get_extents (label->layout, NULL, &logical_rect);
if (logical_rect.height <= height)
- width = perfect_width;
+ width = logical_rect.width;
else
{
gint mid_width = (perfect_width + width) / 2;
pango_layout_get_extents (label->layout, NULL, &logical_rect);
if (logical_rect.height <= height)
- width = mid_width;
+ width = logical_rect.width;
}
}
}
pango_layout_set_width (label->layout, width);
}
}
- else /* !label->wrap */
+ else /* !label->wrap */
pango_layout_set_width (label->layout, -1);
}
}
GtkRequisition *requisition)
{
GtkLabel *label;
+ GtkLabelPrivate *priv;
gint width, height;
PangoRectangle logical_rect;
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (requisition != NULL);
label = GTK_LABEL (widget);
+ priv = GTK_LABEL_GET_PRIVATE (widget);
/*
* If word wrapping is on, then the height requisition can depend
width = label->misc.xpad * 2;
height = label->misc.ypad * 2;
- pango_layout_get_extents (label->layout, NULL, &logical_rect);
-
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
- if (label->wrap && aux_info && aux_info->width > 0)
+
+ if (label->have_transform)
+ {
+ PangoRectangle rect;
+ PangoContext *context = pango_layout_get_context (label->layout);
+ const PangoMatrix *matrix = pango_context_get_matrix (context);
+
+ pango_layout_get_extents (label->layout, NULL, &rect);
+ pango_matrix_transform_rectangle (matrix, &rect);
+ pango_extents_to_pixels (&rect, NULL);
+
+ requisition->width = width + rect.width;
+ requisition->height = height + rect.height;
+
+ return;
+ }
+ else
+ pango_layout_get_extents (label->layout, NULL, &logical_rect);
+
+ if ((label->wrap || label->ellipsize ||
+ priv->width_chars > 0 || priv->max_width_chars > 0) &&
+ aux_info && aux_info->width > 0)
width += aux_info->width;
- else
+ else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
+ {
+ width += PANGO_PIXELS (get_label_char_width (label));
+ }
+ else
width += PANGO_PIXELS (logical_rect.width);
-
- height += PANGO_PIXELS (logical_rect.height);
+
+ if (label->single_line_mode)
+ {
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+ gint ascent, descent;
+
+ context = pango_layout_get_context (label->layout);
+ metrics = pango_context_get_metrics (context, widget->style->font_desc,
+ pango_context_get_language (context));
+
+ ascent = pango_font_metrics_get_ascent (metrics);
+ descent = pango_font_metrics_get_descent (metrics);
+ pango_font_metrics_unref (metrics);
+
+ height += PANGO_PIXELS (ascent + descent);
+ }
+ else
+ height += PANGO_PIXELS (logical_rect.height);
requisition->width = width;
requisition->height = height;
label = GTK_LABEL (widget);
- (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
+ (* GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate) (widget, allocation);
+
+ if (label->ellipsize)
+ {
+ if (label->layout)
+ {
+ gint width;
+ PangoRectangle logical;
+
+ width = (allocation->width - label->misc.xpad * 2) * PANGO_SCALE;
+
+ pango_layout_set_width (label->layout, -1);
+ pango_layout_get_extents (label->layout, NULL, &logical);
+
+ if (logical.width > width)
+ pango_layout_set_width (label->layout, width);
+ }
+ }
if (label->select_info && label->select_info->window)
{
GtkStateType prev_state)
{
GtkLabel *label;
+ GdkCursor *cursor;
label = GTK_LABEL (widget);
if (label->select_info)
- gtk_label_select_region (label, 0, 0);
+ {
+ gtk_label_select_region (label, 0, 0);
+
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ if (GTK_WIDGET_IS_SENSITIVE (widget))
+ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
+ else
+ cursor = NULL;
+
+ gdk_window_set_cursor (label->select_info->window, cursor);
+
+ if (cursor)
+ gdk_cursor_unref (cursor);
+ }
+ }
- if (GTK_WIDGET_CLASS (parent_class)->state_changed)
- GTK_WIDGET_CLASS (parent_class)->state_changed (widget, prev_state);
+ if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_changed)
+ GTK_WIDGET_CLASS (gtk_label_parent_class)->state_changed (widget, prev_state);
}
static void
/* We have to clear the layout, fonts etc. may have changed */
gtk_label_clear_layout (label);
+ gtk_label_invalidate_wrap_width (label);
}
static void
if (label->layout)
pango_layout_context_changed (label->layout);
- GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
+ GTK_WIDGET_CLASS (gtk_label_parent_class)->direction_changed (widget, previous_dir);
}
-#if 0
-static void
-gtk_label_paint_word (GtkLabel *label,
- gint x,
- gint y,
- GtkLabelWord *word,
- GdkRectangle *area)
-{
- GtkWidget *widget = GTK_WIDGET (label);
- GtkLabelULine *uline;
- gchar *tmp_str;
-
- tmp_str = gdk_wcstombs (word->beginning);
- if (tmp_str)
- {
- gtk_paint_string (widget->style, widget->window, widget->state,
- area, widget, "label",
- x + word->x,
- y + word->y,
- tmp_str);
- g_free (tmp_str);
- }
-
- for (uline = word->uline; uline; uline = uline->next)
- gtk_paint_hline (widget->style, widget->window,
- widget->state, area,
- widget, "label",
- x + uline->x1, x + uline->x2, y + uline->y);
-}
-#endif
-
static void
get_layout_location (GtkLabel *label,
gint *xp,
gint *yp)
{
GtkMisc *misc;
- GtkWidget *widget;
+ GtkWidget *widget;
+ GtkLabelPrivate *priv;
gfloat xalign;
- gint x, y;
+ gint req_width, x, y;
misc = GTK_MISC (label);
widget = GTK_WIDGET (label);
-
+ priv = GTK_LABEL_GET_PRIVATE (label);
+
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
xalign = misc->xalign;
else
xalign = 1.0 - misc->xalign;
-
- x = floor (widget->allocation.x + (gint)misc->xpad
- + ((widget->allocation.width - widget->requisition.width) * xalign)
- + 0.5);
-
+
+ if (label->ellipsize || priv->width_chars > 0)
+ {
+ int width;
+ PangoRectangle logical;
+
+ width = pango_layout_get_width (label->layout);
+ pango_layout_get_pixel_extents (label->layout, NULL, &logical);
+
+ req_width = logical.width;
+ if (width != -1)
+ req_width = MIN(PANGO_PIXELS (width), req_width);
+ req_width += 2 * misc->xpad;
+ }
+ else
+ req_width = widget->requisition.width;
+
+ x = floor (widget->allocation.x + (gint)misc->xpad +
+ xalign * (widget->allocation.width - req_width));
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+ x = MAX (x, widget->allocation.x + misc->xpad);
+ else
+ x = MIN (x, widget->allocation.x + widget->allocation.width - misc->xpad);
+
y = floor (widget->allocation.y + (gint)misc->ypad
- + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
- + 0.5);
-
+ + MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign),
+ 0));
+
+ if (xp)
+ *xp = x;
+
+ if (yp)
+ *yp = y;
+}
+
+static void
+draw_insertion_cursor (GtkLabel *label,
+ GdkRectangle *cursor_location,
+ gboolean is_primary,
+ PangoDirection direction,
+ gboolean draw_arrow)
+{
+ GtkWidget *widget = GTK_WIDGET (label);
+ GtkTextDirection text_dir;
+
+ if (direction == PANGO_DIRECTION_LTR)
+ text_dir = GTK_TEXT_DIR_LTR;
+ else
+ text_dir = GTK_TEXT_DIR_RTL;
- if (xp)
- *xp = x;
+ gtk_draw_insertion_cursor (widget, widget->window, &(widget->allocation),
+ cursor_location,
+ is_primary, text_dir, draw_arrow);
+}
- if (yp)
- *yp = y;
+static PangoDirection
+get_cursor_direction (GtkLabel *label)
+{
+ GSList *l;
+
+ g_assert (label->select_info);
+
+ gtk_label_ensure_layout (label);
+
+ for (l = pango_layout_get_lines_readonly (label->layout); l; l = l->next)
+ {
+ PangoLayoutLine *line = l->data;
+
+ /* If label->select_info->selection_end is at the very end of
+ * the line, we don't know if the cursor is on this line or
+ * the next without looking ahead at the next line. (End
+ * of paragraph is different from line break.) But it's
+ * definitely in this paragraph, which is good enough
+ * to figure out the resolved direction.
+ */
+ if (line->start_index + line->length >= label->select_info->selection_end)
+ return line->resolved_dir;
+ }
+
+ return PANGO_DIRECTION_LTR;
}
static void
{
GtkWidget *widget = GTK_WIDGET (label);
- GtkTextDirection keymap_direction;
- GtkTextDirection widget_direction;
+ PangoDirection keymap_direction;
+ PangoDirection cursor_direction;
PangoRectangle strong_pos, weak_pos;
gboolean split_cursor;
PangoRectangle *cursor1 = NULL;
PangoRectangle *cursor2 = NULL;
GdkRectangle cursor_location;
- GtkTextDirection dir1 = GTK_TEXT_DIR_NONE;
- GtkTextDirection dir2 = GTK_TEXT_DIR_NONE;
- GdkGC *gc1 = NULL;
- GdkGC *gc2 = NULL;
-
- keymap_direction =
- (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
- GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
+ PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
+ PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
- widget_direction = gtk_widget_get_direction (widget);
+ keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
+ cursor_direction = get_cursor_direction (label);
gtk_label_ensure_layout (label);
"gtk-split-cursor", &split_cursor,
NULL);
+ dir1 = cursor_direction;
+
if (split_cursor)
{
- gc1 = label->select_info->cursor_gc;
cursor1 = &strong_pos;
if (strong_pos.x != weak_pos.x ||
strong_pos.y != weak_pos.y)
{
- dir1 = widget_direction;
- dir2 = (widget_direction == GTK_TEXT_DIR_LTR) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
-
- gc2 = widget->style->black_gc;
+ dir2 = (cursor_direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
cursor2 = &weak_pos;
}
}
else
{
- gc1 = label->select_info->cursor_gc;
-
- if (keymap_direction == widget_direction)
+ if (keymap_direction == cursor_direction)
cursor1 = &strong_pos;
else
cursor1 = &weak_pos;
cursor_location.y = yoffset + PANGO_PIXELS (cursor1->y);
cursor_location.width = 0;
cursor_location.height = PANGO_PIXELS (cursor1->height);
+
+ draw_insertion_cursor (label,
+ &cursor_location, TRUE, dir1,
+ dir2 != PANGO_DIRECTION_NEUTRAL);
- _gtk_draw_insertion_cursor (widget->window, gc1,
- &cursor_location, dir1);
-
- if (gc2)
+ if (dir2 != PANGO_DIRECTION_NEUTRAL)
{
cursor_location.x = xoffset + PANGO_PIXELS (cursor2->x);
cursor_location.y = yoffset + PANGO_PIXELS (cursor2->y);
cursor_location.width = 0;
cursor_location.height = PANGO_PIXELS (cursor2->height);
-
- _gtk_draw_insertion_cursor (widget->window, gc2,
- &cursor_location, dir2);
+
+ draw_insertion_cursor (label,
+ &cursor_location, FALSE, dir2,
+ TRUE);
}
}
}
label->text && (*label->text != '\0'))
{
get_layout_location (label, &x, &y);
-
+
gtk_paint_layout (widget->style,
widget->window,
GTK_WIDGET_STATE (widget),
x, y,
range,
1);
-
- /* FIXME should use gtk_paint, but it can't use a clip
+ gdk_region_intersect (clip, event->region);
+
+ /* FIXME should use gtk_paint, but it can't use a clip
* region
*/
g_return_if_fail (GTK_IS_LABEL (label));
g_return_if_fail (str != NULL);
- /* Convert text to wide characters */
-
+ /* Split text into the base text and a separate pattern
+ * of underscores.
+ */
+
new_str = g_new (gchar, strlen (str) + 1);
pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
{
*pattern_dest++ = '_';
if (accel_key == GDK_VoidSymbol)
- accel_key = gdk_keyval_to_lower (c);
+ accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
}
while (src < next_src)
g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
orig_keyval = label->mnemonic_keyval;
+
+ g_object_freeze_notify (G_OBJECT (label));
gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
gtk_label_set_use_markup_internal (label, FALSE);
gtk_label_setup_mnemonic (label, orig_keyval);
+ g_object_thaw_notify (G_OBJECT (label));
+
return keyval;
}
g_return_if_fail (str != NULL);
last_keyval = label->mnemonic_keyval;
-
+
+ g_object_freeze_notify (G_OBJECT (label));
+
gtk_label_set_label_internal (label, g_strdup (str ? str : ""));
gtk_label_set_use_markup_internal (label, FALSE);
gtk_label_set_use_underline_internal (label, TRUE);
gtk_label_recalculate (label);
gtk_label_setup_mnemonic (label, last_keyval);
-}
-
-static void
-gtk_label_realize_cursor_gc (GtkLabel *label)
-{
- GdkColor *cursor_color;
- GdkColor red = {0, 0xffff, 0x0000, 0x0000};
-
- if (label->select_info == NULL)
- return;
-
- if (label->select_info->cursor_gc)
- gdk_gc_unref (label->select_info->cursor_gc);
- gtk_widget_style_get (GTK_WIDGET (label), "cursor_color", &cursor_color, NULL);
- label->select_info->cursor_gc = gdk_gc_new (GTK_WIDGET (label)->window);
- if (cursor_color)
- gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, cursor_color);
- else
- gdk_gc_set_rgb_fg_color (label->select_info->cursor_gc, &red);
+ g_object_thaw_notify (G_OBJECT (label));
}
static void
label = GTK_LABEL (widget);
- (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
+ (* GTK_WIDGET_CLASS (gtk_label_parent_class)->realize) (widget);
if (label->select_info)
- {
- gtk_label_create_window (label);
- gtk_label_realize_cursor_gc (label);
- }
-}
-
-static void
-gtk_label_unrealize_cursor_gc (GtkLabel *label)
-{
- if (label->select_info == NULL)
- return;
-
- if (label->select_info->cursor_gc)
- {
- gdk_gc_unref (label->select_info->cursor_gc);
- label->select_info->cursor_gc = NULL;
- }
+ gtk_label_create_window (label);
}
static void
label = GTK_LABEL (widget);
if (label->select_info)
- {
- gtk_label_unrealize_cursor_gc (label);
- gtk_label_destroy_window (label);
- }
+ gtk_label_destroy_window (label);
- (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+ (* GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize) (widget);
}
static void
label = GTK_LABEL (widget);
- (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
+ (* GTK_WIDGET_CLASS (gtk_label_parent_class)->map) (widget);
if (label->select_info)
gdk_window_show (label->select_info->window);
if (label->select_info)
gdk_window_hide (label->select_info->window);
- (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
+ (* GTK_WIDGET_CLASS (gtk_label_parent_class)->unmap) (widget);
}
static void
gtk_label_select_region_index (label, min, max);
}
-static gint
+static void
+gtk_label_grab_focus (GtkWidget *widget)
+{
+ GtkLabel *label;
+ gboolean select_on_focus;
+
+ label = GTK_LABEL (widget);
+
+ if (label->select_info == NULL)
+ return;
+
+ GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget);
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-label-select-on-focus",
+ &select_on_focus,
+ NULL);
+
+ if (select_on_focus && !label->in_click)
+ gtk_label_select_region (label, 0, -1);
+}
+
+static gboolean
gtk_label_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkLabel *label;
gint index = 0;
+ gint min, max;
label = GTK_LABEL (widget);
if (label->select_info == NULL)
return FALSE;
+ label->select_info->in_drag = FALSE;
if (event->button == 1)
{
- if (!GTK_WIDGET_HAS_FOCUS (widget))
- gtk_widget_grab_focus (widget);
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ {
+ label->in_click = TRUE;
+ gtk_widget_grab_focus (widget);
+ label->in_click = FALSE;
+ }
if (event->type == GDK_3BUTTON_PRESS)
{
- gtk_label_select_region_index (label, 0, strlen (label->label));
+ gtk_label_select_region_index (label, 0, strlen (label->text));
return TRUE;
}
get_layout_index (label, event->x, event->y, &index);
+ min = MIN (label->select_info->selection_anchor,
+ label->select_info->selection_end);
+ max = MAX (label->select_info->selection_anchor,
+ label->select_info->selection_end);
+
if ((label->select_info->selection_anchor !=
label->select_info->selection_end) &&
(event->state & GDK_SHIFT_MASK))
{
- gint min, max;
-
/* extend (same as motion) */
- min = MIN (label->select_info->selection_anchor,
- label->select_info->selection_end);
- max = MAX (label->select_info->selection_anchor,
- label->select_info->selection_end);
-
min = MIN (min, index);
max = MAX (max, index);
gtk_label_select_region_index (label, min, max);
}
- else
+ else
{
if (event->type == GDK_3BUTTON_PRESS)
- gtk_label_select_region_index (label, 0, strlen (label->label));
+ gtk_label_select_region_index (label, 0, strlen (label->text));
else if (event->type == GDK_2BUTTON_PRESS)
- gtk_label_select_word (label);
- else
+ gtk_label_select_word (label);
+ else if (min < max && min <= index && index <= max)
+ {
+ label->select_info->in_drag = TRUE;
+ label->select_info->drag_start_x = event->x;
+ label->select_info->drag_start_y = event->y;
+ }
+ else
/* start a replacement */
gtk_label_select_region_index (label, index, index);
}
return FALSE;
}
-static gint
+static gboolean
gtk_label_button_release (GtkWidget *widget,
GdkEventButton *event)
{
- GtkLabel *label;
-
- label = GTK_LABEL (widget);
+ GtkLabel *label = GTK_LABEL (widget);
+ gint index;
if (label->select_info == NULL)
return FALSE;
+ if (label->select_info->in_drag)
+ {
+ label->select_info->in_drag = 0;
+
+ get_layout_index (label, event->x, event->y, &index);
+ gtk_label_select_region_index (label, index, index);
+
+ return FALSE;
+ }
+
if (event->button != 1)
return FALSE;
return TRUE;
}
-static gint
+static void
+drag_begin_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gpointer data)
+{
+ GtkLabel *label;
+ GdkPixmap *pixmap = NULL;
+
+ g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
+
+ label = GTK_LABEL (widget);
+
+ if ((label->select_info->selection_anchor !=
+ label->select_info->selection_end) &&
+ label->text)
+ {
+ gint start, end;
+ gint len;
+
+ start = MIN (label->select_info->selection_anchor,
+ label->select_info->selection_end);
+ end = MAX (label->select_info->selection_anchor,
+ label->select_info->selection_end);
+
+ len = strlen (label->text);
+
+ if (end > len)
+ end = len;
+
+ if (start > len)
+ start = len;
+
+ pixmap = _gtk_text_util_create_drag_icon (widget,
+ label->text + start,
+ end - start);
+ }
+
+ if (pixmap)
+ gtk_drag_set_icon_pixmap (context,
+ gdk_drawable_get_colormap (pixmap),
+ pixmap,
+ NULL,
+ -2, -2);
+ else
+ gtk_drag_set_icon_default (context);
+
+ if (pixmap)
+ g_object_unref (pixmap);
+}
+
+static gboolean
gtk_label_motion (GtkWidget *widget,
GdkEventMotion *event)
{
if (label->select_info == NULL)
return FALSE;
+
if ((event->state & GDK_BUTTON1_MASK) == 0)
return FALSE;
gdk_window_get_pointer (label->select_info->window,
&x, &y, NULL);
- get_layout_index (label, x, y, &index);
+ if (label->select_info->in_drag)
+ {
+ if (gtk_drag_check_threshold (widget,
+ label->select_info->drag_start_x,
+ label->select_info->drag_start_y,
+ event->x, event->y))
+ {
+ GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
+
+ gtk_target_list_add_text_targets (target_list, 0);
+
+ g_signal_connect (widget, "drag_begin",
+ G_CALLBACK (drag_begin_cb), NULL);
+ gtk_drag_begin (widget, target_list,
+ GDK_ACTION_COPY,
+ 1, (GdkEvent *)event);
+
+ label->select_info->in_drag = FALSE;
+
+ gtk_target_list_unref (target_list);
+ }
+ }
+ else
+ {
+ get_layout_index (label, x, y, &index);
+
+ gtk_label_select_region_index (label,
+ label->select_info->selection_anchor,
+ index);
+ }
- gtk_label_select_region_index (label,
- label->select_info->selection_anchor,
- index);
-
return TRUE;
}
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
- attributes.window_type = GDK_WINDOW_TEMP;
+ attributes.window_type = GDK_WINDOW_CHILD;
attributes.wclass = GDK_INPUT_ONLY;
attributes.override_redirect = TRUE;
attributes.event_mask = gtk_widget_get_events (widget) |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK;
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
+ if (GTK_WIDGET_IS_SENSITIVE (widget))
+ {
+ attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
+ GDK_XTERM);
+ attributes_mask |= GDK_WA_CURSOR;
+ }
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_NOREDIR;
label->select_info->window = gdk_window_new (widget->window,
&attributes, attributes_mask);
- gdk_window_set_user_data (label->select_info->window, widget);
+ gdk_window_set_user_data (label->select_info->window, widget);
+
+ if (attributes_mask & GDK_WA_CURSOR)
+ gdk_cursor_unref (attributes.cursor);
}
static void
GTK_WIDGET_SET_FLAGS (label, GTK_CAN_FOCUS);
if (GTK_WIDGET_REALIZED (label))
- {
- gtk_label_create_window (label);
- gtk_label_realize_cursor_gc (label);
- }
+ gtk_label_create_window (label);
if (GTK_WIDGET_MAPPED (label))
gdk_window_show (label->select_info->window);
/* unselect, to give up the selection */
gtk_label_select_region (label, 0, 0);
- gtk_label_unrealize_cursor_gc (label);
-
if (label->select_info->window)
{
gtk_label_destroy_window (label);
{
g_object_freeze_notify (G_OBJECT (label));
g_object_notify (G_OBJECT (label), "selectable");
- g_object_notify (G_OBJECT (label), "cursor_position");
- g_object_notify (G_OBJECT (label), "selection_bound");
+ g_object_notify (G_OBJECT (label), "cursor-position");
+ g_object_notify (G_OBJECT (label), "selection-bound");
g_object_thaw_notify (G_OBJECT (label));
gtk_widget_queue_draw (GTK_WIDGET (label));
}
}
static void
-get_text_callback (GtkClipboard *clipboard,
- GtkSelectionData *selection_data,
- guint info,
- gpointer user_data_or_owner)
+free_angle (gpointer angle)
{
- GtkLabel *label;
+ g_slice_free (gdouble, angle);
+}
+
+/**
+ * gtk_label_set_angle:
+ * @label: a #GtkLabel
+ * @angle: the angle that the baseline of the label makes with
+ * the horizontal, in degrees, measured counterclockwise
+ *
+ * Sets the angle of rotation for the label. An angle of 90 reads from
+ * from bottom to top, an angle of 270, from top to bottom. The angle
+ * setting for the label is ignored if the label is selectable,
+ * wrapped, or ellipsized.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_label_set_angle (GtkLabel *label,
+ gdouble angle)
+{
+ gdouble *label_angle;
+
+ g_return_if_fail (GTK_IS_LABEL (label));
+
+ label_angle = (gdouble *)g_object_get_qdata (G_OBJECT (label), quark_angle);
+
+ if (!label_angle)
+ {
+ label_angle = g_slice_new (gdouble);
+ *label_angle = 0.0;
+ g_object_set_qdata_full (G_OBJECT (label), quark_angle,
+ label_angle, free_angle);
+ }
- label = GTK_LABEL (user_data_or_owner);
+ /* Canonicalize to [0,360]. We don't canonicalize 360 to 0, because
+ * double property ranges are inclusive, and changing 360 to 0 would
+ * make a property editor behave strangely.
+ */
+ if (angle < 0 || angle > 360.0)
+ angle = angle - 360. * floor (angle / 360.);
+
+ if (*label_angle != angle)
+ {
+ *label_angle = angle;
+
+ gtk_label_clear_layout (label);
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+
+ g_object_notify (G_OBJECT (label), "angle");
+ }
+}
+
+/**
+ * gtk_label_get_angle:
+ * @label: a #GtkLabel
+ *
+ * Gets the angle of rotation for the label. See
+ * gtk_label_set_angle.
+ *
+ * Return value: the angle of rotation for the label
+ *
+ * Since: 2.6
+ **/
+gdouble
+gtk_label_get_angle (GtkLabel *label)
+{
+ gdouble *angle;
+
+ g_return_val_if_fail (GTK_IS_LABEL (label), 0.0);
+ angle = (gdouble *)g_object_get_qdata (G_OBJECT (label), quark_angle);
+
+ if (angle)
+ return *angle;
+ else
+ return 0.0;
+}
+
+static void
+gtk_label_set_selection_text (GtkLabel *label,
+ GtkSelectionData *selection_data)
+{
if ((label->select_info->selection_anchor !=
label->select_info->selection_end) &&
label->text)
label->select_info->selection_end);
end = MAX (label->select_info->selection_anchor,
label->select_info->selection_end);
-
+
len = strlen (label->text);
-
+
if (end > len)
end = len;
-
+
if (start > len)
start = len;
-
+
gtk_selection_data_set_text (selection_data,
label->text + start,
end - start);
}
}
+static void
+gtk_label_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
+}
+
+static void
+get_text_callback (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ guint info,
+ gpointer user_data_or_owner)
+{
+ gtk_label_set_selection_text (GTK_LABEL (user_data_or_owner), selection_data);
+}
+
static void
clear_text_callback (GtkClipboard *clipboard,
gpointer user_data_or_owner)
label->select_info->selection_anchor = anchor_index;
label->select_info->selection_end = end_index;
- clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label),
+ GDK_SELECTION_PRIMARY);
if (anchor_index != end_index)
{
gtk_widget_queue_draw (GTK_WIDGET (label));
g_object_freeze_notify (G_OBJECT (label));
- g_object_notify (G_OBJECT (label), "cursor_position");
- g_object_notify (G_OBJECT (label), "selection_bound");
+ g_object_notify (G_OBJECT (label), "cursor-position");
+ g_object_notify (G_OBJECT (label), "selection-bound");
g_object_thaw_notify (G_OBJECT (label));
}
}
* @label: a #GtkLabel
* @setting: %TRUE if the label's text should be parsed for markup.
*
- * Sets whether the text of the label contains markup in Pango's
- * text markup lango. See gtk_label_set_markup().
+ * Sets whether the text of the label contains markup in <link
+ * linkend="PangoMarkupFormat">Pango's text markup
+ * language</link>. See gtk_label_set_markup().
**/
void
gtk_label_set_use_markup (GtkLabel *label,
* gtk_label_get_use_markup:
* @label: a #GtkLabel
*
- * Returns whether the label's text is interpreted as marked up with the
- * Pango text markup language. See gtk_label_set_use_markup ().
+ * Returns whether the label's text is interpreted as marked up with
+ * the <link linkend="PangoMarkupFormat">Pango text markup
+ * language</link>. See gtk_label_set_use_markup ().
*
* Return value: %TRUE if the label's text will be parsed for markup.
**/
return label->use_underline;
}
-static gboolean
-gtk_label_focus (GtkWidget *widget,
- GtkDirectionType direction)
+/**
+ * gtk_label_set_single_line_mode:
+ * @label: a #GtkLabel
+ * @single_line_mode: %TRUE if the label should be in single line mode
+ *
+ * Sets whether the label is in single line mode.
+ *
+ * Since: 2.6
+ */
+void
+gtk_label_set_single_line_mode (GtkLabel *label,
+ gboolean single_line_mode)
{
- /* We never want to be in the tab chain */
- return FALSE;
+ g_return_if_fail (GTK_IS_LABEL (label));
+
+ single_line_mode = single_line_mode != FALSE;
+
+ if (label->single_line_mode != single_line_mode)
+ {
+ label->single_line_mode = single_line_mode;
+
+ gtk_label_clear_layout (label);
+ gtk_widget_queue_resize (GTK_WIDGET (label));
+
+ g_object_notify (G_OBJECT (label), "single-line-mode");
+ }
+}
+
+/**
+ * gtk_label_get_single_line_mode:
+ * @label: a #GtkLabel
+ *
+ * Returns whether the label is in single line mode.
+ *
+ * Return value: %TRUE when the label is in single line mode.
+ *
+ * Since: 2.6
+ **/
+gboolean
+gtk_label_get_single_line_mode (GtkLabel *label)
+{
+ g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
+
+ return label->single_line_mode;
}
/* Compute the X position for an offset that corresponds to the "more important
gint *x,
gint *y)
{
- GtkTextDirection keymap_direction =
- (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
- GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
- GtkTextDirection widget_direction = gtk_widget_get_direction (GTK_WIDGET (label));
+ GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
+ PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
+ PangoDirection cursor_direction = get_cursor_direction (label);
gboolean split_cursor;
PangoRectangle strong_pos, weak_pos;
}
else
{
- if (keymap_direction == widget_direction)
+ if (keymap_direction == cursor_direction)
{
*x = strong_pos.x / PANGO_SCALE;
*y = strong_pos.y / PANGO_SCALE;
gint start,
gint count)
{
- gint offset = g_utf8_pointer_to_offset (label->label,
- label->label + start);
+ gint offset = g_utf8_pointer_to_offset (label->text,
+ label->text + start);
- if (label->label)
+ if (label->text)
{
PangoLogAttr *log_attrs;
gint n_attrs;
gtk_label_ensure_layout (label);
- length = g_utf8_strlen (label->label, -1);
+ length = g_utf8_strlen (label->text, -1);
pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
g_free (log_attrs);
}
- return g_utf8_offset_to_pointer (label->label, offset) - label->label;
+ return g_utf8_offset_to_pointer (label->text, offset) - label->text;
}
static gint
strong = TRUE;
else
{
- GtkTextDirection keymap_direction =
- (gdk_keymap_get_direction (gdk_keymap_get_default ()) == PANGO_DIRECTION_LTR) ?
- GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
+ GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (label)));
+ PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
- strong = keymap_direction == gtk_widget_get_direction (GTK_WIDGET (label));
+ strong = keymap_direction == get_cursor_direction (label);
}
if (count > 0)
index = new_index;
while (new_trailing--)
- index = g_utf8_next_char (label->label + new_index) - label->label;
+ index = g_utf8_next_char (label->text + new_index) - label->text;
}
return index;
gtk_label_move_forward_word (GtkLabel *label,
gint start)
{
- gint new_pos = g_utf8_pointer_to_offset (label->label,
- label->label + start);
+ gint new_pos = g_utf8_pointer_to_offset (label->text,
+ label->text + start);
gint length;
- length = g_utf8_strlen (label->label, -1);
+ length = g_utf8_strlen (label->text, -1);
if (new_pos < length)
{
PangoLogAttr *log_attrs;
g_free (log_attrs);
}
- return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
+ return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
}
gtk_label_move_backward_word (GtkLabel *label,
gint start)
{
- gint new_pos = g_utf8_pointer_to_offset (label->label,
- label->label + start);
- gint length;
+ gint new_pos = g_utf8_pointer_to_offset (label->text,
+ label->text + start);
- length = g_utf8_strlen (label->label, -1);
-
if (new_pos > 0)
{
PangoLogAttr *log_attrs;
g_free (log_attrs);
}
- return g_utf8_offset_to_pointer (label->label, new_pos) - label->label;
+ return g_utf8_offset_to_pointer (label->text, new_pos) - label->text;
}
static void
gint count,
gboolean extend_selection)
{
+ gint old_pos;
gint new_pos;
if (label->select_info == NULL)
return;
-
- new_pos = label->select_info->selection_end;
+
+ old_pos = new_pos = label->select_info->selection_end;
if (label->select_info->selection_end != label->select_info->selection_anchor &&
!extend_selection)
new_pos = end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
else
new_pos = !end_is_left ? label->select_info->selection_end : label->select_info->selection_anchor;
-
break;
}
case GTK_MOVEMENT_LOGICAL_POSITIONS:
case GTK_MOVEMENT_PARAGRAPH_ENDS:
case GTK_MOVEMENT_BUFFER_ENDS:
/* FIXME: Can do better here */
- new_pos = count < 0 ? 0 : strlen (label->label);
+ new_pos = count < 0 ? 0 : strlen (label->text);
break;
case GTK_MOVEMENT_DISPLAY_LINES:
case GTK_MOVEMENT_PARAGRAPHS:
case GTK_MOVEMENT_PAGES:
+ case GTK_MOVEMENT_HORIZONTAL_PAGES:
break;
}
}
break;
case GTK_MOVEMENT_VISUAL_POSITIONS:
new_pos = gtk_label_move_visually (label, new_pos, count);
+ if (new_pos == old_pos)
+ {
+ if (!extend_selection)
+ {
+ if (!gtk_widget_keynav_failed (GTK_WIDGET (label),
+ count > 0 ?
+ GTK_DIR_RIGHT : GTK_DIR_LEFT))
+ {
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (label));
+
+ if (toplevel)
+ gtk_widget_child_focus (toplevel,
+ count > 0 ?
+ GTK_DIR_RIGHT : GTK_DIR_LEFT);
+ }
+ }
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (label));
+ }
+ }
break;
case GTK_MOVEMENT_WORDS:
while (count > 0)
new_pos = gtk_label_move_backward_word (label, new_pos);
count++;
}
+ if (new_pos == old_pos)
+ gtk_widget_error_bell (GTK_WIDGET (label));
break;
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
case GTK_MOVEMENT_PARAGRAPH_ENDS:
case GTK_MOVEMENT_BUFFER_ENDS:
/* FIXME: Can do better here */
- new_pos = count < 0 ? 0 : strlen (label->label);
+ new_pos = count < 0 ? 0 : strlen (label->text);
+ if (new_pos == old_pos)
+ gtk_widget_error_bell (GTK_WIDGET (label));
break;
case GTK_MOVEMENT_DISPLAY_LINES:
case GTK_MOVEMENT_PARAGRAPHS:
case GTK_MOVEMENT_PAGES:
+ case GTK_MOVEMENT_HORIZONTAL_PAGES:
break;
}
}
start = len;
if (start != end)
- gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
+ gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (label),
+ GDK_SELECTION_CLIPBOARD),
label->text + start, end - start);
}
}
static void
gtk_label_select_all (GtkLabel *label)
{
- gtk_label_select_region_index (label, 0, strlen (label->label));
+ gtk_label_select_region_index (label, 0, strlen (label->text));
}
/* Quick hack of a popup menu
activate_cb (GtkWidget *menuitem,
GtkLabel *label)
{
- const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
- gtk_signal_emit_by_name (GTK_OBJECT (label), signal);
+ const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
+ g_signal_emit_by_name (label, signal);
}
static void
{
GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
- gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
- gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
- GTK_SIGNAL_FUNC (activate_cb), label);
+ g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
+ g_signal_connect (menuitem, "activate",
+ G_CALLBACK (activate_cb), label);
gtk_widget_set_sensitive (menuitem, sensitive);
GtkLabel *label;
GtkWidget *widget;
GtkRequisition req;
+ GdkScreen *screen;
label = GTK_LABEL (user_data);
widget = GTK_WIDGET (label);
return;
g_return_if_fail (GTK_WIDGET_REALIZED (label));
-
+
+ screen = gtk_widget_get_screen (widget);
gdk_window_get_origin (widget->window, x, y);
gtk_widget_size_request (label->select_info->popup_menu, &req);
*x += widget->allocation.width / 2;
*y += widget->allocation.height;
- *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
- *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
+ *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
+ *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
}
append_action_signal (label, label->select_info->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
FALSE);
- menuitem = gtk_menu_item_new_with_label (_("Select All"));
- gtk_signal_connect_object (GTK_OBJECT (menuitem), "activate",
- GTK_SIGNAL_FUNC (gtk_label_select_all), label);
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
+ gtk_widget_set_sensitive (menuitem, FALSE);
gtk_widget_show (menuitem);
gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
gtk_widget_show (menuitem);
gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
- menuitem = gtk_menu_item_new_with_label (_("Input Methods"));
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
+ g_signal_connect_swapped (menuitem, "activate",
+ G_CALLBACK (gtk_label_select_all), label);
gtk_widget_show (menuitem);
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), gtk_menu_new ());
- gtk_widget_set_sensitive (menuitem, FALSE);
gtk_menu_shell_append (GTK_MENU_SHELL (label->select_info->popup_menu), menuitem);
- gtk_signal_emit (GTK_OBJECT (label),
- signals[POPULATE_POPUP],
- label->select_info->popup_menu);
+ g_signal_emit (label,
+ signals[POPULATE_POPUP],
+ 0,
+ label->select_info->popup_menu);
if (event)
gtk_menu_popup (GTK_MENU (label->select_info->popup_menu), NULL, NULL,
popup_position_func, label,
0, gtk_get_current_event_time ());
}
+
+#define __GTK_LABEL_C__
+#include "gtkaliasdef.c"