turn on italics in TextView

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

turn on italics in TextView

Doug McCasland
Hi,

I am trying GTK3 TextView, in C. I know how to apply tags, such as italics,
bold, etc., to a region of text.

But how do I "turn on" a style (italics, bold, etc) while typing in the
buffer? For example, suppose I am typing text and there are no styles set.
Then I want to type in italics. I want to apply the italic tag to the
insert point, after which whatever I typed would be in italics.

I notice that when you place the insert cursor to the right of any existing
styled text, the tags of the previous character are inherited, but only if
the style is in effect before and after the insert point. Interestingly,
the trailing newline can be stylized (invisibly), so when the insert point
is at the end of a line and the last visible character has a style, then
that style is inherited.

I've looked at some methods that use a key-press signal and then apply a
text tag to the region of the untagged character just typed, but that is
slow and looks odd on screen -- the plain char is displayed and then
replaced by the tagged char.

I've also tried:

gtk_text_buffer_insert_markup(buf, &iter, "<i>", -1);

but that gets a Warning: Invalid markup string: ... Element 'markup' was
closed, but the currently open element is 'i' and has no effect on the
displayed text. Using <i></i> gets no warning but also has no effect. I
finally resorted to:

gtk_text_buffer_insert_markup(buf, &iter, "<i> </i>", -1); // 2 spaces

gtk_text_iter_backward_char (&iter);

gtk_text_buffer_place_cursor(buf, &iter);

which lets me start typing in italics between 2 new (tagged) spaces --
that's not so bad.

But clicking an "I" button to start typing in italics -- that is a basic
editing function that has been around for decades. It must be possible in
GTK somehow?

thanks
_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: turn on italics in TextView

Gtk+ - Apps Dev mailing list

 
Hi Doug,

You can try using the "insert-text" callback to set your italics on the inserted text. This is what I came up with to test. The signal is connected after so that the update occurs first. Careful about not changing the location iter also since there is a warning in the documentation about doing so. Might not need to worry about it here but something to be aware of.

https://developer.gnome.org/gtk3/stable/GtkTextBuffer.html#GtkTextBuffer-insert-text

Eric


/*
  gcc -Wall textview2.c -o textview2 `pkg-config --cflags --libs gtk+-3.0`
  Tested on GTK3.18 and Ubuntu16.04
*/

#include<gtk/gtk.h>

static gboolean italic=FALSE;

static void toggle_italic(GtkToggleButton *toggle1, gpointer data)
  {
    GtkWidget *label=gtk_bin_get_child(GTK_BIN(toggle1));
    if(gtk_toggle_button_get_active(toggle1))
      {
        gtk_label_set_markup(GTK_LABEL(label), "<span style='italic'>Italics</span>");
        italic=TRUE;
      }
    else
      {
        gtk_label_set_text(GTK_LABEL(label), "Italics");
        italic=FALSE;
      }
    gtk_widget_grab_focus(GTK_WIDGET(data));
  }
static void new_text(GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, gpointer user_data)
  {
    if(italic)
      {
        GtkTextIter *start=gtk_text_iter_copy(location);
        GtkTextIter *end=gtk_text_iter_copy(location);
        gtk_text_iter_backward_chars(start, len);
        gtk_text_buffer_apply_tag_by_name(textbuffer, "tag1", start, end);
        gtk_text_iter_free(start);
        gtk_text_iter_free(end);
      }
  }
