[gnome-mud] New input box code



Hello,

The attached patch re-implements input box as always a GtkTextView that
is adjusting its height as necessary. Return/Enter sends text,
Return/Enter with any modifier keys goes to next line in the input box,
adjusting height as necessary.
A largest height of 5 is used, after which a scrollbar is used - that
value can easily be changed by adjusting the value passed to
mud_window_textview_ensure_height().
The height is always kept only as high as necessary.

The code used to check line_yrange in ensure_height too, in addition to
on creation, but I opted for saving the line height and re-use it,
because there seem to be bugs in GtkTextView that cause get_line_yrange
to report a bogus value (usually an old visible_line_count * real height
of a line) on line reduction to 1; e.g if you have two visible lines,
and hitting backspace deletes the linebreak, get_yrange will report 34,
not 17 as it should on my system. I think the same can be seen with
after sending the thing off the mud (and keep_text is off?).

This means that if the input boxes font height changes after initial
creation, it will get bad heights from that on. Need to either
workaround the get_yrange problem somehow, or respond to height changing
signals and cache it again, or do something more clean.
In wxMUD I always query the font height, for example. But that's mainly
just because I don't have clean access to gtk_text_view_get_line_yrange
at all there.

The horizontal scrollbar policy is made AUTOMATIC instead of NONE
because of gnome bugzilla bug #308126 - it will appear only if we hit
that bug. This ensures that the input box won't make the toplevel grow
it's width without a limit, which would be just plain wrong to do.

The discoverability of modifier+enter is a little problem, imho, too.
But all the cool kids are doing it (gaim, gossip?)

You might want to set the wrap mode in glade file instead of code. I did
it in code because:
a) I don't trust my glade GUI to not screw up the glade file to no
recognition (the removal of text_entry and co was done by hand in text
editor)
b) I'm not sure if it should be in the glade file, instead of code - it
is a programmatical thing to ensure such word-wrap, not an UI choice.

The size_request is set on the vscrollbar of text_view_scroll because
otherwise it's higher than a line height, and we don't like that.

Worth noting is, that with it always being a GtkTextView, implementing
password hiding will be quite a feat, if possible at all without loosing
sanity.

Hopefully the patch is useful and commitable as is, or after slight
changes/improvements.
I need to work on other things for a couple of days myself, so posting
the current (not-too-bad) state of the patch here for consideration.


-- 
With regards,
Mart Raudsepp

Project manager of wxMUD      - http://wxmud.sourceforge.net/
Developer of wxWidgets        - http://www.wxwidgets.org/
GTK+ port maintainer of OMGUI - http://www.omgui.org/
Index: src/mud-window.c
===================================================================
RCS file: /cvs/gnome/gnome-mud/src/mud-window.c,v
retrieving revision 1.19
diff -u -B -r1.19 mud-window.c
--- src/mud-window.c	25 Apr 2006 09:12:44 -0000	1.19
+++ src/mud-window.c	25 Apr 2006 19:59:27 -0000
@@ -42,7 +42,6 @@
 	
 	GtkWidget *window;
 	GtkWidget *notebook;
-	GtkWidget *textentry;
 	GtkWidget *textview;
 	GtkWidget *textviewscroll;
 	GtkWidget *mainvpane;
@@ -64,7 +63,7 @@
 	gchar *port;
 
 	gint nr_of_tabs;
-	gint toggleState;
+	gint textview_line_height;
 	
 	MudTray *tray;
 };
@@ -190,34 +189,72 @@
 
 }
 
