root/branch/max/pysourceview/pysourceview.py @ 928

Revision 928, 25.8 kB (checked in by maxim-gavrilov, 6 years ago)

small fixes

Line 
1import pygtk
2pygtk.require('2.0')
3
4import gettext
5gettext.install('pysourceview')
6
7import gtk
8from gtk import TextView
9from gtk import gdk
10import pango
11import gobject
12import pango
13
14# defines
15GUTTER_PIXMAP = 16
16
17TARGET_COLOR = 200 # DnD color
18
19MIN_NUMBER_WINDOW_WIDTH = 20
20
21DEFAULT_TAB_WIDTH = 8
22MAX_TAB_WIDTH = 32
23
24DEFAULT_MARGIN = 80
25MAX_MARGIN = 200
26
27# main view class
28class SourceView(TextView):
29    __gproperties__ = {
30        "show_line_numbers" : (gobject.TYPE_BOOLEAN,
31                               _("Show Line Numbers"),
32                               _("Whether to display line numbers"),
33                               False,
34                               gobject.PARAM_READWRITE),
35       
36        "show_line_markers" : (gobject.TYPE_BOOLEAN,
37                               _("Show Line Markers"),
38                               _("Whether to display line marker pixbufs"),
39                               False,
40                               gobject.PARAM_READWRITE),
41
42        "tabs_width" : (gobject.TYPE_UINT,
43                        _("Tabs Width"),
44                        _("Tabs Width"),
45                        1,
46                        MAX_TAB_WIDTH,
47                        DEFAULT_TAB_WIDTH,
48                        gobject.PARAM_READWRITE),
49       
50        "auto_indent" : (gobject.TYPE_BOOLEAN,
51                         _("Auto Indentation"),
52                         _("Whether to enable auto indentation"),
53                         False,
54                         gobject.PARAM_READWRITE),
55
56        "insert_spaces_instead_of_tabs": (gobject.TYPE_BOOLEAN,
57                                          _("Insert Spaces Instead of Tabs"),
58                                          _("Whether to insert spaces instead of tabs"),
59                                          False,
60                                          gobject.PARAM_READWRITE),
61
62        "show_margin" : (gobject.TYPE_BOOLEAN,
63                         _("Show Right Margin"),
64                         _("Whether to display the right margin"),
65                         False,
66                         gobject.PARAM_READWRITE),
67
68        "margin" : (gobject.TYPE_UINT,
69                    _("Margin position"),
70                    _("Position of the right margin"),
71                    1,
72                    MAX_MARGIN,
73                    DEFAULT_MARGIN,
74                    gobject.PARAM_READWRITE),
75
76        "smart_home_end" : (gobject.TYPE_BOOLEAN,
77                            _("Smart Home/End"),
78                            _("HOME and END keys move to first/last "
79                              "non whitespace chapters on line before going "
80                              "to the start/end of the line"),
81                            False,
82                            gobject.PARAM_READWRITE),
83
84        "highlight_current_line" : (gobject.TYPE_BOOLEAN,
85                                    _("Highlight current line"),
86                                    _("Whether to highlight the current line"),
87                                    False,
88                                    gobject.PARAM_READWRITE),
89
90        "indent_on_tab" : (gobject.TYPE_BOOLEAN,
91                           _("Indent on tab"),
92                           _("Whether to indent the selected text when the tab key is pressed"),
93                           True,
94                           gobject.PARAM_READWRITE)
95    }
96
97   
98    def __init__(self, buffer=None):
99        TextView.__init__(self, buffer)
100       
101        self.tabs_width = DEFAULT_TAB_WIDTH
102        self.margin = DEFAULT_MARGIN;
103        self.cached_margin_width = -1
104        self.indent_on_tab = True
105        self.smart_home_end = False
106        self.set_left_margin(2)
107        self.set_right_margin(2)
108
109        # create members
110        self.show_line_numbers = False
111        self.show_line_markers = False
112        self.auto_indent = False
113        self.insert_spaces = False
114        self.show_margin = False
115        self.highlight_current_line = False
116        self.source_buffer = None
117        self.source_buffer_handler_id = []
118        self.old_lines = 0 # number of lines
119        self.current_line_gc = None
120
121        self._set_source_buffer(self.get_buffer())
122
123        # TODO: not yet implemented
124        #self.pixmap_cache = dict()
125        #self.style_scheme_applied = False
126        #self.style_scheme = None
127
128        # DnD init
129        #tl = self.drag_dest_get_target_list()
130        #if tl:
131        #    tl.append(("application/x-color", 0, TARGET_COLOR))
132        #    self.connect("drag_data_received", self.view_dnd_drop)
133        #    self.connect("notify::buffer", self.notify_buffer0
134       
135    def set_show_line_numbers(self, show):
136        if show and not self.show_line_numbers:
137            if not self.show_line_markers:
138                self.set_border_window_size(gtk.TEXT_WINDOW_LEFT, MIN_NUMBER_WINDOW_WIDTH)
139            else:
140                self.queue_draw()
141            self.show_line_numbers = show
142            self.notify("show_line_numbers")
143        if not show and self.show_line_numbers:
144            self.queue_draw()
145            self.show_line_numbers = show
146            self.notify("show_line_numbers")
147
148    def get_show_line_numbers(self):
149        return self.show_line_numbers
150
151    def set_show_line_markers(self, show):
152        if show and not self.show_line_markers:
153            if not self.show_line_numbers:
154                self.set_border_window_size(gtk.TEXT_WINDOW_LEFT, MIN_NUMBER_WINDOW_WIDTH)
155            else:
156                self.queue_draw()
157            self.show_line_markers = show
158            self.notify("show_line_markers")
159        if not show and self.show_line_markers:
160            self.queue_draw()
161            self.show_line_markers = show
162            self.notify("show_line_markers")
163
164    def get_show_line_markers(self):
165        return self.show_line_markers
166
167    def set_tabs_width(self, width):
168        if width <= 0 or width > MAX_TAB_WIDTH or self.tabs_width == width:
169            return
170        save_width = self.tabs_width
171        self.tabs_width = width
172        if self._set_tab_stops_internal():
173            self.notify("tabs_width")
174        else:
175            self.tabs_width = save_width
176
177    def get_tabs_width(self):
178        return self.tabs_width
179
180    def set_auto_indent(self, enable):
181        if self.auto_indent != enable:
182            self.auto_indent = enable
183            self.notify("auto_indent")
184           
185    def get_auto_indent(self):
186        return self.auto_indent
187
188    def set_insert_spaces_instead_of_tabs(self, enable):
189        if self.insert_spaces != enable:
190            self.insert_spaces = enable
191            self.notify("insert_spaces_instead_of_tabs")
192
193    def get_insert_spaces_instead_of_tabs(self):
194        return self.insert_spaces
195
196    def set_show_margin(self, show):
197        if self.show_margin != show:
198            self.show_margin = show
199            self.queue_draw()
200            self.notify("show_margin")
201
202    def get_show_margin(self):
203        return self.show_margin
204
205    def set_margin(self, margin):
206        if margin < 1 or margin > MAX_MARGIN or self.margin == margin:
207            return
208        self.margin = margin
209        self.cached_margin_width = -1
210        self.queue_draw()
211        self.notify("margin")
212
213    def get_margin(self):
214        return self.margin
215
216    def set_smart_home_end(self, enable):
217        if not self.smart_home_end == enable:
218            self.smart_home_end = enable
219            self.notify("smart_home_end")
220
221    def get_smart_home_end(self):
222        return self.smart_home_end
223
224    def set_highlight_current_line(self, enable):
225        if not self.highlight_current_line == enable:
226            self.highlight_current_line = enable
227            self.queue_draw()
228            self.notify("highlight_current_line")
229   
230    def get_highlight_current_line(self):
231        return self.highlight_current_line
232
233    property_map = {
234        'show-line-numbers': (set_show_line_numbers, get_show_line_numbers),
235        'show-line-marker': (set_show_line_markers, get_show_line_markers),
236        'tabs-width': (set_tabs_width, get_tabs_width),
237        'auto-indent': (set_auto_indent, get_auto_indent),
238        'insert-spaces-instead-of-tabs': (set_insert_spaces_instead_of_tabs, get_insert_spaces_instead_of_tabs),
239        'show-margin': (set_show_margin, get_show_margin),
240        'margin': (set_margin, get_margin),
241        'smart-home-end': (set_smart_home_end, get_smart_home_end),
242        'highlight-current-line': (set_highlight_current_line, get_highlight_current_line)
243        }
244   
245    def do_get_property(self, property):
246        if property.name in self._property_map:
247            return self._property_map[property.name]
248        raise AttributeError, 'unknown property %s' % property.name
249       
250    def do_set_property(self, property, value):
251        if property.name in self._property_map:
252            return self._property_map[property.name]
253        raise AttributeError, 'unknown property %s' % property.name
254       
255    # aux
256    def _set_tab_stops_internal(self):
257        real_tab_width = self._calculate_real_tab_width(self.tabs_width, ' ')
258        if real_tab_width < 0:
259            return False
260        tab_array = pango.TabArray(1, True)
261        tab_array.set_tab(0, pango.TAB_LEFT, real_tab_width)
262        self.set_tabs(tab_array)
263        return True
264
265    def _calculate_real_tab_width(self, tab_size, c):
266        if tab_size == 0:
267            return -1
268        tab_string = c * tab_size
269        layout = self.create_pango_layout(tab_string)
270        if layout:
271            return layout.get_pixel_size()[0]
272        return -1
273
274    def _set_source_buffer(self, buffer):
275        if self.source_buffer == buffer:
276            return
277        if self.source_buffer:
278            for handler_id in self.source_buffer_handler_id:
279                self.source_buffer.disconnect(handler_id)
280        if buffer and type(buffer) == SourceBuffer:
281            self.source_buffer_handler_id = [
282                self.connect("highlight_updated", self._highlight_updated_cb),
283                self.connect("marker-updated", self._marker_updated_cb),
284                self.connect("notify::style_scheme", self._buffer_style_scheme_changed_cb),
285            ]
286        else:
287            self.source_buffer = None
288            self.source_buffer_handler_id = []
289
290        if buffer:
291            self._update_style_scheme()
292
293    def _highlight_updated_cb(self, buffer, start, end):
294        visible_rect = self.get_visible_rect()
295        (y, height) = self.get_line_yrange(start)
296        updated_rect.y = y
297        (y, height) = self.get_line_yrange(end)
298        updated_rect.height = y + height - updated_rect.y
299        updated_rect.x = visible_rect.x
300        updated_rect.width = visible_rect.width
301
302        redraw_rect = updated_rect.intersect(visible_rect)
303        if not tuple(redraw_rect) == (0, 0, 0, 0):
304            (x, y) = self.buffer_to_window_coord(gtk.TEXT_WINDOW_WIDGET, redraw_rect.x, redraw_rect.y)
305            widget_rect = gdk.Rectangle(0, 0, redraw_rect.width, redraw_rect.height)
306            self.query_draw_area(widget_rect.x, widget_rect.y, widget_rect.width, widget_rect.height)
307
308    def _marker_updated_cb(self, buffer, where):
309        if not self.show_line_markers:
310            return
311        visible_rect = self.get_visible_rect()
312        (y, height) = self.get_line_yrange(where)
313        updated_rect = gdk.Rectangle(visible_rect.x, y, visible_rect.width, height)
314        redraw_rect = updated_rect.intersect(visible_rect)
315        if not tuple(redraw_rect) == (0, 0, 0, 0):
316            y_win = self.buffer_to_window_coord(gtk.TEXT_WINDOW_WIDGET, 0, redraw_rect.y)[1]
317            width = self.get_border_window_size(gtk.TEXT_WINDOW_LEFT)
318            self.query_draw_area(0, y_win, width, height)
319       
320    def _buffer_style_scheme_changed_cb(self, buffer, pspec):
321        self._update_style_scheme()
322
323    def _update_style_scheme(self):
324        # TODO: not yet implemented
325        pass
326        #buffer = self.get_buffer()
327        #if type(buffer) == SourceBuffer:
328        #    new_scheme = buffer.get_style_scheme()
329        #else:
330        #    new_scheme = None
331
332    def do_key_press_event(self, event):
333        buf = self.get_buffer()
334        modifiers = gtk.accelerator_get_default_mod_mask()
335        key = event.keyval
336        mark = buf.get_insert()
337        cur = buf.get_iter_at_mark(mark)
338
339        if key in [gdk.keyval_from_name(name) for name in ['Enter', 'Return']] and \
340           not event.state & gdk.SHIFT_MASK and \
341           self.auto_indent:
342            indent = self._compute_indentation(cur)
343            if indent:
344                # TODO: find im_context
345                #if self.im_context.filter_keypress(event):
346                #    return True
347                cur = buf.get_iter_at_mark(mark)
348                buf.begin_user_action()
349                buf.insert(cur, "\n")
350                buf.insert(cur, indent)
351                buf.end_user_action()
352                self.scroll_mark_onscreen(mark)
353                return True
354
355        if key in [gdk.keyval_from_name(name) for name in ['Tab', 'KP_Tab', 'ISO_Left_Tab']] and \
356           (event.state & modifiers) in (0, gdk.SHIFT_MASK):
357            selection = buf.get_selection_bounds()
358            has_selection = bool(selection)
359            if not has_selection:
360                it = buf.get_iter_at_mark(buf.get_insert())
361                selection = (it, it.copy())
362           
363            if self.indent_on_tab:
364                if event.state & gdk.SHIFT_MASK:
365                    self._unindent_lines(selection)
366                    return True
367                if has_selection and \
368                   ((selection[0].starts_line() and selection[1].ends_line()) or \
369                    (selection[0].get_line() != selection[1].get_line())):
370                    self._indent_lines(selection)
371                    return True
372            self._insert_tab_or_spaces(selection)
373            return True
374        TextView.do_key_press_event(self, event)
375
376    def _unindent_lines(self, (start, end)):
377        #TODO: to be implemented
378        pass
379
380    def _compute_indentation(self, cur):
381        line = cur.get_line()
382        buf = self.get_buffer()
383        start = buf.get_iter_at_line(line)
384        end = start.copy()
385        ch = end.get_char()
386
387        while ch.isspace() and not ch in ('\n', '\r') and end.compare(cur) < 0:
388            if not end.forward_char():
389                break
390            ch = end.get_char()
391
392        if start.equal(end):
393            return None
394
395        res = start.get_slice(end)
396        return res
397
398    def _indent_lines(self, (start, end)):
399        buf = self.get_buffer()
400
401        start_line = start.get_line()
402        end_line = end.get_line()
403
404        if end.get_visible_line_offset() == 0 and end_line > start_line:
405            end_line -= 1
406
407        if self.get_insert_spaces_instead_of_tabs():
408            tabs_size = self.tabs_width
409            tab_buffer = ' ' * tabs_size
410        else:
411            tab_buffer = "\t"
412
413        buf.begin_user_action()
414        for i in xrange(start_line, end_line + 1):
415            cur = buf.get_iter_at_line(i)
416            if cur.ends_line():
417                continue
418            buf.insert(cur, tab_buffer, -1)
419        buf.end_user_action()
420
421        self.scroll_mark_onscreen(buf.get_insert())
422       
423    def _insert_tab_or_spaces(self, (start, end)):
424        if self.insert_spaces:
425            tabs_size = self.tabs_width
426            cur = start.copy()
427            cur_pos = cur.get_line_offset()
428            tab_pos = cur_pos
429            while tab_pos > 0:
430                cur.backward_char()
431                c = cur.get_char()
432                if c == '\t':
433                    break
434                tab_pos -= 1
435            num_of_equivalent_spaces = tabs_size - (cur_pos - tab_pos) % tabs_size
436            tab_buf = ' ' * num_of_equivalent_spaces
437        else:
438            tab_buf = '\t'
439
440        buf = self.get_buffer()
441        buf.begin_user_action()
442        buf.delete(start, end)
443        buf.insert(start, tab_buf, -1)
444        buf.end_user_action()
445
446    def do_move_cursor(self, step, count, extend_selection):
447        buffer = self.get_buffer()
448        mark = buffer.get_insert()
449        cur = buffer.get_iter_at_mark(mark)
450        it = cur.copy()
451
452        if self.smart_home_end and  step == gtk.MOVEMENT_DISPLAY_LINE_ENDS and count == -1:
453            #move_to_first_char
454            it.set_line_offset(0)
455            while not it.ends_line():
456                if it.get_char().isspace():
457                    it.forward_char()
458                else:
459                    break
460            self._do_cursor_move(cur, it, extend_selection)
461            return
462        elif self.smart_home_end and step == gtk.MOVEMENT_DISPLAY_LINE_ENDS and count == 1:
463            #move_to_last_char
464            if not it.ends_line():
465                it.forward_to_line_end()
466            while not it.starts_line():
467                it.backward_char()
468                if not it.get_char().isspace():
469                    it.forward_char()
470                    break
471            self._do_cursor_move(cur, it, extend_selection)
472            return
473        TextView.do_move_cursor(self, step, count, extend_selection)
474               
475    def _do_cursor_move(self, cur, it, extend_selection):
476        buffer = self.get_buffer()
477        if not cur.equal(it) or not extend_selection:
478            # move_cursor
479            if extend_selection:
480                buffer.move_mark_by_name("insert", it)
481            else:
482                buffer.place_cursor(it)
483            self.scroll_mark_onscreen(buffer.get_insert())
484
485    def do_expose_event(self, event):
486        event_handled = False
487        # update highlight
488        if event.window == self.get_window(gtk.TEXT_WINDOW_TEXT) and not self.source_buffer is None:
489            visible_rect = self.get_visible_rect()
490            iter1 = self.get_line_at_y(visible_rect.y)[0]
491            iter1.backward_line()
492            iter2 = self.get_line_at_y(visible_rect.y + visible_rect.height)[0]
493            iter2.forward_line()
494            self.source_buffer.update_highlight(iter1, iter2, False)
495
496        if event.window == self.get_window(gtk.TEXT_WINDOW_LEFT):
497            self._paint_margin(event)
498            event_handled = True
499        else:
500            buffer =self.get_buffer()
501            lines = buffer.get_line_count()
502            if self.old_lines != lines:
503                self.old_lines = lines
504                w = self.get_window(gtk.TEXT_WINDOW_LEFT)
505                if not w is None:
506                    w.invalidate_rect(None, False)
507
508            if self.highlight_current_line and event.window == self.get_window(gtk.TEXT_WINDOW_TEXT):
509                cur = buffer.get_iter_at_mark(buffer.get_insert())
510                (y, height) = self.get_line_yrange(cur)
511                visible_rect = self.get_visible_rect()
512                (redraw_x, redraw_y) = self.buffer_to_window_coords(gtk.TEXT_WINDOW_TEXT,
513                                                                              visible_rect.x, visible_rect.y)
514                (win_x, win_y) = self.buffer_to_window_coords(gtk.TEXT_WINDOW_TEXT, 0, y)
515                redraw_rect = gdk.Rectangle(redraw_x, redraw_y, visible_rect.width, visible_rect.height)
516
517                if self.current_line_gc:
518                    gc = self.current_line_gc
519                else:
520                    gc = self.style.bg_gc[self.state]
521
522                if self.get_focus_hadjustment():
523                    margin = self.get_left_margin() - int(self.get_focus_hadjustment())
524                else:
525                    margin = self.get_left_margin()
526
527                event.window.draw_rectangle(gc, True, redraw_rect.x + max(0, margin - 1),
528                                   win_y, redraw_rect.width, height)
529
530            event_handled = TextView.do_expose_event(self, event)
531
532            if self.show_margin and event.window == self.get_window(gtk.TEXT_WINDOW_TEXT):
533                if self.cached_margin_width < 0:
534                    self.cached_margin_width = self._calculate_real_tab_width(self.margin, '_')
535                visible_rect = self.get_visible_rect()
536                redraw_x, redraw_y = self.buffer_to_window_coords(gtk.TEXT_WINDOW_LEFT,
537                                                                  visible_rect.x, visible_rect.y)
538                redraw_rect = gdk.Rectangle(redraw_x, redraw_y, visible_rect.width, visible_rect.height)
539                cr = self.get_window(gtk.TEXT_WINDOW_TEXT).cairo_create()
540                cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
541                cr.clip()
542                x = self.cached_margin_width - \
543                    visible_rect.x + redraw_rect.x + 0.5 + \
544                    self.get_left_margin()
545                cr.set_line_width(1.0)
546                cr.move_to(x, redraw_rect.y)
547                cr.line_to(x, redraw_rect.y + redraw_rect.height)
548                # TODO: get style properties
549                alpha = 40
550                line_color = 0
551                toggle = False
552
553                if not line_color:
554                    line_color = self.style.text[gtk.STATE_NORMAL]
555                cr.set_source_rgba(line_color.red / 65535.,
556                                   line_color.green / 65535.,
557                                   line_color.blue / 65535.,
558                                   alpha / 255.)
559                cr.stroke()
560                if toggle:
561                    # TODO: overlay draw
562                    pass
563
564       
565        return event_handled
566
567    def do_button_press_event(self, event):
568        buf = self.get_buffer()
569        if self.show_line_numbers and event.window == self.get_window(gtk.TEXT_WINDOW_LEFT):
570            (x_buf, y_buf) = self.window_to_buffer_coord(gtk.TEXT_WINDOW_LEFT, event.x, event.y)
571            line_start = self.get_line_at_y(y_buf)[0]
572            if event.type == gdk.BUTTON_PRESS and event.button == 1:
573                if event.state & gdk.CONTROL_MASK:
574                    self._select_line(buf, line_start)
575                elif event.state & gdk.SHIFT_MASK:
576                    self._extend_selection_to_line(buf, line_start)
577                else:
578                    buf.place_cursor(line_start)
579            elif event.type == gdk._2BUTTON_PRESS and event.button == 1:
580                self._select_line(buf, line_start)
581            return True
582        return TextView.do_button_press_event(self, event)
583
584    def _paint_margin(self, event):
585        if not self.show_line_numbers and not self.show_line_markers:
586            self.set_border_window_size(gtk.TEXT_WINDOW_LEFT, 0)
587            return
588        win = self.get_window(gtk.TEXT_WINDOW_LEFT)
589        buf = self.get_buffer()
590        y1 = event.area.y
591        y2 = y1 + event.area.height
592        (x1, y1) = self.window_to_buffer_coords(gtk.TEXT_WINDOW_LEFT, 0, y1)
593        (x2, y2) = self.window_to_buffer_coords(gtk.TEXT_WINDOW_LEFT, 0, y2)
594
595        (numbers, pixels) = self._get_lines(y1, y2)
596
597        if len(numbers) == 0:
598            numbers.append(0)
599            pixels.append(0)
600
601        tmp = str(max(99, buf.get_line_count()))
602        layout = self.create_pango_layout(tmp)
603        text_width = layout.get_pixel_size()[0]
604        layout.set_width(text_width)
605        layout.set_alignment(pango.ALIGN_RIGHT)
606
607        if self.show_line_numbers:
608            margin_width = text_width + 4
609        else:
610            margin_width = 0
611        x_pixmap = margin_width
612        if self.show_line_markers:
613            margin_width += GUTTER_PIXMAP
614        if margin_width == 0:
615            return
616
617        self.set_border_window_size(gtk.TEXT_WINDOW_LEFT, margin_width)
618        markers = None
619        if self.source_buffer and self.show_line_markers:
620            # TODO: not yet implemented
621            pass
622
623        #current_marker = markers
624        #if current_marker:
625        #    marker_line = current_marker.data.get_line()
626
627        cur = buf.get_iter_at_mark(buf.get_insert())
628        cur_line = cur.get_line() + 1
629        for number, pixel in zip(numbers, pixels):
630            pos = self.buffer_to_window_coords(gtk.TEXT_WINDOW_LEFT, 0, pixel)[1]
631            if self.show_line_numbers:
632                line_to_paint = number + 1
633                if line_to_paint == cur_line:
634                    layout.set_markup("<b>%d</b>" % line_to_paint)
635                else:
636                    layout.set_markup("%d" % line_to_paint)
637                self.style.paint_layout(win, self.state, False, None, self, None, text_width + 2, pos, layout)
638
639            if self.show_line_markers and current_marker and marker_line == number:
640                # TODO: _draw_line_markers
641                pass
642       
643
644    def _get_lines(self, first_y, last_y):
645        buffer_coords = []
646        numbers = []
647        last_line_num = -1
648        it = self.get_line_at_y(first_y)[0]
649
650        while not it.is_end():
651            (y, height) = self.get_line_yrange(it)
652            buffer_coords.append(y)
653            last_line_num = it.get_line()
654            numbers.append(last_line_num)
655            if y + height >= last_y:
656                break
657            it.forward_line()
658
659        if it.is_end():
660            (y, height) = self.get_line_yrange(it)
661            line_num = it.get_line()
662            if line_num != last_line_num:
663                buffer_coords.append(y)
664                numbers.append(line_num)
665
666        return (numbers, buffer_coords)
667           
668           
669
670class SourceBuffer(gtk.TextBuffer):
671    pass
672
673gobject.type_register(SourceView)
674
675if __name__ == "__main__":
676    import gtk
677    class TestApp:
678        def destroy(self, widget, data=None):
679            gtk.main_quit()
680
681        def __init__(self):
682            self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
683            self.window.set_size_request(400, 400)
684            self.window.connect("destroy", self.destroy)
685            self.textview = SourceView()
686            self.textview.set_tabs_width(10)
687            self.textview.set_auto_indent(True)
688            self.textview.set_insert_spaces_instead_of_tabs(True)
689            self.textview.set_smart_home_end(True)
690            self.textview.set_highlight_current_line(True)
691            self.textview.set_show_line_numbers(True)
692            self.textview.set_margin(80)
693            self.textview.set_show_margin(True)
694            self.window.add(self.textview)
695            self.window.show_all()
696
697    app = TestApp()
698    gtk.main()
699
Note: See TracBrowser for help on using the browser.