int main (int argc, char *argv[])
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Textview");
    gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *text_view1=gtk_text_view_new();
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view1), GTK_WRAP_CHAR);
    gtk_widget_set_vexpand(text_view1, TRUE);
    gtk_widget_set_hexpand(text_view1, TRUE);

    GtkTextBuffer *buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view1));
    gtk_text_buffer_create_tag(buffer, "tag1", "style", PANGO_STYLE_ITALIC, NULL);
    g_signal_connect_after(buffer, "insert-text", G_CALLBACK(new_text), NULL);

    GtkWidget *toggle1=gtk_toggle_button_new_with_label("Italics");
    g_signal_connect(toggle1, "toggled", G_CALLBACK(toggle_italic), text_view1);

    GtkWidget *grid=gtk_grid_new();
    gtk_container_set_border_width(GTK_CONTAINER(grid), 8);
    gtk_grid_set_row_spacing(GTK_GRID(grid), 12);
    gtk_grid_attach(GTK_GRID(grid), text_view1, 0, 0, 1, 1);
    gtk_grid_attach(GTK_GRID(grid), toggle1, 0, 1, 1, 1);
   
    gtk_container_add(GTK_CONTAINER(window), grid);

    gtk_widget_show_all(window);

    gtk_main();

    return 0;
  }


 


_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: turn on italics in TextView

Gtk+ - Apps Dev mailing list

 
Here are a few things that might improve the above code a little. Use

gtk_button_set_focus_on_click(GTK_BUTTON(toggle1), FALSE);

instead of a grab. Also the global gboolean can be eliminated if you pass the toggle button pointer to the "insert-text" callback. Then you can just use

if(gtk_toggle_button_get_active(user_data))
 
For the sequence of events it is my understanding that the text changes will be made during the event cycle before the window gets re-painted.

https://developer.gnome.org/gtk3/stable/chap-drawing-model.html

Eric
 

 

 

-----Original Message-----
From: Doug McCasland <[hidden email]>
To: cecashon <[hidden email]>
Sent: Tue, Jun 13, 2017 4:09 pm
Subject: Re: turn on italics in TextView


cecashon, thanks so much for your great reply!


I had tried all those calls, but I hadn't put them together as you did, nor did I apply the tag in the way your code does.  And I didn't think of having one signal/function for the button-down and another for the apply_tag_by_name.  Cool!  


So your code gets a signal after the character(s) is entered. Then the style is applied to that char, without moving the insert point.  Do you know if the un-tagged char is visibly displayed first, and then altered?  Or is all the processing somehow finished before the display changes, and then only the tagged char is put on the screen.






_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: turn on italics in TextView

Doug McCasland
​Thanks again.  That works, but ​the state is lost when the cursor is
moved.  Here is some code to discover multiple styles after the cursor is
moved.  The pointers to the style tags are saved in globals, then in the
callback for the cursor move, we look for those pointers in the linked-list
returned by gtk_text_iter_get_tag().  I tried to use some of the other
link-list functions/macros, such as g_slist_position, but could only
get gtk_text_iter_get_tag() to work.  Maybe there's a more efficient way to
do this.

// globals
GSList *gtk_text_iter_get_tags (const GtkTextIter *iter);
GtkTextTag *italp, *boldp, *ulinep;

// call back after cursor is moved
  void
get_style(GtkTextView *tv, GtkMovementStep step,
        gint count, gboolean extend, gpointer *user_data)  {
GSList *tlist;
GtkTextIter start;
GtkTextMark *mark;
GtkTextBuffer *buf;

buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv));

mark = gtk_text_buffer_get_insert(buf);
gtk_text_buffer_get_iter_at_mark (buf, &start, mark);

tlist = gtk_text_iter_get_tags(&start);

// look for each style -- could used to set bits in a bitfield
if (g_slist_find(tlist, italp))
    g_printerr("got match for ital\n");
if (g_slist_find(tlist, boldp))
    g_printerr("got match for bold\n");
if (g_slist_find(tlist, ulinep))
    g_printerr("got match for uline\n");

}

. . .
main(...)
 . . .
italp = gtk_text_buffer_create_tag(buffer, "ital", "style",
PANGO_STYLE_ITALIC, NULL);
boldp =gtk_text_buffer_create_tag(buffer, "bold", "weight",
PANGO_WEIGHT_BOLD, NULL);
ulinep = gtk_text_buffer_create_tag(buffer, "uline", "underline",
PANGO_UNDERLINE_SINGLE, NULL);

g_signal_connect_after(text_view, "move-cursor", G_CALLBACK(get_style),
NULL);
. . .



On Wed, Jun 14, 2017 at 10:48 AM, <[hidden email]> wrote:

