# UI for gathering needed data and storing them in director bean class
# then it calls PNGGeneration, and (if everything was OK) AVIGeneration

# TODO: change default directory when selecting new according to already set item
# (for temp dirs, avi and fct files selections)

import os
import fnmatch
import tempfile
import gi

gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk, Gtk, GObject

from fract4d_compiler import fc
from fract4d import animation, fractal, fractconfig
from . import dialog, hig, PNGGen, AVIGen, DlgAdvOpt, director_prefs


class UserCancelledError(Exception):
    pass


class SanityCheckError(Exception):
    "The type of exception which is thrown when animation sanity checks fail"

    def __init__(self, msg):
        Exception.__init__(self, msg)


class DirectorDialog(dialog.T, hig.MessagePopper):
    RESPONSE_RENDER = 1

    def check_for_keyframe_clash(self, keyframe, fct_dir):
        keydir = os.path.dirname(keyframe)
        if keydir[-1] != "/":
            keydir += "/"

        if fct_dir[-1] != "/":
            fct_dir += "/"
        if keydir == fct_dir:
            raise SanityCheckError(
                _("Keyframe %s is in the temporary .fct directory and could be overwritten. Please change temp directory." % keyframe))

    def check_fct_file_sanity(self):
        # things to check with fct temp dir
        if not self.animation.get_fct_enabled():
            # we're not generating .fct files, so this is superfluous
            return

        # check fct temp dir is set
        if self.animation.get_fct_dir() == "":
            raise SanityCheckError(
                _("Directory for temporary .fct files not set"))

        # check if it is directory
        if not os.path.isdir(self.animation.get_fct_dir()):
            raise SanityCheckError(
                _("Path for temporary .fct files is not a directory"))

        fct_path = self.animation.get_fct_dir()

        # heck if any keyframe fct files are in temp fct dir
        for i in range(self.animation.keyframes_count()):
            keyframe = self.animation.get_keyframe_filename(i)
            self.check_for_keyframe_clash(keyframe, fct_path)

        # check if there are any .fct files in temp fct dir
        has_any = False
        for file in os.listdir(fct_path):
            if fnmatch.fnmatch(file, "*.fct"):
                has_any = True

            if has_any is True:
                response = self.ask_question(
                    _("Directory for temporary .fct files contains other .fct files"),
                    _("These may be overwritten. Proceed?"))
                if response != Gtk.ResponseType.ACCEPT:
                    raise UserCancelledError()
            return

    # throws SanityCheckError if there was a problem
    def check_sanity(self):
        # check if at least two keyframes exist
        if self.animation.keyframes_count() < 2:
            raise SanityCheckError(_("There must be at least two keyframes"))

        # check png temp dir is set
        if self.animation.get_png_dir() == "":
            raise SanityCheckError(
                _("Directory for temporary .png files not set"))

        # check if it is directory
        if not os.path.isdir(self.animation.get_png_dir()):
            raise SanityCheckError(
                _("Path for temporary .png files is not a directory"))

        # check avi file is set
        if self.animation.get_avi_file() == "":
            raise SanityCheckError(_("Output AVI file name not set"))

        self.check_fct_file_sanity()

    # wrapper to show dialog for selecting .fct file
    # returns selected file or empty string
    def get_fct_file(self):
        temp_file = ""
        dialog = Gtk.FileChooserDialog(title="Choose keyframe...",
                                       transient_for=self,
                                       action=Gtk.FileChooserAction.OPEN)
        dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                           Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
        dialog.set_default_response(Gtk.ResponseType.OK)
        # ----setting filters---------
        filter = Gtk.FileFilter()
        filter.set_name("gnofract4d files (*.fct)")
        filter.add_pattern("*.fct")
        dialog.add_filter(filter)
        filter = Gtk.FileFilter()
        filter.set_name("All files")
        filter.add_pattern("*")
        dialog.add_filter(filter)
        # ----------------------------
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            temp_file = dialog.get_filename()
        dialog.destroy()
        return temp_file

    # wrapper to show dialog for selecting .avi file
    # returns selected file or empty string
    def get_avi_file(self):
        temp_file = ""
        dialog = Gtk.FileChooserDialog(title="Save AVI file...",
                                       transient_for=self,
                                       action=Gtk.FileChooserAction.SAVE)
        dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                           Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
        dialog.set_default_response(Gtk.ResponseType.OK)
        current_file = self.txt_temp_avi.get_text()
        dialog.set_current_name(current_file if current_file else "video.webm")
        # ----setting filters---------
        filter = Gtk.FileFilter()
        filter.set_name("webm video file (*.webm)")
        filter.add_pattern("*.webm")
        dialog.add_filter(filter)
        filter = Gtk.FileFilter()
        filter.set_name("All files")
        filter.add_pattern("*")
        dialog.add_filter(filter)
        # ----------------------------
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            temp_file = dialog.get_filename()
        dialog.destroy()
        return temp_file

    # wrapper to show dialog for selecting .cfg file
    # returns selected file or empty string
    def get_cfg_file_save(self):
        temp_file = ""
        dialog = Gtk.FileChooserDialog(title="Save animation...",
                                       transient_for=self,
                                       action=Gtk.FileChooserAction.SAVE)
        dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                           Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
        dialog.set_default_response(Gtk.ResponseType.OK)
        dialog.set_current_name("animation.fcta")
        # ----setting filters---------
        filter = Gtk.FileFilter()
        filter.set_name("gnofract4d animation files (*.fcta)")
        filter.add_pattern("*.fcta")
        dialog.add_filter(filter)
        filter = Gtk.FileFilter()
        filter.set_name("All files")
        filter.add_pattern("*")
        dialog.add_filter(filter)
        # ----------------------------
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            temp_file = dialog.get_filename()
        dialog.destroy()
        return temp_file

    # wrapper to show dialog for selecting .fct file
    # returns selected file or empty string
    def get_cfg_file_open(self):
        temp_file = ""
        dialog = Gtk.FileChooserDialog(title="Choose animation...",
                                       transient_for=self,
                                       action=Gtk.FileChooserAction.OPEN)
        dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                           Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
        dialog.set_default_response(Gtk.ResponseType.OK)
        # ----setting filters---------
        filter = Gtk.FileFilter()
        filter.set_name("gnofract4d animation files (*.fcta)")
        filter.add_pattern("*.fcta")
        dialog.add_filter(filter)
        filter = Gtk.FileFilter()
        filter.set_name("All files")
        filter.add_pattern("*")
        dialog.add_filter(filter)
        # ----------------------------
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            temp_file = dialog.get_filename()
        # elif response == Gtk.ResponseType.CANCEL:
        #    print 'Closed, no files selected'
        dialog.destroy()
        return temp_file

    def temp_avi_clicked(self, widget, data=None):
        avi = self.get_avi_file()
        if avi:
            self.txt_temp_avi.set_text(avi)

    def output_width_changed(self, widget, data=None):
        self.animation.set_width(self.spin_width.get_value())

    def output_height_changed(self, widget, data=None):
        self.animation.set_height(self.spin_height.get_value())

    def output_framerate_changed(self, widget, data=None):
        self.animation.set_framerate(self.spin_framerate.get_value())

    def duration_changed(self, widget, data=None):
        if self.current_select == -1:
            return
        self.animation.set_keyframe_duration(
            self.current_select, int(
                self.spin_duration.get_value()))
        self.update_model()

    def stop_changed(self, widget, data=None):
        if self.current_select == -1:
            return
        self.animation.set_keyframe_stop(
            self.current_select, int(
                self.spin_kf_stop.get_value()))
        self.update_model()

    def interpolation_type_changed(self, widget, data=None):
        if self.current_select == -1:
            return
        self.animation.set_keyframe_int(
            self.current_select, int(
                self.cmb_interpolation_type.get_active()))
        self.update_model()

    # point of whole program:)
    # first we generate png files and list, then .avi
    def generate(self, create_avi=True):
        try:
            self.check_sanity()
        except SanityCheckError as exn:
            self.show_error(_("Cannot Generate Animation"), str(exn))
            raise

        png_gen = PNGGen.PNGGeneration(self.animation, self.compiler, self)
        res = png_gen.show()
        if res == 1:
            # user cancelled, but they know that. Stop silently
            return
        elif res != 0:
            # unexpected return code
            return

        if not create_avi:
            return

        avi_gen = AVIGen.AVIGeneration(self.animation, self)
        res = avi_gen.show()
        if res == 1:
            # user cancelled, but they know that. Stop silently
            pass
        elif res == 0:
            # success
            self.show_info(
                _("AVI Generation Complete"),
                _("File is %s." % self.animation.get_avi_file()))

    def generate_clicked(self, widget, data=None):
        self.generate(True)

    def adv_opt_clicked(self, widget, data=None):
        if self.current_select == -1:
            return
        dlg = DlgAdvOpt.DlgAdvOptions(
            self.current_select, self.animation, self)
        dlg.show()

    # before selecting keyframes in list box we must update values of spin
    # boxes in case user typed something in there
    def before_selection(self, selection, data=None, *kwargs):
        self.spin_duration.update()
        self.spin_kf_stop.update()
        return True

    # update right box (duration, stop, interpolation type) when keyframe is
    # selected from list
    def selection_changed(self, widget, data=None):
        (model, it) = self.tv_keyframes.get_selection().get_selected()
        if it is not None:
            # ------getting index of selected row-----------
            index = 0
            it = model.get_iter_first()
            while it is not None:
                if self.tv_keyframes.get_selection().iter_is_selected(it):
                    break
                it = model.iter_next(it)
                index = index + 1
            self.current_select = index
            self.spin_duration.set_value(
                int(self.animation.get_keyframe_duration(index)))
            self.spin_kf_stop.set_value(
                self.animation.get_keyframe_stop(index))
            self.cmb_interpolation_type.set_active(
                self.animation.get_keyframe_int(index))
            return
        else:
            self.spin_duration.set_value(25)
            self.spin_kf_stop.set_value(1)
            self.cmb_interpolation_type.set_active(animation.INT_LINEAR)
            self.current_select = -1

    def update_model(self):
        (model, it) = self.tv_keyframes.get_selection().get_selected()
        if it is not None:
            # ------getting index of selected row-----------
            index = 0
            it = model.get_iter_first()
            while it is not None:
                if self.tv_keyframes.get_selection().iter_is_selected(it):
                    break
                it = model.iter_next(it)
                index = index + 1

            model.set(it, 1, self.animation.get_keyframe_duration(index))
            model.set(it, 2, self.animation.get_keyframe_stop(index))
            int_type = self.animation.get_keyframe_int(index)
            if int_type == animation.INT_LINEAR:
                model.set(it, 3, "Linear")
            elif int_type == animation.INT_LOG:
                model.set(it, 3, "Logarithmic")
            elif int_type == animation.INT_INVLOG:
                model.set(it, 3, "Inverse logarithmic")
            else:
                model.set(it, 3, "Cosine")

    def swap_redblue_clicked(self, widget, data=None):
        self.animation.set_redblue(self.chk_swapRB.get_active())

    def add_from_file(self, widget, data=None):
        file = self.get_fct_file()
        if file != "":
            self.add_keyframe(file)

    def add_from_current(self, widget, data=None):
        (tmp_fd, tmp_name) = tempfile.mkstemp(suffix='.fct')
        with os.fdopen(tmp_fd, 'w') as f:
            self.f.save(f)
        self.add_keyframe(tmp_name)
        return

    def add_keyframe(self, file):
        if file != "":
            # get current seletion
            (model, it) = self.tv_keyframes.get_selection().get_selected()
            if it is None:  # if it's none, just append at the end of the list
                it = model.append([file, 25, 1, "Linear"])
            else:  # append after currently selected
                it = model.insert_after(it, [file, 25, 1, "Linear"])

            # add to bean with default parameters
            if self.current_select != -1:
                self.animation.add_keyframe(
                    file, 25, 1, animation.INT_LINEAR, self.current_select + 1)
            else:
                self.animation.add_keyframe(file, 25, 1, animation.INT_LINEAR)
            # and select newly item
            self.tv_keyframes.get_selection().select_iter(it)
            # set default duration
            self.spin_duration.set_value(25)
            # set default stop
            self.spin_kf_stop.set_value(1)
            # set default interpolation type
            self.cmb_interpolation_type.set_active(animation.INT_LINEAR)

    def add_keyframe_clicked(self, widget, event):
        if event.type == Gdk.EventType.BUTTON_PRESS:
            widget.popup(
                None,
                None,
                None,
                None,
                event.get_button()[1],
                event.time)
            # Tell calling code that we have handled this event the buck
            # stops here.
            return True
        # Tell calling code that we have not handled this event pass it on.
        return False

    def remove_keyframe_clicked(self, widget, data=None):
        # is anything selected
        (model, it) = self.tv_keyframes.get_selection().get_selected()
        if it is not None:
            temp_curr = self.current_select
            model.remove(it)
            self.animation.remove_keyframe(temp_curr)

    def updateGUI(self):
        # keyframes
        (model, it) = self.tv_keyframes.get_selection().get_selected()
        model.clear()
        for i in range(self.animation.keyframes_count() - 1, -1, -1):
            filename = self.animation.get_keyframe_filename(i)
            duration = self.animation.get_keyframe_duration(i)
            stopped = self.animation.get_keyframe_stop(i)
            it = model.insert(0, [filename, duration, stopped, ""])
            int_type = self.animation.get_keyframe_int(i)
            if int_type == animation.INT_LINEAR:
                model.set(it, 3, "Linear")
            elif int_type == animation.INT_LOG:
                model.set(it, 3, "Logarithmic")
            elif int_type == animation.INT_INVLOG:
                model.set(it, 3, "Inverse logarithmic")
            else:
                model.set(it, 3, "Cosine")
        # output part
        self.txt_temp_avi.set_text(self.animation.get_avi_file())
        self.spin_width.set_value(self.animation.get_width())
        self.spin_height.set_value(self.animation.get_height())
        self.spin_framerate.set_value(self.animation.get_framerate())
        self.chk_swapRB.set_active(self.animation.get_redblue())

    # loads configuration file, returns 0 on ok, -1 on error (and displays
    # error message)
    def load_configuration(self, file):
        if file == "":
            return -1
        try:
            self.animation.load_animation(file)
        except Exception as err:
            self.show_error(
                _("Cannot load animation"),
                str(err))
            return -1
        # set GUI to reflect changes
        self.updateGUI()
        return 0

    # loads configuration from pickled file
    def load_configuration_clicked(self, widget, data=None):
        cfg = self.get_cfg_file_open()
        if cfg != "":
            self.load_configuration(cfg)

    # reset all field to defaults
    def new_configuration_clicked(self, widget, data=None):
        self.animation.reset()
        self.updateGUI()

    # save configuration in file
    def save_configuration_clicked(self, widget, data=None):
        cfg = self.get_cfg_file_save()
        if cfg != "":
            try:
                self.animation.save_animation(cfg)
            except Exception as err:
                self.show_error(
                    _("Error saving animation"),
                    str(err))

    def preferences_clicked(self, widget, data=None):
        dlg = director_prefs.DirectorPrefs(self.animation, self)
        dlg.show()

    # creating window...
    def __init__(self, main_window, f, userConfig, conf_file=""):
        #pylint: disable=no-member
        dialog.T.__init__(
            self,
            _("Director"),
            main_window,
            (_("_Render"), DirectorDialog.RESPONSE_RENDER,
             Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
        )

        hig.MessagePopper.__init__(self)
        self.animation = animation.T(f.compiler, userConfig)
        self.f = f
        self.compiler = f.compiler

        # main VBox
        self.box_main = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        self.box_main.set_homogeneous(False)
        # --------------------menu-------------------------------
        self.manager = Gtk.UIManager()
        accelgroup = self.manager.get_accel_group()
        self.add_accel_group(accelgroup)

        actiongroup = Gtk.ActionGroup.new("Director")
        actiongroup.add_actions([
            ('DirectorMenuAction', None, _('_Director')),
            ('DirectorEditAction', None, _('_Edit')),

            ('DirectorNewAction', Gtk.STOCK_NEW, _('_New Animation'),
             '<control>N', None, self.new_configuration_clicked),
            ('DirectorOpenAction', Gtk.STOCK_OPEN, _('_Open Animation'),
             '<control>O', None, self.load_configuration_clicked),
            ('DirectorSaveAction', Gtk.STOCK_SAVE, _('_Save Animation'),
             '<control>S', None, self.save_configuration_clicked),
            ('DirectorEditPrefsAction', Gtk.STOCK_PREFERENCES, _('_Preferences'),
             '<control>P', None, self.preferences_clicked),
        ])

        self.manager.insert_action_group(actiongroup, 0)

        menu = '''
<ui>
<menubar>
<menu name="Director" action="DirectorMenuAction">
    <menuitem action="DirectorNewAction"/>
    <menuitem action="DirectorOpenAction"/>
    <menuitem action="DirectorSaveAction"/>
</menu>
<menu name="Edit" action="DirectorEditAction">
    <menuitem action="DirectorEditPrefsAction"/>
</menu>
</menubar>
</ui>
'''
        self.manager.add_ui_from_string(menu)

        self.menubar = self.manager.get_widget('/menubar')
        self.box_main.pack_start(self.menubar, False, True, 0)

        # -----------creating popup menu-------------------------------
        # popup menu for keyframes
        self.popup_menu = Gtk.Menu()
        self.mnu_pop_add_file = Gtk.MenuItem.new_with_label("From file")
        self.popup_menu.append(self.mnu_pop_add_file)
        self.mnu_pop_add_file.connect("activate", self.add_from_file, None)
        self.mnu_pop_add_file.show()
        self.mnu_pop_add_current = Gtk.MenuItem.new_with_label(
            "From current fractal")
        self.popup_menu.append(self.mnu_pop_add_current)
        self.mnu_pop_add_current.connect(
            "activate", self.add_from_current, None)
        self.mnu_pop_add_current.show()

        # --------------Keyframes box-----------------------------------
        self.frm_kf = Gtk.Frame.new("Keyframes")
        self.frm_kf.set_border_width(10)
        vbox_kfs = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8)
        button_box_kfs = Gtk.ButtonBox()
        button_box_kfs.set_layout(Gtk.ButtonBoxStyle.SPREAD)
        self.sw = Gtk.ScrolledWindow()
        self.sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.sw.set_size_request(-1, 100)
