#!/usr/bin/env python
#
from __future__ import division, print_function
from vedo import Plotter
from vedo.mesh import Mesh
from vedo.tetmesh import TetMesh
from vedo.ugrid import UGrid
from vedo.volume import Volume
from vedo import settings, printc, getColor, humansort, __version__
from vedo import io, load
import vedo.applications as applications
from vedo.shapes import Text2D, VedoLogo
from vedo.docs import tips
import sys, argparse, os, glob

#################################################################################################
class MyArgs:
    def __init__(self):
        self.files = []
        self.color = None
        self.alpha = 1
        self.wireframe = False
        self.point_size = -1
        self.showedges = False ##
        self.lighting = 'default'##
        self.flat = False##
        self.axes_type = 4
        self.no_camera_share = False
        self.legend_off = True
        self.full_screen = False
        self.background = ""
        self.background_grad = ""
        self.zoom = 1
        self.quiet = False
        self.multirenderer_mode = False
        self.scrolling_mode = False
        self.ray_cast_mode = False
        self.z_spacing = 1
        self.y_spacing = 1
        self.x_spacing = 1
        self.slicer = False
        self.slicer2d = False
        self.lego = False
        self.cmap = "jet"
        self.mode = 0
        self.reload = False

#################################################################################################
vp = None
args = MyArgs()
kact = 0
cmap_slicer = None


