4

I see on https://live.gnome.org/GtkSourceView that "we can now support code folding in GtkSourceView" using gtk+ 2.8. Yet I can't find any examples anywhere. Is it ready to be used? Are there any examples that can be provided to get the ball rolling?

I've read the bug report and I have emailed Bijan Binaee to offer my assistance, but did not hear anything in return. Anyone have any insight? Thanks.

nomadicME
  • 1,389
  • 5
  • 15
  • 35
  • 1
    I think that statement refers to the infrastructure needed to support folding. As for Bijan, AFAICT, Iran has recently blocked gmail, so he (probably) has no access to that account. You might try the IRC account. – ergosys Jun 07 '12 at 03:39
  • I know they've been talking about adding code folding for quite some time. I agree that your best bet is to ask around on IRC. The Gedit guys are usually pretty active and would know what's going on with GtkSourceView. – Micah Carrick Jun 09 '12 at 02:56

2 Answers2

1

I recently revisited this topic and was able to cobble together a simple python example, which demonstrates one way to accomplish code folding in gtk:

#!/usr/bin/python

import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '3.0')

import signal
import sys,os
import cairo
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
from gi.repository import GObject as gobject
from gi.repository import GtkSource as gtksource
from gi.repository.GdkPixbuf import Pixbuf

theme = 'light'     # [light/dark] type of gtk theme in use