#        filenames=Gtk.ListStore(GObject.TYPE_STRING,
#            GObject.TYPE_STRING)
#        self.tv_keyframes=Gtk.TreeView(filenames)
#        self.tv_column_name = Gtk.TreeViewColumn('Keyframes')
#        self.tv_keyframes.append_column(self.tv_column_name)
#        self.tv_column_duration = Gtk.TreeViewColumn('Duration')
#        self.tv_keyframes.append_column(self.tv_column_duration)
#        self.cell_name = Gtk.CellRendererText()
#        self.tv_column_name.pack_start(self.cell_name, True)
#        self.tv_column_name.add_attribute(self.cell_name, 'text', 0)
#        self.cell_duration = Gtk.CellRendererText()
#        self.tv_column_name.pack_start(self.cell_duration, True)
#        self.tv_column_name.add_attribute(self.cell_duration, 'text', 0)
        filenames = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_UINT,
                                  GObject.TYPE_UINT, GObject.TYPE_STRING)
        self.tv_keyframes = Gtk.TreeView()
        self.tv_keyframes.set_model(filenames)
        column = Gtk.TreeViewColumn(
            'Keyframes', Gtk.CellRendererText(), text=0)
        self.tv_keyframes.append_column(column)

        column = Gtk.TreeViewColumn(
            'Stopped for', Gtk.CellRendererText(), text=2)
        self.tv_keyframes.append_column(column)

        column = Gtk.TreeViewColumn(
            'Transition duration',
            Gtk.CellRendererText(),
            text=1)
        self.tv_keyframes.append_column(column)

        column = Gtk.TreeViewColumn(
            'Interpolation type',
            Gtk.CellRendererText(),
            text=3)
        self.tv_keyframes.append_column(column)

        self.sw.add(self.tv_keyframes)
        self.tv_keyframes.get_selection().connect(
            "changed", self.selection_changed, None)
        self.tv_keyframes.get_selection().set_select_function(self.before_selection, None)
        self.current_select = -1

        self.btn_add_keyframe = Gtk.Button.new_with_label("Add")
        # self.btn_add_keyframe.connect("clicked",self.add_keyframe_clicked,None)
        self.btn_add_keyframe.connect_object(
            "event", self.add_keyframe_clicked, self.popup_menu)

        self.btn_remove_keyframe = Gtk.Button.new_with_label("Remove")
        self.btn_remove_keyframe.connect(
            "clicked", self.remove_keyframe_clicked, None)

        button_box_kfs.pack_start(self.btn_add_keyframe, True, True, 0)
        button_box_kfs.pack_start(self.btn_remove_keyframe, True, True, 0)

        vbox_kfs.pack_start(self.sw, True, True, 0)
        vbox_kfs.pack_start(button_box_kfs, True, True, 10)

        self.frm_kf.add(vbox_kfs)
        self.box_main.pack_start(self.frm_kf, True, True, 0)

        # current keyframe box
        self.current_kf = Gtk.Frame.new("Current Keyframe")
        self.current_kf.set_border_width(10)

        self.box_main.pack_start(self.current_kf, True, True, 0)

        self.tbl_keyframes_right = Gtk.Grid()
        self.tbl_keyframes_right.set_column_homogeneous(True)
        self.tbl_keyframes_right.set_row_homogeneous(True)
        self.tbl_keyframes_right.set_row_spacing(10)
        self.tbl_keyframes_right.set_column_spacing(10)
        self.tbl_keyframes_right.set_border_width(10)

        self.lbl_kf_stop = Gtk.Label(label="Keyframe stopped for:")
        self.tbl_keyframes_right.attach(self.lbl_kf_stop, 0, 0, 1, 1)

        adj_kf_stop = Gtk.Adjustment.new(1, 1, 10000, 1, 10, 0)
        self.spin_kf_stop = Gtk.SpinButton()
        self.spin_kf_stop.set_adjustment(adj_kf_stop)
        self.spin_kf_stop.connect("output", self.stop_changed, None)
        self.tbl_keyframes_right.attach(self.spin_kf_stop, 1, 0, 1, 1)

        self.lbl_duration = Gtk.Label(label="Transition duration:")
        self.tbl_keyframes_right.attach(self.lbl_duration, 0, 1, 1, 1)

        adj_duration = Gtk.Adjustment.new(25, 1, 10000, 1, 10, 0)
        self.spin_duration = Gtk.SpinButton()
        self.spin_duration.set_adjustment(adj_duration)
        self.spin_duration.connect("output", self.duration_changed, None)
        self.tbl_keyframes_right.attach(self.spin_duration, 1, 1, 1, 1)

        self.lbl_int_type = Gtk.Label(label="Interpolation type:")
        self.tbl_keyframes_right.attach(self.lbl_int_type, 0, 2, 1, 1)

        self.cmb_interpolation_type = Gtk.ComboBoxText()  # Gtk.ComboBox()
        self.cmb_interpolation_type.append_text("Linear")
        self.cmb_interpolation_type.append_text("Logarithmic")
        self.cmb_interpolation_type.append_text("Inverse logarithmic")
        self.cmb_interpolation_type.append_text("Cosine")
        self.cmb_interpolation_type.set_active(0)
        self.cmb_interpolation_type.connect(
            "changed", self.interpolation_type_changed, None)
        self.tbl_keyframes_right.attach(
            self.cmb_interpolation_type, 1, 2, 1, 1)

        self.btn_adv_opt = Gtk.Button(label="Advanced options")
        self.btn_adv_opt.connect("clicked", self.adv_opt_clicked, None)
        self.tbl_keyframes_right.attach(self.btn_adv_opt, 0, 3, 2, 1)

        self.current_kf.add(self.tbl_keyframes_right)
        # -------------------------------------------------------------------
        # ----------------------output box-----------------------------------
        self.frm_output = Gtk.Frame.new("Output options")
        self.frm_output.set_border_width(10)

        self.box_output_main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
                                       homogeneous=True, spacing=10)
        self.box_output_main.set_border_width(10)
        self.box_output_file = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
                                       homogeneous=False, spacing=10)

        self.lbl_temp_avi = Gtk.Label(label="Resulting video file:")
        self.box_output_file.pack_start(self.lbl_temp_avi, False, False, 10)

        self.txt_temp_avi = Gtk.Entry()
        self.box_output_file.pack_start(self.txt_temp_avi, True, True, 10)

        self.btn_temp_avi = Gtk.Button(label="Browse")
        self.btn_temp_avi.connect("clicked", self.temp_avi_clicked, None)
        self.box_output_file.pack_start(self.btn_temp_avi, True, True, 10)

        self.box_output_main.pack_start(self.box_output_file, True, True, 0)

        self.box_output_res = Gtk.HBox(homogeneous=False, spacing=10)

        self.lbl_res = Gtk.Label(label="Resolution:")
        self.box_output_res.pack_start(self.lbl_res, False, False, 10)

        adj_width = Gtk.Adjustment.new(640, 320, 2048, 10, 100, 0)
        self.spin_width = Gtk.SpinButton()
        self.spin_width.set_adjustment(adj_width)
        self.box_output_res.pack_start(self.spin_width, False, False, 10)

        self.lbl_x = Gtk.Label(label="x")
        self.box_output_res.pack_start(self.lbl_x, False, False, 10)

        adj_height = Gtk.Adjustment.new(480, 240, 1536, 10, 100, 0)
        self.spin_height = Gtk.SpinButton()
        self.spin_height.set_adjustment(adj_height)
        self.box_output_res.pack_start(self.spin_height, False, False, 10)

        self.box_output_main.pack_start(self.box_output_res, True, True, 0)

        self.box_output_framerate = Gtk.HBox(homogeneous=False, spacing=10)

        self.lbl_framerate = Gtk.Label(label="Frame rate:")
        self.box_output_framerate.pack_start(
            self.lbl_framerate, False, False, 10)

        adj_framerate = Gtk.Adjustment.new(25, 5, 100, 1, 5, 0)
        self.spin_framerate = Gtk.SpinButton()
        self.spin_framerate.set_adjustment(adj_framerate)
        self.box_output_framerate.pack_start(
            self.spin_framerate, False, False, 10)

        self.chk_swapRB = Gtk.CheckButton(label="Swap red and blue component")
        self.box_output_framerate.pack_start(self.chk_swapRB, False, False, 50)

        self.box_output_main.pack_start(
            self.box_output_framerate, True, True, 0)

        self.frm_output.add(self.box_output_main)
        self.box_main.pack_start(self.frm_output, False, False, 0)

        # check if video converter can be found
        self.converterpath = fractconfig.T.find_on_path("ffmpeg")
        if not self.converterpath:
            # put a message at the bottom to warn user
            warning_box = Gtk.HBox()
            image = Gtk.Image.new_from_icon_name(
                "dialog-warning", Gtk.IconSize.BUTTON)

            warning_box.pack_start(image, True, True, 0)

            message = Gtk.Label(label=_(
                "ffmpeg utility not found. Without it we can't generate any video but can still save sequences of still images."))

            message.set_line_wrap(True)
            warning_box.pack_start(message, True, True, 0)
            self.box_main.pack_end(warning_box, True, True, 0)

        # initialise default settings
        if conf_file:
            self.load_configuration(conf_file)
        else:
            self.updateGUI()

        # don't connect signals until after settings initialised
        self.spin_height.connect(
            "value-changed",
            self.output_height_changed,
            None)
        self.spin_width.connect(
            "value-changed",
            self.output_width_changed,
            None)
        self.spin_framerate.connect(
            "value-changed", self.output_framerate_changed, None)
        self.chk_swapRB.connect("toggled", self.swap_redblue_clicked, None)

        # --------------showing all-------------------------------
        self.vbox.add(self.box_main)
        self.vbox.show_all()

    def onResponse(self, widget, id):
        if id == Gtk.ResponseType.CLOSE or \
                id == Gtk.ResponseType.NONE or \
                id == Gtk.ResponseType.DELETE_EVENT:
            self.hide()
        elif id == DirectorDialog.RESPONSE_RENDER:
            self.animation.set_avi_file(self.txt_temp_avi.get_text())
            try:
                self.generate(self.converterpath is not None)
            except (SanityCheckError, UserCancelledError):
                # prevent dialog closing if being run
                GObject.signal_stop_emission_by_name(self, "response")
            else:
                self.hide()

    def main(self):
        Gtk.main()


if __name__ == "__main__":
    GObject.threads_init()
    Gtk.threads_init()

    main_window = Gtk.Window()
    userConfig = fractconfig.userConfig()
    compiler = fc.Compiler(userConfig)
    f = fractal.T(compiler)
    fracwin = DirectorDialog(main_window, f, userConfig)

    fracwin.main()