#################################################################################################
def draw_scene():
    global kact, cmap_slicer

    nfiles = len(args.files)
    if nfiles == 0:
        print("No input files provided.")
        return
    humansort(args.files)

    wsize = "auto"
    if args.full_screen:
        wsize = "full"

    if args.ray_cast_mode:
        if args.background == "":
            args.background = "bb"

    if args.background == "":
        args.background = "white"

    if args.background_grad:
        args.background_grad = getColor(args.background_grad)

    N = None
    if args.multirenderer_mode:
        if nfiles < 201:
            N = nfiles
        if nfiles > 200:
            printc("Warning: option '-n' allows a maximum of 200 files", c=1)
            printc("         you are trying to load ", nfiles, " files.\n", c=1)
            N = 200
        vp = Plotter(size=wsize, N=N, bg=args.background, bg2=args.background_grad)
        vp.axes = args.axes_type
        if args.axes_type == 4 or args.axes_type == 5:
            vp.axes = 0
    else:
        N = nfiles
        vp = Plotter(size=wsize, bg=args.background, bg2=args.background_grad)
        vp.axes = args.axes_type

    vp.verbose = not args.quiet
    vp.sharecam = not args.no_camera_share

    leg = True
    wire = False
    if args.legend_off or nfiles == 1:
        leg = None
    if args.wireframe:
        wire = True

    ##########################################################
    # special case of SLC/TIFF volumes with -g option
    if args.ray_cast_mode:
        # print('DEBUG special case of SLC/TIFF volumes with -g option')

        vol = io.load(args.files[0], force=args.reload)

        if not isinstance(vol, Volume):
            printc("~times Type Error:\nExpected a Volume but loaded", type(vol),
                   'object.', c=1)
            return

        sp = vol.spacing()
        vol.spacing([sp[0]*args.x_spacing, sp[1]*args.y_spacing, sp[2]*args.z_spacing])
        vol.mode(int(args.mode)).color(args.cmap).jittering(True)
        if args.lighting !='default':
            vol.lighting(args.lighting)
        vp = applications.RayCaster(vol)
        vp.show(viewup="z", interactive=True)
        vp.sliders[0][0].SetEnabled(False)
        vp.sliders[1][0].SetEnabled(False)
        vp.sliders[2][0].SetEnabled(False)
        return

    ##########################################################
    # special case of SLC/TIFF/DICOM volumes with --slicer option
    elif args.slicer:
        # print('DEBUG special case of SLC/TIFF/DICOM volumes with --slicer option')

        useSlider3D = False
        if args.axes_type == 4:
            args.axes_type=1
        elif args.axes_type == 3:
            args.axes_type=1
            useSlider3D = True

        vol = io.load(args.files[0], force=args.reload)

        sp = vol.spacing()
        vol.spacing([sp[0]*args.x_spacing, sp[1]*args.y_spacing, sp[2]*args.z_spacing])

        settings.plotter_instance = None # reset

        plt = applications.Slicer(
                     vol,
                     bg='white', bg2='lb',
                     useSlider3D=useSlider3D,
                     cmaps=[args.cmap, "Spectral_r", "hot_r", "bone_r", "gist_ncar_r"],
                     alpha=args.alpha,
                     axes=args.axes_type,
                     clamp=True,
                     size=(1000,800),
                     )

        plt.show()
        return

    ########################################################################
    elif args.slicer2d:
        # print('DEBUG special case of SLC/TIFF/DICOM volumes with --slicer2d option')
        vol = io.load(args.files[0], force=args.reload)
        sp = vol.spacing()
        vol.spacing([sp[0]*args.x_spacing, sp[1]*args.y_spacing, sp[2]*args.z_spacing])
        settings.plotter_instance = None # reset
        applications.Slicer2d(vol)
        return


    ########################################################################
    # normal mode for single VOXEL file with Isosurface Slider or LEGO mode
    elif nfiles == 1 and (
        ".slc" in args.files[0].lower()
        or ".vti" in args.files[0].lower()
        or ".tif" in args.files[0].lower()
        or ".mhd" in args.files[0].lower()
        or ".nrrd" in args.files[0].lower()
        or ".dem" in args.files[0].lower()
    ):
        # print('DEBUG normal mode for single VOXEL file with Isosurface Slider or LEGO mode')
        vol = io.load(args.files[0], force=args.reload)
        sp = vol.spacing()
        vol.spacing([sp[0]*args.x_spacing, sp[1]*args.y_spacing, sp[2]*args.z_spacing])
        if not args.color:
            args.color = 'gold'
        vp = applications.IsosurfaceBrowser(vol, lego=args.lego, c=args.color, cmap=args.cmap)
        vp.show(zoom=args.zoom, viewup="z")
        return


    ########################################################################
    # NORMAL mode for single or multiple files, or multiren mode, or numpy scene
    elif nfiles == 1 or (not args.scrolling_mode):
        # print('DEBUG NORMAL mode for single or multiple files, or multiren mode')

        ##########################################################
        # loading a full scene
        if ".npy" in args.files[0] or ".npz" in args.files[0] and nfiles == 1:

            objct = io.load(args.files[0], force=args.reload)

            if "Plotter" in str(type(objct)): # loading a full scene
                objct.show()
                return
            else:                             # loading a set of meshes
                vp.show(objct)
                return
        ##########################################################

        actors = []
        for i in range(N):
            f = args.files[i]

            colb = args.color
            if args.color is None and N > 1:
                colb = i

            actor = load(f, force=args.reload)

            if isinstance(actor, (TetMesh, UGrid)):
                actor = actor.tomesh().shrink(0.975).c(colb).alpha(args.alpha)

            if isinstance(actor, Mesh):
                actors.append(actor)
                actor.c(colb).alpha(args.alpha).wireframe(wire).lighting(args.lighting)
                if args.flat:
                    actor.flat()
                else:
                    actor.phong()

                if leg:
                    actor.legend(os.path.basename(f))

                if args.point_size > 0:
                    try:
                        actor.GetProperty().SetPointSize(args.point_size)
                        actor.GetProperty().SetRepresentationToPoints()
                    except AttributeError:
                        pass

                if args.showedges:
                    try:
                        actor.GetProperty().SetEdgeVisibility(1)
                        actor.GetProperty().SetLineWidth(0.1)
                        actor.GetProperty().SetRepresentationToSurface()
                    except AttributeError:
                        pass
            else:
                actors.append(actor)

            if args.multirenderer_mode:
                actor._legend = None
                vp.show(actor, at=i, interactive=False, zoom=args.zoom)
                vp.actors = actors

        if args.multirenderer_mode:
            vp.interactor.Start()
        else:

            # if scene is empty just draw the logo
            if all(a is None for a in actors):
                actors = [VedoLogo(distance=6, c='k'),
                          Text2D('..could not load file(s)', s=0.9, bg='y',
                                  c='r', font='', pos='bottom-center'),
                          ]
                vp.axes=0
                vp.backgroundColor('w','bb')

            vp.show(actors, interactive=True, zoom=args.zoom)
        return

    ########################################################################
    # scrolling mode  -s
    else:
        #print("DEBUG simple browser mode  -s")
        if vp.axes==4:
            vp.axes=1

        acts = vp.load(args.files, force=args.reload)
        for a in acts:
            if hasattr(a, 'c'): #Picture doesnt have it
                a.c(args.color)
            a.alpha(args.alpha)

        applications.Browser(acts)
        vp.show(interactive=True, zoom=args.zoom)


