New input box code

View: New views
1 Messages — Rating Filter:   Alert me  

New input box code

by Mart Raudsepp :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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/

[automatic_multiline_input.patch]

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>


_______________________________________________
gnome-mud-list mailing list
gnome-mud-list@...
http://mail.gnome.org/mailman/listinfo/gnome-mud-list