-static gboolean
-mud_window_textentry_keypress(GtkWidget *widget, GdkEventKey *event, MudWindow *window)
+static gint
+mud_window_textview_get_display_line_count(GtkTextView *textview)
 {
+	gint result = 1;
+	GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
+	GtkTextIter iter;
 
-	return FALSE;
+	gtk_text_buffer_get_start_iter(buffer, &iter);
+	while (gtk_text_view_forward_display_line(textview, &iter))
+		++result;
+
+	if (gtk_text_buffer_get_line_count(buffer) != 1)
+	{
+		GtkTextIter iter2;
+		gtk_text_buffer_get_end_iter(buffer, &iter2);
+		if (gtk_text_iter_get_chars_in_line(&iter) == 0)
+			++result;
+	}
+
+	return result;
+}
+
+static void
+mud_window_textview_ensure_height(MudWindow *window, guint max_lines)
+{
+	gint lines = mud_window_textview_get_display_line_count(GTK_TEXT_VIEW(window->priv->textview));
+	gtk_widget_set_size_request(window->priv->textview, -1,
+								window->priv->textview_line_height * MIN(lines, max_lines));
+	gtk_widget_queue_resize(gtk_widget_get_parent(window->priv->textview));
+}
+
+static void
+mud_window_textview_buffer_changed(GtkTextBuffer *buffer, MudWindow *window)
+{
+	mud_window_textview_ensure_height(window, 5);
 }
 
 static gboolean
 mud_window_textview_keypress(GtkWidget *widget, GdkEventKey *event, MudWindow *window)
 {
 	gchar *text;
-        GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(window->priv->textview));
+	GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(window->priv->textview));
 	GtkTextIter start, end;
 	
-	if(event->keyval == GDK_KP_Enter)
+	if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) &&
+			(event->state & gtk_accelerator_get_default_mod_mask()) == 0)
 	{
-		if(window->priv->current_view)
-		{
-			gtk_text_buffer_get_bounds(buffer, &start, &end);
-	
-			text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+		gtk_text_buffer_get_bounds(buffer, &start, &end);
+
+		text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+
+		if (g_str_equal(text, ""))
+			text = g_strdup(" ");
+
+		if (window->priv->current_view)
 			mud_connection_view_send(MUD_CONNECTION_VIEW(window->priv->current_view), text);
-			
+
+		if (gconf_client_get_bool(window->priv->gconf_client,
+			"/apps/gnome-mud/functionality/keeptext", NULL) == FALSE)
+			gtk_text_buffer_delete(buffer, &start, &end);
+		else
 			gtk_text_buffer_select_range(buffer, &start, &end);
 
-			return TRUE;
-			
-		}
+		free(text);
+
+		return TRUE;
 	}
 
 	return FALSE;
@@ -257,22 +294,6 @@
 }
 
 static void
-mud_window_textentry_activate(GtkWidget *widget, MudWindow *window)
-{
-	gchar *tmp;
-
-	tmp = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
-		if (g_str_equal(tmp, ""))
-			tmp = g_strdup(" ");
-	if (window->priv->current_view)
-		mud_connection_view_send(MUD_CONNECTION_VIEW(window->priv->current_view), tmp);
-		if (gconf_client_get_bool(window->priv->gconf_client,
-		   "/apps/gnome-mud/functionality/keeptext", NULL) == FALSE)
-			gtk_entry_set_text(GTK_ENTRY(widget), g_strdup(""));
-		free (tmp);
-}
-
-static void
 mud_window_preferences_cb(GtkWidget *widget, MudWindow *window)
 {
 	mud_preferences_window_new("Default");
@@ -316,25 +337,6 @@
 	mud_window_mconnect_new(window, mywig, window->priv->tray);
 }
 
-static void
-mud_window_inputtoggle_cb(GtkWidget *widget, MudWindow *window)
-{
-	
-	if(window->priv->toggleState)
-	{
-		gtk_widget_hide(window->priv->textview);
-		gtk_widget_hide(window->priv->textviewscroll);
-		gtk_widget_show(window->priv->textentry);
-	}
-	else
-	{
-		gtk_widget_hide(window->priv->textentry);
-		gtk_widget_show(window->priv->textview);
-		gtk_widget_show(window->priv->textviewscroll);	
-	}
-	window->priv->toggleState = !window->priv->toggleState;
-}
-
 gboolean
 mud_window_size_request(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data)
 {	
@@ -650,10 +652,9 @@
 	g_signal_connect(window->priv->bufferdump, "activate", G_CALLBACK(mud_window_buffer_cb), window);
 
 	/* preferences window button */
-
 	window->priv->mi_profiles = glade_xml_get_widget(glade, "mi_profiles_menu");
 	g_signal_connect(glade_xml_get_widget(glade, "menu_preferences"), "activate", G_CALLBACK(mud_window_preferences_cb), window);
-	
+
 	g_signal_connect(glade_xml_get_widget(glade, "menu_about"), "activate", G_CALLBACK(mud_window_about_cb), window);
 	
 	/* other objects */
@@ -663,22 +664,27 @@
 	window->priv->textviewscroll = glade_xml_get_widget(glade, "text_view_scroll");
 	window->priv->textview = glade_xml_get_widget(glade, "text_view");
 
+	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(window->priv->textview), GTK_WRAP_WORD_CHAR);
+
 	g_signal_connect(window->priv->textview, "key_press_event", G_CALLBACK(mud_window_textview_keypress), window);
