154. How to highlight matching brackets in GtkTextView - Part 3?

Problem

In Part 1 and Part 2, you have highlighted enclosing curly brackets in a GtkTextView.

We will make one more improvement in this article. When the user moves the cursor with the mouse or arrow keys, the highlight will automatically disappear as shown below:

How to highlight matching brackets in GtkTextView - Part 3?


Solution


Sample Code

1   
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
16   
18   
20   
21   
22   
23   
24   
25   
26   
27   
28   
29   
30   
31   
32   
33   
34   
41   
42   
43   
44   
45   
46   
47   
48   
49   
50   
51   
52   
53   
54   
55   
56   
57   
58   
60   
61   
62   
63   
64   
65   
66   
68   
69   
70   
71   
72   
73   
76   
78   
79   
80   
81   
82   
83   
84   
89   
90   
91   
92   
93   
94   
95   
96   
97   
98   
99   
100   
101   
102   
103   
104   
107   
109   
110   
111   
112   
113   
114   
115   
120   
121   
122   
123   
124   
125   
126   
127   
129   
131   
132   
133   
134   
135   
136   
137   
138   
139   
140   
141   
142   
143   
144   
145   
146   
148   
149   
150   
151   
152   
153   
154   
155   
156   
157   
159   
160   
161   
162   
163   
164   
165   
166   
167   
168   
169   
170   
171   
172   
<?php
$window = new GtkWindow();
$window->set_size_request(400, 240);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->add($vbox = new GtkVBox());

// display title
$title = new GtkLabel("Find matching curly bracket - Part 3\n".
"The highlight will disappear\n".
"when you move the cursor with mouse or keypress");
$title->modify_font(new PangoFontDescription("Times New Roman Italic 10"));
$title->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#0000ff"));
$title->set_size_request(-1, 60);
$title->set_justify(Gtk::JUSTIFY_CENTER);
$alignment = new GtkAlignment(0.5, 0.5, 0, 0);
$alignment->add($title);
$vbox->pack_start($alignment);

$left_start_iter = $left_end_iter = null;
$right_start_iter = $right_end_iter = null;

// Create a new buffer and a new view to show the buffer.
$buffer = new GtkTextBuffer();
$buffer->set_text('if ($i==1) {
    test();
} else {
    test2();
}');
$view = new GtkTextView();
$view->set_buffer($buffer);
$view->modify_font(new PangoFontDescription("Arial 10"));
$view->set_wrap_mode(Gtk::WRAP_WORD);
$view->connect('button-press-event', 'on_button_press_in_textview'); // note 1
$view->connect('key-press-event', 'on_key_press_in_textview'); // note 2

$hbox = new GtkHBox();
$hbox->pack_start($button = new GtkButton('Find enclosing bracket'), 0);
$vbox->pack_start($hbox, 0);
$button->connect('clicked', 'on_button', $buffer);

$scrolled_win = new GtkScrolledWindow();
$scrolled_win->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
$vbox->pack_start($scrolled_win);
$scrolled_win->add($view);

$tag_table = $buffer->get_tag_table();
$tag['highlight'] = new GtkTextTag();
$tag['highlight']->set_property('background', "#ffff00");
$tag_table->add($tag['highlight']);

$window->show_all();
Gtk::main();

function find_left_bracket($iter, $buffer) {
    global $tag;
    $iter2 = $iter->copy();

    $match_start = $iter->copy();
    $match_end = $iter->copy();

    // check left { first
    $found = $iter->backward_search('{', 0, $match_start,
        $match_end, null);
    if (!$found) return null;

    // check if there's a } on the left
    $match_start2 = $iter->copy();
    $match_end2 = $iter->copy();

    $found2 = $iter2->backward_search('}', 0, $match_start2,
        $match_end2, null);

    if ($found2 && $match_start->compare($match_start2)!=1) return null;

    $buffer->apply_tag($tag['highlight'], $match_start, $match_end);
    return array($match_start, $match_end);
}

function find_right_bracket($iter, $buffer) {
    global $tag;
    $iter2 = $iter->copy();
    $match_start = $iter->copy();
    $match_end = $iter->copy();

    // check right } first
    $found = $iter->forward_search('}', 0, $match_start,
        $match_end, null);
    if (!$found) return null;

    // check if there's a { on the left
    $match_start2 = $iter->copy();
    $match_end2 = $iter->copy();

    $found2 = $iter2->forward_search('{', 0, $match_start2,
        $match_end2, null);

    if ($found2 && $match_start->compare($match_start2)!=-1) return null;

    $buffer->apply_tag($tag['highlight'], $match_start, $match_end);
    return array($match_start, $match_end);
}

function on_button($button, $buffer) {
    global $view, $tag;

    $cursor_pos = $buffer->get_mark('insert');
    $iter = $buffer->get_iter_at_mark($cursor_pos);
    $last_pos = $buffer->create_mark('last_pos', $iter, false);

    global $left_start_iter, $left_end_iter;
    global $right_start_iter, $right_end_iter;

    list($left_start_iter, $left_end_iter) =
        find_left_bracket($iter, $buffer);
    if ($left_start_iter==null) return;

    list($right_start_iter, $right_end_iter) =
        find_right_bracket($iter, $buffer);
    if ($right_start_iter==null) return;


    $view->scroll_mark_onscreen($last_pos);
    $view->grab_focus();
}

function on_button_press_in_textview($widget, $event) {
    remove_highlight();
}

function on_key_press_in_textview($widget, $event) {
    remove_highlight();
}

function remove_highlight() {
    global $buffer, $tag;
    global $left_start_iter, $left_end_iter;
    global $right_start_iter, $right_end_iter;
    if ($left_start_iter==null || $left_end_iter==null) return; // note 3
    if ($right_start_iter==null || $right_end_iter==null) return; // note 3
    $buffer->remove_tag($tag['highlight'], $left_start_iter, $left_end_iter); // note 4
    $buffer->remove_tag($tag['highlight'], $right_start_iter, $right_end_iter); // note 4
}

?>

Output

As shown above.
 

Add comment


Security code
Refresh