#################################################################################
# GUI or argparse
#################################################################################
if len(sys.argv) == 1 or os.name == "nt":  # no args are passed, pop up GUI

    # print('DEBUG gui started')
    if sys.version_info[0] > 2:
        from tkinter import Frame, Tk, BOTH, Label, Scale, Checkbutton, BooleanVar, StringVar
        from tkinter.ttk import Button, Style, Combobox, Entry
        from tkinter import filedialog as tkFileDialog
    else:
        from Tkinter import Frame, Tk, BOTH, Label, Scale, Checkbutton, BooleanVar, StringVar
        from ttk import Button, Style, Combobox, Entry
        import tkFileDialog

    ######################
    class vedoGUI(Frame):
        def __init__(self, parent):
            Frame.__init__(self, parent, bg="white")
            self.parent = parent
            self.filenames = []
            self.noshare = BooleanVar()
            self.flat = BooleanVar()
            self.xspacing = StringVar()
            self.yspacing = StringVar()
            self.zspacing = StringVar()
            self.background_grad = BooleanVar()
            self.initUI()

        def initUI(self):
            self.parent.title("vedo")
            self.style = Style()
            self.style.theme_use("clam")
            self.pack(fill=BOTH, expand=True)

            ############import
            Button(self, text="Import Files", command=self._importCMD, width=15).place(x=115, y=17)

            ############meshes
            Frame(root, height=1, width=398, bg="grey").place(x=1, y=60)
            Label(self, text="Meshes", fg="white", bg="green", font=("Courier 11 bold")).place(x=20, y=65)

            # color
            Label(self, text="Color:", bg="white").place(x=30, y=98)
            colvalues = ('by scalar', 'gold','red','green','blue', 'coral','plum','tomato')
            self.colorCB = Combobox(self, state="readonly", values=colvalues, width=10)
            self.colorCB.current(0)
            self.colorCB.place(x=100, y=98)

            # mode
            modvalues = ('surface', 'surf. & edges','wireframe','point cloud')
            self.surfmodeCB = Combobox(self, state="readonly", values=modvalues, width=14)
            self.surfmodeCB.current(0)
            self.surfmodeCB.place(x=205, y=98)

            # alpha
            Label(self, text="Alpha:", bg="white").place(x=30, y=145)
            self.alphaCB = Scale(
                self,
                from_=0,
                to=1,
                resolution=0.02,
                bg="white",
                length=220,
                orient="horizontal",
            )
            self.alphaCB.set(1.0)
            self.alphaCB.place(x=100, y=125)

            # lighting
            Label(self, text="Lighting:", bg="white").place(x=30, y=180)
            lightvalues = ('default','metallic','plastic','shiny','glossy')
            self.lightCB = Combobox(self, state="readonly", values=lightvalues, width=10)
            self.lightCB.current(0)
            self.lightCB.place(x=100, y=180)
            # shading phong or flat
            self.flatCB = Checkbutton(self, text="flat shading", var=self.flat, bg="white")
            #self.flatCB.select()
            self.flatCB.place(x=210, y=180)

            # rendering arrangement
            Label(self, text="Arrange as:", bg="white").place(x=30, y=220)
            schemevalues = ('superpose (default)','mesh browser', 'n sync-ed renderers')
            self.schememodeCB = Combobox(self, state="readonly", values=schemevalues, width=20)
            self.schememodeCB.current(0)
            self.schememodeCB.place(x=160, y=220)

            # share cam
            self.noshareCB = Checkbutton(self, text="independent cameras",
                                         variable=self.noshare, bg="white")
            self.noshareCB.place(x=160, y=245)


            ############volumes
            Frame(root, height=1, width=398, bg="grey").place(x=1, y=275)
            Label(self, text="Volumes", fg="white", bg="blue", font=("Courier 11 bold")).place(x=20, y=280)

            # mode
            Label(self, text="Rendering mode:", bg="white").place(x=30, y=310)
            modevalues = (
                "isosurface (default)",
                "composite",
                "maximum proj",
                "lego",
                "slicer",
                "slicer2d",
            )
            self.modeCB = Combobox(self, state="readonly", values=modevalues, width=20)
            self.modeCB.current(0)
            self.modeCB.place(x=160, y=310)

            Label(self, text="Spacing factors:", bg="white").place(x=30, y=335)
            self.xspacingCB = Entry(self, textvariable=self.xspacing, width=3)
            self.xspacing.set('1.0')
            self.xspacingCB.place(x=160, y=335)
            self.yspacingCB = Entry(self, textvariable=self.yspacing, width=3)
            self.yspacing.set('1.0')
            self.yspacingCB.place(x=210, y=335)
            self.zspacingCB = Entry(self, textvariable=self.zspacing, width=3)
            self.zspacing.set('1.0')
            self.zspacingCB.place(x=260, y=335)


            ############## options
            Frame(root, height=1, width=398,bg="grey").place(x=1, y=370)
            Label(self, text="Options", fg='white', bg="brown", font=("Courier 11 bold")).place(x=20, y=375)

            # backgr color
            Label(self, text="Background color:", bg="white").place(x=30, y=405)
            bgcolvalues = ("white", "lightyellow", "azure", "blackboard", "black")
            self.bgcolorCB = Combobox(self, state="readonly", values=bgcolvalues, width=9)
            self.bgcolorCB.current(3)
            self.bgcolorCB.place(x=160, y=405)
            # backgr color gradient
            self.backgroundGradCB = Checkbutton(self, text="gradient",
                                                variable=self.background_grad, bg="white")
            self.backgroundGradCB.place(x=255, y=405)

            ################ render button
            Frame(root, height=1, width=398, bg="grey").place(x=1, y=437)
            Button(self, text="Render", command=self._run, width=15).place(x=115, y=454)


        def _importCMD(self):
            ftypes = [
                ("All files", "*"),
                ("VTK files", "*.vtk"),
                ("VTK files", "*.vtp"),
                ("VTK files", "*.vts"),
                ("VTK files", "*.vtu"),
                ("Surface Mesh", "*.ply"),
                ("Surface Mesh", "*.obj"),
                ("Surface Mesh", "*.stl"),
                ("Surface Mesh", "*.off"),
                ("Surface Mesh", "*.facet"),
                ("Volume files", "*.tif"),
                ("Volume files", "*.slc"),
                ("Volume files", "*.vti"),
                ("Volume files", "*.mhd"),
                ("Volume files", "*.nrrd"),
                ("Volume files", "*.nii"),
                ("Volume files", "*.dem"),
                ("Picture files", "*.png"),
                ("Picture files", "*.jpg"),
                ("Picture files", "*.bmp"),
                ("Picture files", "*.jpeg"),
                ("Geojson files", "*.geojson"),
                ("DOLFIN files", "*.xml.gz"),
                ("DOLFIN files", "*.xml"),
                ("DOLFIN files", "*.xdmf"),
                ("Neutral mesh", "*.neu*"),
                ("GMESH", "*.gmsh"),
                ("Point Cloud", "*.pcd"),
                ("3DS", "*.3ds"),
                ("Numpy scene file", "*.npy"),
                ("Numpy scene file", "*.npz"),
            ]
            self.filenames = tkFileDialog.askopenfilenames(parent=root, filetypes=ftypes)
            args.files = list(self.filenames)


        def _run(self):

            tips()

            args.files = list(self.filenames)
            if self.colorCB.get() == "by scalar":
                args.color = None
            else:
                if self.colorCB.get() == 'red':
                    args.color = 'crimson'
                elif self.colorCB.get() == 'green':
                    args.color = 'limegreen'
                elif self.colorCB.get() == 'blue':
                    args.color = 'darkcyan'
                else:
                    args.color = self.colorCB.get()

            args.alpha = self.alphaCB.get()

            args.wireframe = False
            args.showedges = False
            args.point_size = 0
            if self.surfmodeCB.get() == 'point cloud':
                args.point_size = 2
            elif self.surfmodeCB.get() == 'wireframe':
                args.wireframe = True
            elif self.surfmodeCB.get() == 'surf. & edges':
                args.showedges = True
            else:
                pass # normal surface mode

            args.lighting = self.lightCB.get()
            args.flat = self.flat.get()

            args.no_camera_share = self.noshare.get()
            args.background = self.bgcolorCB.get()

            args.background_grad = None
            if self.background_grad.get():
                b = getColor(args.background)
                args.background_grad = (b[0]/1.8, b[1]/1.8, b[2]/1.8)

            args.multirenderer_mode = False
            args.scrolling_mode = False
            if self.schememodeCB.get() == "n sync-ed renderers":
                args.multirenderer_mode = True
            elif self.schememodeCB.get() == "mesh browser":
                args.scrolling_mode = True

            args.ray_cast_mode = False
            args.lego = False
            args.slicer = False
            args.slicer2d = False
            args.lego = False
            args.mode = 0
            if self.modeCB.get() == "composite":
                args.ray_cast_mode = True
                args.mode = 0
            elif self.modeCB.get() == "maximum proj":
                args.ray_cast_mode = True
                args.mode = 1
            elif self.modeCB.get() == "slicer":
                args.slicer = True
            elif self.modeCB.get() == "slicer2d":
                args.slicer2d = True
            elif self.modeCB.get() == "lego":
                args.lego = True

            args.x_spacing = 1
            args.y_spacing = 1
            args.z_spacing = 1
            if self.xspacing.get() != '1.0': args.x_spacing = float(self.xspacing.get())
            if self.yspacing.get() != '1.0': args.y_spacing = float(self.yspacing.get())
            if self.zspacing.get() != '1.0': args.z_spacing = float(self.zspacing.get())

            draw_scene()
            if os.name == "nt":
                exit()
            if settings.plotter_instance:
                settings.plotter_instance.close()

    root = Tk()
    root.geometry("360x500")
    app = vedoGUI(root)

    def tkcallback(event):
        #printc("xy cursor position:", event.x, event.y, event.char)
        if event.char == 'q':
            root.destroy()

    app.bind("<Key>", tkcallback)
    app.focus_set()
    app.pack()

    if os.name == "nt" and len(sys.argv) > 1:
        app.filenames = sys.argv[1:]
        print("Already", len(app.filenames), "files loaded.")

    root.mainloop()