class Editor:

        def check_sigint_timer(self,timeout):
                gobject.timeout_add_seconds(timeout, self.check_sigint)

        def check_sigint(self):
                return True

        def quit_activated(self):
                dialog = gtk.MessageDialog(parent=self.window, type=gtk.MessageType.QUESTION, buttons=gtk.ButtonsType.YES_NO)   
                dialog.set_title("Question")
                dialog.set_position(gtk.WindowPosition.CENTER_ALWAYS)
                dialog.set_markup("Are you sure you want to quit?")
                response = dialog.run()
                if response == gtk.ResponseType.YES:
                    dialog.destroy()
                    gtk.main_quit()
                elif response == gtk.ResponseType.NO:
                    dialog.destroy()

        def delete_event_cb(self, widget, data=None):
                print "delete_event signal occurred"
                self.quit_activated()
                return True

        def destroy_cb(self, widget, data=None):
                print "destroy signal occurred"
                self.quit_activated()

        def signal_handler(self, signal, frame):
                print '\nYou pressed Ctrl+C!, exiting'
                gtk.main_quit()

        def get_fold_minus_pixbuf(self):
                w = 24
                h = 24
                surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, w, h)
                cr = cairo.Context (surface)
                if theme == 'dark':
                    cr.set_source_rgb(0.94, 0.94, 0.94)
                else:       
                    cr.set_source_rgb(0., 0., 0.)
                cr.rectangle(0,0,w,h)
                cr.fill()

                if theme == 'dark':
                    cr.set_source_rgb(0., 0., 0.)
                else:       
                    cr.set_source_rgb(0.94, 0.94, 0.94)
                cr.move_to (w/5.,h/2.)
                cr.line_to (w*0.8,h/2.)
                cr.stroke ()

                pixbuf = gdk.pixbuf_get_from_surface(surface,0,0,w,h)
                return pixbuf

        def get_fold_plus_pixbuf(self):
                w = 24
                h = 24
                surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, w, h)
                cr = cairo.Context (surface)
                if theme == 'dark':
                    cr.set_source_rgb(0.94, 0.94, 0.94)
                else:       
                    cr.set_source_rgb(0., 0., 0.)
                cr.rectangle(0,0,w,h)
                cr.fill()

                if theme == 'dark':
                    cr.set_source_rgb(0., 0., 0.)
                else:       
                    cr.set_source_rgb(0.94, 0.94, 0.94)
                cr.move_to (w/5.,h/2.)
                cr.line_to (w*0.8,h/2.)
                cr.stroke ()

                cr.move_to (w/2.,h/5.)
                cr.line_to (w/2.,h*0.8)
                cr.stroke ()

                pixbuf = gdk.pixbuf_get_from_surface(surface,0,0,w,h)
                return pixbuf

        def get_fold_vert_pixbuf(self):
                w = 24
                h = 24
                surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, w, h)
                cr = cairo.Context (surface)
                if theme == 'dark':
                    cr.set_source_rgb(1., 1., 1.)
                else:       
                    cr.set_source_rgb(0., 0., 0.)
                cr.move_to (w/2,0)
                cr.line_to (w/2,h)
                cr.stroke ()
                pixbuf = gdk.pixbuf_get_from_surface(surface,0,0,w,h)
                return pixbuf

        def get_fold_end_pixbuf(self):
                w = 24
                h = 24
                surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, w, h)
                cr = cairo.Context (surface)
                if theme == 'dark':
                    cr.set_source_rgb(1., 1., 1.)
                else:       
                    cr.set_source_rgb(0., 0., 0.)
                cr.move_to (w/2,0)
                cr.line_to (w/2,h/2)
                cr.line_to (w,h/2)
                cr.stroke ()
                pixbuf = gdk.pixbuf_get_from_surface(surface,0,0,w,h)
                return pixbuf

        def place_mark(self,mtype,line):
                iter = self.buffer.get_iter_at_line (line)

                if mtype == '+':
                    self.buffer.create_source_mark(None, "fold_plus", iter)
                elif mtype == '-':
                    self.buffer.create_source_mark(None, "fold_minus", iter)
                elif mtype == '|':
                    self.buffer.create_source_mark(None, "fold_vert", iter)
                elif mtype == 'end':
                    self.buffer.create_source_mark(None, "fold_end", iter)

        def create_marks(self):
                pixbuf = self.get_fold_plus_pixbuf()
                mark_attr = gtksource.MarkAttributes.new()
                mark_attr.set_pixbuf(pixbuf)
                self.view.set_mark_attributes("fold_plus",mark_attr,0)

                pixbuf = self.get_fold_minus_pixbuf()
                mark_attr = gtksource.MarkAttributes.new()
                mark_attr.set_pixbuf(pixbuf)
                self.view.set_mark_attributes("fold_minus",mark_attr,0)

                pixbuf = self.get_fold_vert_pixbuf()
                mark_attr = gtksource.MarkAttributes.new()
                mark_attr.set_pixbuf(pixbuf)
                self.view.set_mark_attributes("fold_vert",mark_attr,0)

                pixbuf = self.get_fold_end_pixbuf()
                mark_attr = gtksource.MarkAttributes.new()
                mark_attr.set_pixbuf(pixbuf)
                self.view.set_mark_attributes("fold_end",mark_attr,0)

        def mark_activated_cb(self,view,iter,event):
                line = iter.get_line()
                marks = self.buffer.get_source_marks_at_iter(iter)          
                for mark in marks:
                    cat = mark.get_category()   
                    if cat == 'fold_minus':
                        start = self.buffer.get_iter_at_line (self.block[0]+1)
                        end = self.buffer.get_iter_at_line (self.block[1]+1)
                        self.buffer.apply_tag_by_name("invisible",start,end)

                        # remove the existing mark, then create the opposite mark
                        start = self.buffer.get_iter_at_line (self.block[0])
                        self.buffer.remove_source_marks(start,start)
                        self.place_mark('+',self.block[0])

                    elif cat == 'fold_plus':
                        start = self.buffer.get_iter_at_line (self.block[0]+1)
                        end = self.buffer.get_iter_at_line (self.block[1]+1)
                        self.buffer.remove_all_tags(start,end)

                        # remove the existing mark, then create the opposite mark
                        start = self.buffer.get_iter_at_line (self.block[0])
                        self.buffer.remove_source_marks(start,start)
                        self.place_mark('-',self.block[0])

        def __init__(self):

                signal.signal(signal.SIGINT, self.signal_handler)

                self.window = gtk.Window(gtk.WindowType.TOPLEVEL)
                self.window.connect("delete_event", self.delete_event_cb)
                self.window.connect("destroy", self.destroy_cb)
                self.window.set_border_width(10)
                self.window.maximize()

                self.view = gtksource.View()
                self.view.connect("line-mark-activated",self.mark_activated_cb)
                self.buffer = self.view.get_buffer()
                self.view.set_show_line_numbers(True)
                self.view.set_show_line_marks(True)
                sw = gtk.ScrolledWindow()
                sw.add(self.view)
                self.window.add(sw)

                path = sys.argv[0]
                txt = open(path).read()
                self.buffer.set_text(txt)

                lm = gtksource.LanguageManager.new()
                lang = lm.guess_language(path)
                self.buffer.set_highlight_syntax(True)
                self.buffer.set_language(lang)

                self.buffer.create_tag("invisible",invisible=True)

                self.block = [25,35]
                self.create_marks()
                self.place_mark('-',self.block[0])

                for i in xrange(self.block[0],self.block[1]):
                    self.place_mark('|',i)

                self.place_mark('end',self.block[1])

                self.window.show_all()

                self.check_sigint_timer(1)

        def main(self):
                gtk.main()

if __name__ == "__main__":
        ed = Editor()
        ed.main()

Be sure and change the theme variable to reflect the type of gtk3 theme you happen to be using.

It would be greatly appreciated if anyone can show how to eliminate the line gaps in the vertical line drawn in the gutter.

nomadicME
  • 1,389
  • 5
  • 15
  • 35
0

Sorry about the mail, it probably missed by me

There is some works on GTK Source View code folding based on GTef. You can find the latest working sources on This repository

You can also check bugzilla page

Pazel1374
  • 218
  • 3
  • 14