>
> Here are a few things that might improve the above code a little. Use
>
> gtk_button_set_focus_on_click(GTK_BUTTON(toggle1), FALSE);
>
> instead of a grab. Also the global gboolean can be eliminated if you pass
> the toggle button pointer to the "insert-text" callback. Then you can just
> use
>
> if(gtk_toggle_button_get_active(user_data))
>
> For the sequence of events it is my understanding that the text changes
> will be made during the event cycle before the window gets re-painted.
>
> https://developer.gnome.org/gtk3/stable/chap-drawing-model.html
>
> Eric
>
>
>
> -----Original Message-----
> From: Doug McCasland <[hidden email]>
> To: cecashon <[hidden email]>
> Sent: Tue, Jun 13, 2017 4:09 pm
> Subject: Re: turn on italics in TextView
>
> cecashon, thanks so much for your great reply!
>
> I had tried all those calls, but I hadn't put them together as you did,
> nor did I apply the tag in the way your code does.  And I didn't think of
> having one signal/function for the button-down and another for the
> apply_tag_by_name.  Cool!
>
> So your code gets a signal after the character(s) is entered. Then the
> style is applied to that char, without moving the insert point.  Do you
> know if the un-tagged char is visibly displayed first, and then altered?
> Or is all the processing somehow finished before the display changes, and
> then only the tagged char is put on the screen.
>
>
>
>


--
Doug McCasland   <[hidden email]>
_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: turn on italics in TextView

Gtk+ - Apps Dev mailing list

 
Another option is to look at the properties of the tags to get the information that you need. This might work better than saving globals and matching pointers.

Eric

...
    GSList *tlist=NULL;
    GSList *next=NULL;
    tlist=gtk_text_iter_get_tags(&start);
    if(tlist!=NULL)
      {
        do
          {
            next=tlist->next;
            gchar *string=NULL;
            g_object_get(G_OBJECT(tlist->data), "name", &string, NULL);
            g_print("%s\n", string);
            g_free(string);
            tlist=g_slist_next(tlist);
          }while(next!=NULL);
       }
    else g_print("No Tags\n");

    if(tlist!=NULL) g_slist_free(tlist);
...

 



_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: turn on italics in TextView

Gtk+ - Apps Dev mailing list

 
On that last post, I think that I have some bad pointer arithmetic. Moving a pointer past the end and freeing a moved pointer. Not so good.

Eric

...
    GSList *tlist=NULL;
    GSList *p=NULL;
    GSList *next=NULL;
    tlist=gtk_text_iter_get_tags(&start);
    p=tlist;
    if(tlist!=NULL)
      {
        do
          {
            next=p->next;
            gchar *string=NULL;
            g_object_get(G_OBJECT(p->data), "name", &string, NULL);
            g_print("%s\n", string);
            g_free(string);
            if(next!=NULL)p=g_slist_next(p);
          }while(next!=NULL);
       }
    else g_print("No Tag\n");

    if(tlist!=NULL) g_slist_free(tlist);
...

 

 

-----Original Message-----
From: Eric Cashon via gtk-app-devel-list <[hidden email]>
To: dougm <[hidden email]>
Cc: gtk-app-devel-list <[hidden email]>
Sent: Tue, Jun 20, 2017 4:48 pm
Subject: Re: turn on italics in TextView


 
Another option is to look at the properties of the tags to get the information that you need. This might work better than saving globals and matching pointers.

Eric

...
    GSList *tlist=NULL;
    GSList *next=NULL;
    tlist=gtk_text_iter_get_tags(&start);
    if(tlist!=NULL)
    {
        do
          {
            next=tlist->next;
            gchar *string=NULL;
            g_object_get(G_OBJECT(tlist->data), "name", &string, NULL);
            g_print("%s\n", string);
            g_free(string);
      tlist=g_slist_next(tlist);
          }while(next!=NULL);
       }
    else g_print("No Tags\n");

    if(tlist!=NULL) g_slist_free(tlist);
...

 



_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

_______________________________________________
gtk-app-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Loading...