-	
-	gtk_widget_hide(window->priv->textviewscroll);
-	gtk_widget_hide(window->priv->textview);
-	
-	window->priv->toggleState = 0;
+	g_signal_connect(gtk_text_view_get_buffer(GTK_TEXT_VIEW(window->priv->textview)), "changed",
+					 G_CALLBACK(mud_window_textview_buffer_changed), window);
 
-	window->priv->textentry = glade_xml_get_widget(glade, "text_entry");
-	g_signal_connect(window->priv->textentry, "key_press_event", G_CALLBACK(mud_window_textentry_keypress), window);
-	g_signal_connect(window->priv->textentry, "activate", G_CALLBACK(mud_window_textentry_activate), window);
+	{
+		/* Set the initial height of the input box equal to the height of one line */
+		GtkTextIter iter;
+		gint y;
+		gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(window->priv->textview)), &iter);
+		gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(window->priv->textview), &iter, &y, &window->priv->textview_line_height);
 
-	window->priv->mainvpane = glade_xml_get_widget(glade, "main_vpane");
-	
-	window->priv->image = glade_xml_get_widget(glade, "image");
+		gtk_widget_set_size_request(window->priv->textview, -1, window->priv->textview_line_height*1);
+		gtk_widget_set_size_request(GTK_SCROLLED_WINDOW(window->priv->textviewscroll)->vscrollbar, -1, 1);
 
-	g_signal_connect(glade_xml_get_widget(glade, "toggle_input"), "clicked", G_CALLBACK(mud_window_inputtoggle_cb), window);
+		if (GTK_WIDGET_VISIBLE(window->priv->textviewscroll))
+			gtk_widget_queue_resize(window->priv->textviewscroll);
+	}
+
+	window->priv->image = glade_xml_get_widget(glade, "image");
 
 	g_signal_connect(glade_xml_get_widget(glade, "plugin_list"), "activate", G_CALLBACK(do_plugin_information), NULL);
 	
Index: ui/main.glade
===================================================================
RCS file: /cvs/gnome/gnome-mud/ui/main.glade,v
retrieving revision 1.17
diff -u -B -r1.17 main.glade
--- ui/main.glade	25 Apr 2006 09:12:44 -0000	1.17
+++ ui/main.glade	25 Apr 2006 19:59:27 -0000
@@ -537,30 +537,10 @@
 		  <property name="spacing">0</property>
 
 		  <child>
-		    <widget class="GtkEntry" id="text_entry">
-		      <property name="height_request">25</property>
-		      <property name="visible">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="editable">True</property>
-		      <property name="visibility">True</property>
-		      <property name="max_length">0</property>
-		      <property name="text" translatable="yes"></property>
-		      <property name="has_frame">True</property>
-		      <property name="invisible_char">*</property>
-		      <property name="activates_default">False</property>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">False</property>
-		      <property name="fill">False</property>
-		    </packing>
-		  </child>
-
-		  <child>
 		    <widget class="GtkScrolledWindow" id="text_view_scroll">
 		      <property name="visible">True</property>
 		      <property name="can_focus">True</property>
-		      <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+		      <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
 		      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
 		      <property name="shadow_type">GTK_SHADOW_IN</property>
 		      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
@@ -598,31 +578,6 @@
 		</packing>
 	      </child>
 
-	      <child>
-		<widget class="GtkButton" id="toggle_input">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="relief">GTK_RELIEF_NORMAL</property>
-		  <property name="focus_on_click">True</property>
-
-		  <child>
-		    <widget class="GtkImage" id="image65">
-		      <property name="visible">True</property>
-		      <property name="stock">gtk-justify-fill</property>
-		      <property name="icon_size">1</property>
-		      <property name="xalign">0.5</property>
-		      <property name="yalign">0.5</property>
-		      <property name="xpad">0</property>
-		      <property name="ypad">0</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
 	    </widget>
 	    <packing>
 	      <property name="padding">0</property>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]