else:  ################################################################################################# command line mode

    pr = argparse.ArgumentParser(description="version "+str(__version__)+""" -
                                 check out home page https://github.com/marcomusy/vedo""")
    pr.add_argument('files', nargs='*',             help="Input filename(s)")
    pr.add_argument("-c", "--color", type=str,      help="mesh color [integer or color name]", default=None, metavar='')
    pr.add_argument("-a", "--alpha",    type=float, help="alpha value [0-1]", default=1, metavar='')
    pr.add_argument("-w", "--wireframe",            help="use wireframe representation", action="store_true")
    pr.add_argument("-p", "--point-size", type=float, help="specify point size", default=-1, metavar='')
    pr.add_argument("-e", "--showedges",            help="show a thin line on mesh edges", action="store_true")
    pr.add_argument("-k", "--lighting", type=str,   help="metallic, plastic, shiny or glossy", default='default', metavar='')
    pr.add_argument("-K", "--flat",                 help="use flat shading", action="store_true")
    pr.add_argument("-x", "--axes-type", type=int,  help="specify axes type [0-5]", default=4, metavar='')
    pr.add_argument("-i", "--no-camera-share",      help="do not share camera in renderers", action="store_true")
    pr.add_argument("-l", "--legend-off",           help="do not show legends", action="store_true")
    pr.add_argument("-f", "--full-screen",          help="full screen mode", action="store_true")
    pr.add_argument("-bg","--background", type=str, help="background color [integer or color name]", default='', metavar='')
    pr.add_argument("-bg2", "--background-grad",    help="use background color gradient", default='', metavar='')
    pr.add_argument("-z", "--zoom", type=float,     help="zooming factor", default=1, metavar='')
    pr.add_argument("-q", "--quiet",                help="quiet mode, less verbose", default=False, action="store_false")
    pr.add_argument("-n", "--multirenderer-mode",   help="Multi renderer Mode: files go to separate renderers", action="store_true")
    pr.add_argument("-s", "--scrolling-mode",       help="Scrolling Mode: use slider to scroll files", action="store_true")
    pr.add_argument("-g", "--ray-cast-mode",        help="GPU Ray-casting Mode for 3D image files", action="store_true")
    pr.add_argument("-gx", "--x-spacing", type=float, help="Volume x-spacing factor [1]", default=1, metavar='')
    pr.add_argument("-gy", "--y-spacing", type=float, help="Volume y-spacing factor [1]", default=1, metavar='')
    pr.add_argument("-gz", "--z-spacing", type=float, help="Volume z-spacing factor [1]", default=1, metavar='')
    pr.add_argument("--mode",                       help="Voxel rendering composite mode", default=0, metavar='')
    pr.add_argument("--cmap",                       help="Voxel rendering color map name", default='jet', metavar='')
    pr.add_argument("--slicer",                     help="Slicer Mode for volumetric data", action="store_true")
    pr.add_argument("--slicer2d",                   help="2D Slicer Mode for volumetric data", action="store_true")
    pr.add_argument("--lego",                       help="Voxel rendering for 3D image files", action="store_true")
    pr.add_argument("-r", "--run",                  help="Run example from vedo/examples", metavar='')
    pr.add_argument("--list",                       help="List examples in vedo/examples", action="store_true")
    pr.add_argument("--reload",                     help="Reload the file, ignoring any previous download", action="store_true")
    args = pr.parse_args()

    if args.run:
        expath = os.path.join(settings.installdir, "examples", "**", "*.py")
        exfiles = [f for f in glob.glob(expath, recursive=True)]
        f2search = os.path.basename(args.run).lower()
        matching = [s for s in exfiles if (f2search in os.path.basename(s).lower() and "__" not in s)]
        matching = list(sorted(matching))
        nmat = len(matching)
        if nmat == 0:
            printc("No matching example found containing string:", args.run, c=1)
            printc(" Use vedo --list to show available scripts.", c=1)
            printc(" Current installation directory is:", settings.installdir, c=1)
            exit(1)

        if nmat > 1:
            printc("\nSelect one of", nmat, "matching scripts:", c='y', italic=1)

        for mat in matching[:25]:
            # printc('Running matching example:', c='y', italic=0, end=' ')
            printc(os.path.basename(mat).replace('.py',''), c='y', italic=1, end=' ')
            with open(mat) as fm:
                lline = ''.join(fm.readlines(60))
                lline = lline.replace('\n','').replace('\'','').replace('\"','').replace('-','')
                line = lline[:56] #cut
                if line.startswith('from'): line=''
                if line.startswith('import'): line=''
                if len(lline) > len(line):
                    line += '..'
                if len(line)>5:
                    printc('-', line,  c='y', bold=0, italic=1)
                else:
                    print()

        if nmat>25:
            printc('...', c='y')

        if nmat > 1:
            exit(0)

        if args.no_camera_share: # -i option to dump the full code
            print()
            with open(matching[0]) as fm:
                codedump = fm.readlines()
            for line in codedump:
                printc(line.strip(), c='cyan', italic=1, bold=0)
            print()

        printc("("+matching[0]+")", c='y', bold=0, italic=1)
        os.system('python3 ' + matching[0])

    elif args.list:
        print()
        printc("Available examples are:", box='-')
        expath = os.path.join(settings.installdir, 'examples')

        exfiles = [(f, os.path.basename(f))
                    for f in sorted(glob.glob(
                                              os.path.join(expath, "**", "*.py"),
                                              recursive=True,
                                             )
                                    )
                  ]
        nl = 4

        printc("Basic examples:", c='g', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "basic" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='g', bold=0)

        printc("Advanced examples:", c='y', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "advanced" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='y', bold=0)

        printc("Simulation examples:", c='m', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "simulation" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='m', bold=0)

        printc("Plotting 2D examples:", c='w', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "pyplot" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='w', bold=0)

        printc("Volumetric examples:", c='b', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "volumetric" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='b', bold=0)

        printc("Tetrahedral mesh examples:", c='y', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "tetmesh" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='y', bold=0)

        printc("Other examples:", c='cyan', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "other" in f and "dolfin" not in f and "trimesh" not in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='cyan', bold=0)

        printc("      Dolfin examples:", c='r', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "dolfin" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='r', bold=0)

        printc("      Trimesh examples:", c='m', bold=1, underline=1)
        scs = []
        for f,bn in exfiles:
            if "trimesh" in f:
                lb = ' ' if (len(scs)+1)%nl else '\n'
                scs.append(lb+bn.replace('.py',''))
        printc("".join(scs), c='m', bold=0)
        print()

    else:
        draw_scene()
