EXPAND_BOTH = evas.EVAS_HINT_EXPAND, evas.EVAS_HINT_EXPAND
EXPAND_HORIZ = evas.EVAS_HINT_EXPAND, 0.0
FILL_BOTH = evas.EVAS_HINT_FILL, evas.EVAS_HINT_FILL
FILL_HORIZ = evas.EVAS_HINT_FILL, 0.5
MESSAGE_CLOCK_TIME = 12
MESSAGE_CLOCK_DATE = 13
DMAN_QUEUED = 0
DMAN_RUNNING = 1
DMAN_COMPLETED = 2
DMAN_ABORTED = 3
DMAN_PAUSED = 4
def LOG(msg):
def DBG(msg):
def DBG_FOCUS(*args):
def init():
    def _volume_slider_changed_cb(slider):
    def _mute_toggle_signal_cb(a, s, d):
def shutdown():
def get_theme_info(theme):
def set_theme_file(path):
def load_icon(icon: str):
def load_image(name, path=None):
def ask_to_exit():
def exit_now():
def volume_show(hidein=0, persistent=False):
def volume_hide():
def volume_set(value):
def scale_set(scale):
def scale_get():
def scale_bigger():
def scale_smaller():
def scale_reset():
def background_set(image):
def fps_set(fps):
def fullscreen_get():
def fullscreen_set(full):
def fullscreen_toggle():
def win_raise():
def clock_update():
def mouse_show():
def mouse_hide():
def part_get(name):
def signal_emit(sig, src='emc'):
def signal_cb_add(emission, source, cb):
def signal_cb_del(emission, source, cb):
def text_set(part, text):
def swallow_set(part, obj, delete_old=True):
def box_append(part, obj):
def box_prepend(part, obj):
def box_remove(part, obj):
def box_remove_all(part, clear=True):
def _on_key_down(event):
def focus_move(direction):
def _input_event_cb(event):
def _event_cb(event):
    def __init__(self, parent, focus_allow=True, is_focus_manager=False,
                 focus_history_allow=True):
    def __repr__(self):
    def _delete_cb(self, obj):
    def callback_focused_add(self, cb, *args, **kargs):
    def callback_unfocused_add(self, cb, *args, **kargs):
    def _callbacks_call(self, cb_list):
    def _get_children_recursive(obj, focusable_only, L):
    def focusable_children(self):
    def children(self):
    def focus_allow(self):
    def focus_allow(self, allow):
    def focus_history_allow(self):
    def focus_history_allow(self, allow):
    def focus_history_remove(self):
    def tree_focus_allow(self):
    def tree_focus_allow(self, allow):
    def focus(self):
    def focus(self, focus):
    def _delayed_history_pop():
    def focused_object(self):
    def focused_child(self):
    def is_focus_manager(self):
    def parent_manager(self):
    def dump_focus_tree(self, level=0):
    def focused_geometry(self):
    def focus_move(self, direction):
    def __init__(self, parent,
                 select_on_focus=True,
                 focus_on_select=True,
                 **kargs):
    def focused_item(self):
    def focused_item(self, item):
    def focused_geometry(self):
    def clear(self):
    def _focused_cb(self, obj):
    def _unfocused_cb(self, obj):
    def _item_selected_cb(self, obj, item):
    def _item_realized_cb(self, obj, item):
    def __init__(self, *args, **kargs):
    def focus_move_internal(self, direction):
    def __init__(self, parent, focus_allow=False, is_focus_manager=False,
                 focus_history_allow=True, **kargs):
    def focus_move_internal(self, direction):
    def __init__(self, parent,
                 focus_allow=True,
                 select_on_focus=True,
                 focus_on_select=True,
                 **kargs):
    def focus_move_internal(self, direction):
    def __init__(self, parent,
                 focus_allow=True,
                 select_on_focus=True,
                 focus_on_select=True,
                 **kargs):
    def focus_move_internal(self, direction):
    def __init__(self, parent,
                 focus_allow=True,
                 select_on_focus=True,
                 focus_on_select=True,
                 **kargs):
    def focus_move_internal(self, direction):
    def __init__(self, parent, label=None, icon=None, cb=None, cb_data=None,
                 toggle=False, focus_allow=True, **kargs):
    def icon_set(self, icon):
    def toggled(self):
    def toggled(self, toggled):
    def activate(self, obj=None):
    def __init__(self, parent, focus_allow=True, **kargs):
    def focus_move_internal(self, direction):
    def __init__(self, parent, focus_allow=True, **kargs):
    def _focused_cb(self, obj):
    def _unfocused_cb(self, obj):
    def __init__(self, relto=None, dismiss_on_select=True):
    def show(self):
    def close(self):
    def item_add(self, label=None, icon=None, end=None, callback=None, *args, **kargs):
    def item_separator_add(self):
    def item_icon_set(item, icon):
    def item_icon_end_set(item, icon):
    def _dismissed_cb(self, obj):
    def _item_activated_cb(self, obj, item):
    def _mouse_move_cb(self, obj, event):
    def _mouse_click_cb(self, obj, event):
    def focus_move_internal(self, direction):
    def _input_event_cb(self, event):
    def __init__(self, url=None, dest=None, icon=None, label2=None,
                 aspect_fixed=True, fill_outside=False, thumb=False):
    def url_set(self, url, dest=None, icon=None, label2=None, thumb=False):
    def cache_path_get(self, url):
    def _thumb_complete_cb(self, status, file, thumb):
    def _start_download(self, url, dest):
    def _download_complete_cb(dest_tmp, status):
    def _del_cb(self, obj):
    def __init__(self, title=None, text=None, content=None, spinner=False,
                 style='panel', done_cb=None, canc_cb=None, user_data=None):
    def activate():
    def delete(self):
    def _delete_real(self):
    def _close_pressed(self, a, s, d):
    def content_get(self):
    def data_get(self):
    def button_add(self, label, selected_cb=None, cb_data=None, icon=None, default=False):
    def buttons_clear(self):
    def title_set(self, text):
    def title_get(self):
    def text_set(self, text):
    def text_get(self):
    def text_append(self, text):
    def list_item_append(self, label, icon=None, end=None, *args, **kwargs):
    def list_go(self):
    def list_clear(self):
    def list_item_selected_get(self):
    def list_item_icon_set(it, icon, end=False):
    def _list_item_activated_cb(self, li, it):
    def spinner_start(self):
    def spinner_stop(self):
    def progress_set(self, val):
    def autoscroll_enable(self, speed_scale=1.0, start_delay=3.0):
    def focus_move_internal(self, direction):
    def _input_event_cb(self, event):
    def __init__(self, text, icon='icon/star', hidein=5.0, close_cb=None):
    def hidein(self, hidein):
    def _hide_timer_cb(self):
    def close(self):
    def text_set(self, text):
    def __init__(self, url, delay=4, show_controls=False, on_del=None):
    def delete(self):
    def _delete_real(self):
    def pause(self):
    def unpause(self):
    def pause_toggle(self):
    def controls_show(self):
    def controls_hide(self):
    def controls_toggle(self):
    def _click_signal_cb(self, obj, signal, src):
    def _show_done_signal_cb(self, obj, signal, src):
    def _hide_done_signal_cb(self, obj, signal, src):
    def _photo_changed_cb(self, obj, item):
    def _populate(self):
    def _item_get_func(self, obj, item_data):
    def _item_del_func(obj, item_data):
    def _input_event_cb(self, event):
    def __init__(self, title=_('Source Selector'), done_cb=None, **kargs):
    def populate_devices(self):
    def populate_folder(self, root, folder):
    def _btn_browse_cb(self, btn):
    def _btn_select_cb(self, btn):
    def __init__(self, conf_group, title=_('Sources Manager'), done_cb=None):
    def _populate(self):
    def _cb_btn_add(self, btn):
    def _cb_btn_remove(self, btn):
    def _cb_selected(self, path):
    def _cb_btn_done(self, btn):
    def __init__(self, tags_db, done_cb=None):
    def _populate(self):
    def _close_cb(self, *args):
    def _btn_add_cb(self, btn):
    def _add_vkeyb_cb(self, vkeyb, text):
    def _btn_remove_cb(self, btn):
    def _remove_confirmed_cb(self, dia):
    def _btn_rename_cb(self, obj):
    def _rename_vkeyb_cb(self, vkeyb, text):
    def __init__(self, accept_cb=None, dismiss_cb=None,
                 title=None, text=None, user_data=None):
    def _pack_btn(self, x, y, w, h, label, icon=None, cb=None):
    def delete(self):
    def text_set(self, text):
    def _dismiss_cb(self, button):
    def _accept_cb(self, button):
    def _default_btn_cb(self, button):
    def _erase_cb(self, button):
    def _space_cb(self, button):
    def _uppercase_cb(self, button):
    def _apply_layout(self, layout):
    def _change_layout_cb(self, button):
    def input_event_cb(self, event):
    def __init__(self, parent=None, autoscroll=False, **kargs):
    def autoscroll(self):
    def autoscroll(self, value):
    def autoscroll_speed_scale(self):
    def autoscroll_speed_scale(self, value):
    def autoscroll_start_delay(self):
    def autoscroll_start_delay(self, value):
    def text_set(self, text):
    def scroll_by(self, sx=0, sy=0, animated=True):
    def delete(self):
    def _autoscroll_start(self):
    def _autoscroll_stop(self):
    def _delayed_start(self):
    def _animator_cb(self):
    def __init__(self, manager, url, dest):
    def start(self):
    def abort(self):
    def _progress_cb(self, dest, dltotal, dlnow):
    def _complete_cb(self, dest, status):
    def __init__(self):
    def queue_download(self, url, dest_name=None, dest_ext=None, dest_folder=None):
    def _update_dialog_text(dia):
    def _change_name_cb(self, bt, dia):
    def _change_name_done_cb(self, vkeyb, text, dia):
    def _change_folder_cb(self, bt, dia):
    def _change_folder_done_cb(self, folder, dia):
    def _start_cb(self, bt, dia):
    def _process_queue(self):
    def in_progress_show(self):
    def in_progress_hide(self, *args):
    def _gl_text_get(obj, part, item):
    def _dia_update_timer_cb(gl):
    def _dia_start_cb(self, btn):
    def _dia_cancel_cb(self, btn):
    def _dia_cancel_confirmed_cb(self, dia):
    def _dia_clear_cb(self, btn):
class _EmcFocusable(object):
class _EmcFocusableWithItems(_EmcFocusable):
class EmcWindow(_EmcFocusable, elm.Window):
class EmcLayout(_EmcFocusable, elm.Layout):
class EmcList(_EmcFocusableWithItems, elm.List, elm.Scrollable):
class EmcGenlist(_EmcFocusableWithItems, elm.Genlist):
class EmcGengrid(_EmcFocusableWithItems, elm.Gengrid):
class EmcButton(_EmcFocusable, elm.Button):
class EmcSlider(_EmcFocusable, elm.Slider):
class EmcTextEntry(_EmcFocusable, elm.Entry):
class EmcMenu(_EmcFocusable, elm.Ctxpopup):
class EmcImage(elm.Image):
class EmcDialog(EmcLayout):
class EmcNotify(edje.Edje):
class EmcSlideshow(elm.Slideshow):
class EmcFolderSelector(EmcDialog):
class EmcSourcesManager(EmcDialog):
class EmcTagsManager(EmcDialog):
class EmcVKeyboard(EmcDialog):
class EmcScrolledEntry(elm.Entry, elm.Scrollable):
class DManItem(object):
class DownloadManager(utils.Singleton): def init():
def show():
def hide():
def item_add(name, weight, label, icon, callback, subitems=None):
def _cb_item_selected(li, item):
def _cb_item_activated(li, item):
def item_activate(name):
def item_del(name):
def input_event_cb(event): def read_from_files(files):
def write_to_file(file):
def setup_defaults():
def add_section(section):
def has_section(section):
def has_option(section, option):
def has_options(options):
def get_options(section):
def get(section, option, default_value=None):
def get_string_list(section, option, separator=' '):
def get_int(section, option):
def get_float(section, option):
def get_bool(section, option):
def get_string(section, option):
def set(section, option, value):
def set_string_list(section, option, values, separator=' '):
def remove_option(section, option): def LOG(msg):
    def __init__(self):
    def __shutdown__(self):
    def __restart__(self):
def load_all():
    def _scan_folder(path):
def get_module_by_name(name):
def list_get():
def is_enabled(name):
def init_by_name(name):
def init_all():
def init_all_by_config():
def save_enabled():
def shutdown_by_name(name):
def shutdown_all():
DEFAULT_MODS = 'calibrator input_keyb onlinevideo movies music ' \
               'tvshows screensaver photos opticals'
class EmcModule(object):     XDG_CONFIG_HOME = ''
    XDG_CACHE_HOME = ''
def LOG(*args):
def DBG(msg):
def iso639_1_to_3(iso1):
def iso639_1_to_5(iso1):
def is_py3():
def is_py2():
def get_resource_file(res_type, res_name, default=None):
def get_available_themes():
def in_use_theme_file_set(theme_file):
def url2path(url):
def hum_size(bites):
def seconds_to_duration(seconds, hours=False):
def splitpath(path):
def ensure_file_not_exists(fullpath):
def md5(txt):
def user_name():
def natural_sort(li):
def natural_cmp(a, b):
def grab_files(folders, show_hidden=False, recursive=True):
def download_url_async(url, dest='tmp', min_size=0,
                       complete_cb=None, progress_cb=None,
                       urlencode=True, *args, **kargs):
    def _cb_download_complete(dest, status, dwl_data, *args, **kargs):
    def _cb_download_progress(dest, dltotal, dlnow, uptotal, upnow, dwl_data, *args, **kargs):
def download_abort(dwl_handler):
def http_error_code_to_str(code):
def distance_between_point_and_segment(point, segment_p1, segment_p2, real=False):
    def __new__(cls, *args, **kwargs):
    def __init__(self, cmd, grab_output=False, done_cb=None, *args, **kargs):
    def data_cb(self, exe, event):
    def del_cb(self, exe, event):
    def __init__(self, url, done_cb=None, prog_cb=None, headers=None, **kargs):
    def _complete_cb(self, event):
    def _data_cb(self, event):
class Singleton(object):
class EmcExec(object):
class EmcUrl(ecore_con.Url): class EmcBrowser(object):
    """
    This is the browser object, it is used to show various page each containing
    a list. Usually you need a single instance of this class for all your needs.
    In order you have to:
     1. implement at least one class that inherit from EmcItemClass
     2. create an instance of EmcBrowser
     3. add a page to the browser using the page_add() method
     4. add items to the current page using item_add(MyItemClass(), url, user_data)
    Later you can create new pages or use back(), clear(), show(), hide()
    """

    def __init__(self, name, default_style='List', icon='icon/home'):
        DBG('EmcBrowser __init__')
        _instances.append(self)
        self.name = name
        self.default_style = default_style
        self.icon = icon

        self.pages = []
        self.current_view = None
        self.autoselect_url = None
        self._freezed = False

    def __str__(self):
        text = '=' * 70 + '\n'
        text += '===  %s  %s\n' % (self.name, '=' * (63 - len(self.name)))
        text += '== name: %s  pages: %d curview: %s\n' % \
                (self.name, len(self.pages), self.current_view)
        for p in self.pages:
            text += '== page: ' + str(p) + '\n'
        text += '=' * 70 + '\n'
        # for s in _style_memory:
        #    text += 'style mem: %s  style: %s\n' % (s, _style_memory[s])
        # text += '*' * 70 + '\n'
        return text

    def delete(self):
        _instances.remove(self)
        del self

    def _search_style_in_parent(self):
        for p in reversed(self.pages):
            if _memorydb.id_exists(p['url']):
                return _memorydb.get_data(p['url'])
        return None

    def page_add(self, url, title, styles, populate_cb, *args, **kwargs):
        """
        When you create a page you need to give at least the url, the title
        and the populate callback. Every other arguments will be passed back
        in the callback. style can be None to use the default page style,
        usually the plain list.

        Args:
           url: A unique string id for the page
           title: Readable text for the user
           styles: A tuple with all the style that the page can show.
                   Available styles: 'List', 'PosterGrid', 'CoverGrid'
                   If set to None it default to the default style given at
                   the Browser instance creation.
                   The first item is the default one.
           populate_cb: Function to call when the page need to be populated.
                        Signature: func(browser, url, *args, **kwargs)
        """

        # choose the style of the new page
        if styles is None:
            styles = (self.default_style,)
        if _memorydb.id_exists(url):
            style = _memorydb.get_data(url)
        else:
            style = self._search_style_in_parent()
        if not style:
            style = styles[0]
        if ini.get_bool('general', 'ignore_views_restrictions') is False:
            if style not in styles:
                style = styles[0]

        # get the correct view instance
        view = self._create_or_get_view(style)

        # append the new page in the pages list
        page = {'view': view, 'url': url, 'title': title, 'styles': styles,
                'cb': populate_cb, 'args': args, 'kwargs': kwargs}
        self.pages.append(page)

        # first time, we don't have a current_view, set it
        if not self.current_view:
            self.current_view = view

        # switch to the new page
        self._populate_page(page)

    def item_add(self, item_class, url, user_data=None):
        """
        Use this method to add an item in the current (last added) page
        Url should be (but its not mandatory) a full correct url in the form:
        file:///home/user/some/dir, it MUST be unique in all the browser
        and MUST not contain any strange chars.
        """
        self.current_view.item_add(item_class, url, user_data,
                                   True if (url and url == self.autoselect_url) else False)

    def group_add(self, label, icon=None):
        """ TODO DOC """
        self.current_view.group_add(label, icon)

    def back(self):
        """ TODO Function doc """
        # discard current page
        old_page = self.pages.pop()
        self.autoselect_url = old_page['url']
        del old_page

        # no more page to go back, hide the view and return to main menu
        if len(self.pages) == 0:
            self.hide()
            mainmenu.show()
            return

        # switch to the previous page
        page_data = self.pages[-1]
        self._populate_page(page_data, is_back=True)

    def refresh(self, hard=False):
        if self.pages and self.current_view:
            if hard:
                # try to keep the selected item selected
                self.autoselect_url = self.current_view.selected_url_get()
                # re-create the page
                self._populate_page(self.pages[-1], is_refresh=True)
            else:
                self.current_view.refresh()

    def change_style(self, style):
        # the current page is always the last one
        page = self.pages[-1]

        # check if the style is valid (unless not explicitly ignored)
        if ini.get_bool('general', 'ignore_views_restrictions') is False:
            if style not in page['styles']:
                DBG('Style %s not available for this page' % style)
                EmcDialog(style='info', title=_('View restriction'),
                          text=_('<br><br>The requested view is not enabled for the current '
                                 'page.<br><br><small><info>NOTE: You can ovveride this '
                                 'restriction in the <i>Configuration → Views</i> '
                                 'section.</info></small>'))
                return

        # change only if needed
        view = self._create_or_get_view(style)
        if view == self.current_view:
            return

        # remember the selected item
        self.autoselect_url = self.current_view.selected_url_get()

        # clear & hide the current view
        self.current_view.clear()
        self.current_view.hide()

        # set the new view in the current (always the last) page
        page['view'] = view

        # remember the user choice
        global _memorydb
        page_url = self.pages[-1]['url']
        _memorydb.set_data(page_url, style)

        # recreate the page
        self.refresh(hard=True)

    def clear(self):
        """ TODO Function doc """
        self.current_view = None
        self.autoselect_url = None
        self._freezed = False
        self.pages = []

    def show(self):
        """ TODO Function doc """
        gui.signal_emit('topbar,show')
        gui.swallow_set('topbar.icon', EmcImage(self.icon))
        self.current_view.show()
        input_events.listener_add('browser-' + self.name, self._input_event_cb)
        for b in _topbar_btns:
            b.focus_allow = True

    def hide(self):
        """ TODO Function doc """
        gui.signal_emit('topbar,hide')
        input_events.listener_del('browser-' + self.name)
        self.current_view.hide()
        for b in _topbar_btns:
            b.focus_allow = False

    @property
    def freezed(self):
        """ TODO Function doc """
        return self._freezed

    def freeze(self):
        """ TODO Function doc """
        self.autoselect_url = self.current_view.selected_url_get()
        self.hide()
        mainmenu.show()
        self._freezed = True

    def unfreeze(self):
        """ TODO Function doc """
        mainmenu.hide()
        self._populate_page(self.pages[-1], is_unfreeze=True)
        self.show()
        self._freezed = False

    def item_bring_in(self, pos='top', animated=True):
        """ Move the view so that the currently selected item will go on 'pos'
        pos can be: 'in', ', top', 'mid'
        """
        self.current_view.item_bring_in(pos, animated)

    # private stuff
    def _populate_page(self, page, is_back=False, is_refresh=False, is_unfreeze=False):
        full = ' > '.join([p['title'] for p in self.pages])
        gui.text_set('topbar.title', full)

        view = page['view']
        if view == self.current_view:
            # same style for the 2 pages, ask the view to perform the correct anim
            if is_refresh or is_unfreeze:
                view.page_show(page['title'], ANIM_NONE)
            elif is_back:
                view.page_show(page['title'], ANIM_BACK)
            elif len(self.pages) < 2:
                view.page_show(page['title'], ANIM_NONE)
            else:
                view.page_show(page['title'], ANIM_FORWARD)
        else:
            # different style...hide one view and show the other
            self.current_view.clear()
            self.current_view.hide()
            view.page_show(page['title'], ANIM_NONE)
            view.show()

        # update state
        self.current_view = view

        # back item (optional)
        if ini.get_bool('general', 'back_in_lists') is True:
            self.item_add(BackItemClass(), 'emc://back', self)
            view.items_count -= 1

        # use this for extra debug
        # print(self)

        # and finally populate the page
        url = page['url']
        cb = page['cb']
        args = page['args']
        kwargs = page['kwargs']
        cb(self, url, *args, **kwargs)

    def _input_event_cb(self, event):
        # pass the event to the view
        view_ret = self.current_view.input_event_cb(event)
        if view_ret == input_events.EVENT_BLOCK:
            return input_events.EVENT_BLOCK

        # always
        if event == 'BACK':
            self.back()
            return input_events.EVENT_BLOCK
        if event == 'EXIT':
            self.freeze()
            return input_events.EVENT_BLOCK
        elif event == 'VIEW_LIST':
            self.change_style('List')
            return input_events.EVENT_BLOCK
        elif event == 'VIEW_POSTERGRID':
            self.change_style('PosterGrid')
            return input_events.EVENT_BLOCK
        elif event == 'VIEW_COVERGRID':
            self.change_style('CoverGrid')
            return input_events.EVENT_BLOCK

        return input_events.EVENT_CONTINUE

    @staticmethod
    def _create_or_get_view(view_name):
        if view_name in _views:
            DBG('View exists: ' + view_name)
            return _views[view_name]
        # call the constructor of the given class style ex: ViewList()
        DBG('Create view: ' + view_name)
        _views[view_name] = eval('View' + view_name + '()')
        return _views[view_name] class EmcItemClass(Singleton):
    """ TODO Class doc """

    def item_selected(self, url, user_data):
        """ Called when an item is selected """
        # DBG(('item_selected(%s)' % url))
        pass

    def label_get(self, url, user_data):
        """ Called when a view need to show the label of your item.
            Must return the string to show. """
        # DBG(('label_get(%s)' % url))
        return 'Unknow'

    def label_end_get(self, url, user_data):
        """ Called when a view need to show the secondary label of your item.
            Must return the string to show, or None """
        return None

    def icon_get(self, url, user_data):
        """ Called when a view need to show the icon of your item.
            Must return the name of the icon to use for the given url
            see gui.load_icon() for detail on what you can pass as the name"""
        # DBG(('icon_get(%s)' % url))
        return None

    def icon_end_get(self, url, user_data):
        # DBG(('icon_end_get(%s)' % url))
        return None

    def info_get(self, url, user_data):
        """ Called when a view need to show the info of your item.
            Must return a string with the murkupped text that describe the item """
        # DBG(('info_get(%s)' % url))
        return None

    def poster_get(self, url, user_data):
        """ Called when a view need to show the poster of your
            item, must return the full path of a valid image file.
            The poster MUST have a 1:2 aspect.
            You can also return a valid url (http://) to automatically
            download the image to a random temp file.
            In addition you can also set the destination path for the given url,
            to set an url AND a destination just return a tuple, as:
            (url, local_path)
            """
        # DBG(('poster_get(%s)' % url))
        return None

    def cover_get(self, url, user_data):
        """ Like poster_get but th image should be squared (or a bit larger) """
        # DBG(('poster_get(%s)' % url))
        return None

    def fanart_get(self, url, user_data):
        """ Called when a view need to show the fanart of your item.
            Must return the full path of a valid image file """
        # DBG(('fanart_get(%s)' % url))
        return None class EmcDialog(EmcLayout):
    """ TODO doc this
    style can be 'panel' or 'minimal'

    you can also apply special style that perform specific task:
       'info', 'error', 'warning', 'yesno', 'cancel', 'progress',
       'list', 'image_list_horiz', 'image_list_vert',
       'buffering'
    """

    minimal_styles = ['info', 'error', 'warning', 'yesno', 'cancel', 'progress']
    dialogs_counter = 0

    def __init__(self, title=None, text=None, content=None, spinner=False,
                 style='panel', done_cb=None, canc_cb=None, user_data=None):

        # load the right edje object
        if style in EmcDialog.minimal_styles or style == 'minimal':
            group = 'emc/dialog/minimal'
        elif style == 'buffering':
            group = 'emc/dialog/buffering'
        else:
            group = 'emc/dialog/panel'
        EmcLayout.__init__(self, layout, file=(theme_file, group),
                           focus_allow=True, is_focus_manager=True,
                           size_hint_align=FILL_BOTH,
                           size_hint_weight=EXPAND_BOTH)
        self.signal_callback_add('emc,dialog,close', '', self._close_pressed)
        self.signal_callback_add('emc,dialog,hide,done', '',
                                 (lambda a, s, d: self._delete_real()))
        self.signal_callback_add('emc,dialog,show,done', '',
                                 (lambda a, s, d: None))

        # put the dialog in the dialogs box of the main edje obj,
        # this way we only manage one edje and don't have stacking problems.
        # otherwise dialogs will stole the mouse events.
        box_append('dialogs.box.stack', self)

        EmcDialog.dialogs_counter += 1
        self._name = 'Dialog-' + str(EmcDialog.dialogs_counter)
        self._content = content
        self._done_cb = done_cb
        self._canc_cb = canc_cb
        self._user_data = user_data
        self._list = None
        self._textentry = None
        self._buttons = []

        # give focus to the dialog itself (for dialogs without any focusable)
        if style != 'buffering':
            self.focus = True

        # title
        if title is None:
            self.signal_emit('emc,dialog,title,hide', 'emc')
        else:
            self.part_text_set('emc.text.title', title)
            self.signal_emit('emc,dialog,title,show', 'emc')

        # vbox
        if style != 'buffering':
            self._vbox = elm.Box(self, horizontal=False, size_hint_align=FILL_HORIZ,
                                 size_hint_weight=EXPAND_HORIZ)
            self._vbox.show()
            self.content_set('emc.swallow.content', self._vbox)

        # if both text and content given then put them side by side
        if text and content:
            hbox = elm.Box(self, horizontal=True, size_hint_align=FILL_BOTH,
                           size_hint_weight=EXPAND_BOTH)
            hbox.show()
            self._vbox.pack_end(hbox)

        # text entry
        if text is not None:
            self._textentry = EmcScrolledEntry(parent=self, text=text,
                                               size_hint_weight=EXPAND_BOTH,
                                               size_hint_align=FILL_BOTH)
            self._textentry.show()

            if content:
                hbox.pack_end(self._textentry)
            else:
                self._vbox.pack_end(self._textentry)

        # user content
        if content is not None:
            frame = elm.Frame(self, style='pad_small', size_hint_align=FILL_BOTH,
                              size_hint_weight=EXPAND_BOTH, content=content)
            frame.show()
            if text is not None:
                hbox.pack_start(frame)
            else:
                self._vbox.pack_end(frame)

        # automatic list
        if style in ['list', 'image_list_horiz', 'image_list_vert']:
            self._list = EmcList(self, focus_allow=False,
                                 size_hint_align=FILL_BOTH, size_hint_weight=EXPAND_BOTH,
                                 horizontal=True if style == 'image_list_horiz' else False,
                                 style='dialog' if style == 'list' else 'image_list')
            self._list.callback_activated_add(self._list_item_activated_cb)
            self._list.show()
            self._vbox.pack_end(self._list)

        # spinner
        if spinner:
            self._spinner = elm.Progressbar(self, style='wheel', pulse_mode=True)
            self._spinner.pulse(True)
            self._spinner.show()
            self._vbox.pack_end(self._spinner)

        # set minimal styles + automatic title
        if style in EmcDialog.minimal_styles:
            self.signal_emit('emc,dialog,%s,set' % style, 'emc')
            if title is None:
                self.part_text_set('emc.text.title', style)
                self.signal_emit('emc,dialog,title,show', 'emc')

        # buttons
        if style in ('info', 'error', 'warning'):
            self.button_add(_('Ok'), lambda btn: self.delete())

        if style == 'yesno':
            if self._canc_cb:
                self.button_add(_('No'), lambda btn: self._canc_cb(self))
            else:
                self.button_add(_('No'), lambda btn: self.delete())

            if self._done_cb:
                self.button_add(_('Yes'), lambda btn: self._done_cb(self))
            else:
                self.button_add(_('Yes'), lambda btn: self.delete())

        if style == 'cancel':
            if canc_cb:
                self.button_add(_('Cancel'), lambda btn: self._canc_cb(self))
            else:
                self.button_add(_('Cancel'), lambda btn: self.delete())

        # listen for input events (not for the buffering dialog)
        if style != 'buffering':
            input_events.listener_add(self._name, self._input_event_cb)

        # show
        self.show()
        self.signal_emit('emc,dialog,show', 'emc')

    @staticmethod
    def activate():
        print('DEPRECATED EmcDialog.activate()')

    def delete(self):
        input_events.listener_del(self._name)
        self.signal_emit('emc,dialog,hide', 'emc')
        self.tree_focus_allow = False
        self.focus_allow = False
        for b in self._buttons:
            b.disabled = True

    def _delete_real(self):
        if self._textentry:
            self._textentry.delete()
        for b in self._buttons:
            b.delete()
        content = self.content_unset('emc.swallow.content')
        if content:
            content.delete()
        box_remove('dialogs.box.stack', self)
        elm.Layout.delete(self)
        del self

    def _close_pressed(self, a, s, d):
        if self._canc_cb:
            self._canc_cb(self)
        else:
            self.delete()

    def content_get(self):
        return self._content

    def data_get(self):
        return self._user_data

    def button_add(self, label, selected_cb=None, cb_data=None, icon=None, default=False):
        b = EmcButton(self, label, icon, selected_cb, cb_data)
        self.box_prepend('emc.box.buttons', b)
        self._buttons.append(b)
        if len(self._buttons) == 1:
            self.signal_emit('emc,dialog,buttons,show', 'emc')
            b.focus = True
        if default is True:
            b.focus = True
        return b

    def buttons_clear(self):
        for b in self._buttons:
            b.delete()
        del self._buttons
        self._buttons = []

    def title_set(self, text):
        if text is not None:
            self.part_text_set('emc.text.title', text)
            self.signal_emit('emc,dialog,title,show', 'emc')
        else:
            self.signal_emit('emc,dialog,title,hide', 'emc')

    def title_get(self):
        return self.part_text_get('emc.text.title')

    def text_set(self, text):
        if self._textentry:
            self._textentry.text_set(text)

    def text_get(self):
        return self._textentry.text_get()

    def text_append(self, text):
        self._textentry.text_set(self._textentry.text_get() + text)

    def list_item_append(self, label, icon=None, end=None, *args, **kwargs):
        if self._list:
            if isinstance(end, str) and end.startswith('text/'):
                end = elm.Label(self, style='dia_list', text=end[5:])
            it = self._list.item_append(label, load_icon(icon), load_icon(end), None)
            it.data['_user_item_data_'] = (args, kwargs)
            if not self._list.selected_item_get():
                it.selected = True
            return it

    def list_go(self):
        self._list.go()

    def list_clear(self):
        self._list.clear()

    def list_item_selected_get(self):
        if self._list:
            return self._list.selected_item_get()

    @staticmethod
    def list_item_icon_set(it, icon, end=False):
        it.part_content_set('end' if end else 'icon', load_icon(icon))

    def _list_item_activated_cb(self, li, it):
        if self._done_cb:
            args, kwargs = it.data['_user_item_data_']
            self._done_cb(self, *args, **kwargs)
        else:
            self.delete()

    def spinner_start(self):
        self._spinner.show()
        self._spinner.pulse(True)

    def spinner_stop(self):
        self._spinner.pulse(False)
        self._spinner.hide()

    def progress_set(self, val):
        self.edje.part_external_object_get('emc.dialog.progress').value_set(val)

    def autoscroll_enable(self, speed_scale=1.0, start_delay=3.0):
        self._textentry.autoscroll_start_delay = start_delay
        self._textentry.autoscroll_speed_scale = speed_scale
        self._textentry.autoscroll = True

    def focus_move_internal(self, direction):
        # try to move between list items
        if self._list or isinstance(self._content, (EmcList, EmcGenlist)):
            li = self._list or self._content
            if li.focus_move_internal(direction):
                return True

        # try to scroll the text entry
        if self._textentry:
            if direction == 'UP':
                self._textentry.scroll_by(0, -100)
            if direction == 'DOWN':
                self._textentry.scroll_by(0, +100)

        # try to move between dialog widgets
        self.focus_move(direction)

        # never let the focus goes out of the dialog
        return True

    def _input_event_cb(self, event):

        if not self.visible:
            return input_events.EVENT_CONTINUE

        if event in ['BACK', 'EXIT']:
            if self._canc_cb:
                self._canc_cb(self)
            else:
                self.delete()
            return input_events.EVENT_BLOCK

        if event == 'OK':
            if isinstance(self.focused_object, EmcButton):
                self.focused_object.activate()

            elif self._done_cb:
                if self._list:
                    it = self._list.selected_item
                    self._list_item_activated_cb(self._list, it)
                else:
                    self._done_cb(self)

            else:
                self.delete()

            return input_events.EVENT_BLOCK

        return input_events.EVENT_CONTINUE class EmcVKeyboard(EmcDialog):
    """ TODOC """

    def __init__(self, accept_cb=None, dismiss_cb=None,
                 title=None, text=None, user_data=None):
        """ TODOC """

        self.accept_cb = accept_cb
        self.dismiss_cb = dismiss_cb
        self.user_data = user_data
        self.buttons = list()

        # choose the correct layout
        self._available_layouts = ini.get_string_list('general', 'keyb_layouts')
        self._current_layout = self._available_layouts[0]  # TODO remember the last one used

        # table
        tb = elm.Table(layout, homogeneous=True)
        tb.show()
        self._table = tb

        # init the parent EmcDialog class
        EmcDialog.__init__(self, title=title, style='minimal', content=tb)

        # set dialog title
        self.part_text_set('emc.text.title', title or _('Insert text'))

        # entry
        self.entry = EmcTextEntry(self, style='vkeyboard', scrollable=True,
                                  single_line=True, editable=True,
                                  context_menu_disabled=True, focus_allow=True,
                                  size_hint_weight=EXPAND_BOTH, size_hint_align=FILL_BOTH)
        self.entry.callback_activated_add(self._accept_cb)
        self.entry.callback_aborted_add(self._dismiss_cb)
        if text: self.text_set(text)
        tb.pack(self.entry, 0, 0, 12, 1)
        self.entry.show()

        # numbers + backspace
        for i, c in enumerate('1234567890'):
            self._pack_btn(i, 1, 1, 1, c, cb=self._default_btn_cb)
        self._pack_btn(10, 1, 2, 1, _('ERASE'), cb=self._erase_cb)

        # characters
        self._apply_layout(self._current_layout)

        # last 2 rows
        self._pack_btn(0, 5, 4, 1, keyboard_layouts[self._current_layout][0],
                       cb=self._change_layout_cb)
        self._pack_btn(4, 5, 4, 1, _('SPACE'), cb=self._space_cb)
        self._pack_btn(8, 5, 4, 1, _('UPPERCASE'), cb=self._uppercase_cb)

        self._pack_btn(0, 6, 5, 1, _('Dismiss'), 'icon/cancel', self._dismiss_cb)
        self._pack_btn(5, 6, 1, 1, None, 'icon/arrowL',
                       lambda b: self.entry.cursor_prev())
        self._pack_btn(6, 6, 1, 1, None, 'icon/arrowR',
                       lambda b: self.entry.cursor_next())
        self._pack_btn(7, 6, 5, 1, _('Accept'), 'icon/ok', self._accept_cb)

        # catch input events
        input_events.listener_add('vkbd', self.input_event_cb)
        self.entry.focus = True

    def _pack_btn(self, x, y, w, h, label, icon=None, cb=None):
        b = EmcButton(self, label, icon, cb=cb, size_hint_align=FILL_HORIZ)
        self._table.pack(b, x, y, w, h)
        self.buttons.append(b)
        return b

    def delete(self):
        input_events.listener_del('vkbd')
        EmcDialog.delete(self)

    def text_set(self, text):
        self.entry.text = text
        self.entry.cursor_end_set()

    def _dismiss_cb(self, button):
        if self.dismiss_cb and callable(self.dismiss_cb):
            self.dismiss_cb(self)
        self.delete()

    def _accept_cb(self, button):
        if self.accept_cb and callable(self.accept_cb):
            if self.user_data is not None:
                ret = self.accept_cb(self, self.entry.entry_get(), self.user_data)
            else:
                ret = self.accept_cb(self, self.entry.entry_get())
            if ret is False:
                return
        self.delete()

    def _default_btn_cb(self, button):
        self.entry.entry_insert(button.text)

    def _erase_cb(self, button):
        pos = self.entry.cursor_pos_get()
        if pos > 0:
            text = self.entry.text
            self.entry.text = text[:pos - 1] + text[pos:]
            self.entry.cursor_pos_set(pos - 1)

    def _space_cb(self, button):
        self.entry.entry_insert(' ')

    def _uppercase_cb(self, button):
        if self._current_layout == 'symbols':
            return

        for btn in self.buttons:
            c = btn.text_get()
            if c and len(c) == 1 and c.isalpha():
                if c.islower():
                    btn.text = c.upper()
                    button.text = _('LOWERCASE')
                else:
                    btn.text = c.lower()
                    button.text = _('UPPERCASE')
            elif c and len(c) == 1:
                if c == '(':
                    btn.text = '['
                elif c == ')':
                    btn.text = ']'
                elif c == '[':
                    btn.text = '('
                elif c == ']':
                    btn.text = ')'
                elif c == '.':
                    btn.text = ':'
                elif c == ':':
                    btn.text = '.'
                elif c == ',':
                    btn.text = ';'
                elif c == ';':
                    btn.text = ','
                elif c == '-':
                    btn.text = '_'
                elif c == '_':
                    btn.text = '-'
                elif c == '?':
                    btn.text = '!'
                elif c == '!':
                    btn.text = '?'
                elif c == '+':
                    btn.text = '*'
                elif c == '*':
                    btn.text = '+'
                elif c == '@':
                    btn.text = '/'
                elif c == '/':
                    btn.text = '@'

    def _apply_layout(self, layout):
        for j in range(2, 5):
            for i in range(12):
                old = self._table.child_get(i, j)
                if old:
                    old.delete()

        self._current_layout = layout
        for j in range(3):
            for i, c in enumerate(keyboard_layouts[self._current_layout][j + 1]):
                if c != ' ':
                    self._pack_btn(i, j + 2, 1, 1, c, cb=self._default_btn_cb)

    def _change_layout_cb(self, button):
        new_idx = self._available_layouts.index(self._current_layout) + 1
        if new_idx >= len(self._available_layouts):
            new_idx = 0
        self._apply_layout(self._available_layouts[new_idx])
        button.text = keyboard_layouts[self._current_layout][0]

    def input_event_cb(self, event):
        if event == 'EXIT':
            self._dismiss_cb(None)
            return input_events.EVENT_BLOCK

        return input_events.EVENT_CONTINUE def DBG(*args):
def ERR(*args):
def init():
def shutdown():
    def __init__(self, url, dst, frame, func, **kargs):
    def __repr__(self):
    def __eq__(self, other):
    def __hash__(self):
    def __init__(self, done_cb=None):
    def id(self):
    def is_idle(self):
    def item_in_process(self):
    def generate_item(self, item):
    def item_completed(self, success):
    def kill(self):
    def _timeout_cb(self):
    def __init__(self, *args):
    def generate_item(self, item):
    def kill(self):
    def _slave_process_start(self):
    def _slave_died_cb(self, exe, event):
    def _slave_stdout_cb(self, exe, event):
    def _send_request(self):
    def _parse_response(self, msg):
    def __init__(self):
    def thumb_path_get(url):
    def generate(self, url, func, frame=None, **kargs):
    def cancel_request(self, req_id):
    def rebuild_workers_pool(self):  # this is used in config_gui
    def _process_queue(self):
    def _worker_done_cb(self, worker, item, success):
class EmcThumbItem(object):
class EmcThumbWorker_Base(object):
class EmcThumbWorker_EThumbSubprocess(EmcThumbWorker_Base):
class EmcThumbnailer(utils.Singleton):
import os
import sys
    import pyudev
from operator import attrgetter
from efl import evas, ecore
from epymc import gui, mainmenu, ini, modules, utils
from epymc.browser import EmcBrowser, EmcItemClass
from epymc.gui import EmcDialog, EmcVKeyboard
from epymc.thumbnailer import emc_thumbnailer
    from epymc.gui import _theme_generation
    from epymc import __version__ as emc_version
        from efl import __version__ as efl_version
    standard_item_int_meaning_add('mediaplayer', 'resume_from_last_pos',
                                  _('Resume playback'), values=vals)
    standard_item_number_add('general', 'scale', _('Interface scale'), 'icon/scale', cb=_change_scale, fmt='%.1f',
                             udm='x', vmin=0.5, vmax=2.0, step=0.1)
    standard_item_action_add(_('Virtual keyboard layouts'), 'icon/key',
                             cb=_vkeyb_layouts_list)
    standard_item_string_add('general', 'download_folder',
                             _('Download folder'), 'icon/download')
    standard_item_number_add('general', 'max_concurrent_download', _('Max concurrent download'), 'icon/download',
                             fmt='%.0f', vmin=1, vmax=10, step=1)
    standard_item_string_add('general', 'time_format', _('Time format'))
    standard_item_string_add('general', 'date_format', _('Date format'))

    # L = evas.render_method_list()
    # for remove in ('buffer', 'software_generic', 'gl_generic'):
    #    if remove in L: L.remove(remove)
    # if 'gl_x11' in L:
    #    L.remove('gl_x11')
    #    L.append('opengl_x11')
    # standard_item_string_from_list_add('general', 'evas_engine',
    # _('Rendering engine'), L, 'icon/evas',
    # cb=_restart_needed)
    standard_item_bool_add('general', 'evas_accelerated',
                           _('Use hardware acceleration'), 'icon/evas',
                           cb=_restart_needed)

    li = ['vlc', 'gstreamer1', 'gstreamer', 'xine', 'generic']
    standard_item_string_from_list_add('mediaplayer', 'backend',
                                       _('Multimedia engine'), li, 'icon/evas')

    standard_item_number_add('general', 'fps', _('Frames per second'), 'icon/evas', cb=_change_fps, fmt='%.0f',
                             udm='fps', vmin=10, vmax=120, step=10)
    standard_item_number_add('thumbnailer', 'max_concurrent_thumb', _('Max concurrent thumbnails'), cb=_change_thumbs,
                             fmt='%.0f', vmin=1, vmax=10, step=1)
    standard_item_number_add('thumbnailer', 'max_generation_time', _('Max thumbnails generation time'),
                             cb=_change_thumbs, fmt='%.0f', udm=_('seconds'), vmin=5, vmax=60, step=5)
    standard_item_action_add(_('Clear thumbnails cache'), icon='icon/refresh',
                             cb=_clear_thumbnails_cache)
    standard_item_action_add(_('Clear online images cache'), icon='icon/refresh',
                             cb=_clear_remotes_cache)


def _restart_needed():
    EmcDialog(style='info', title=_('Restart needed'),
              text=_('You need to restart the program to apply the new configuration.'))


def _change_fps():
    gui.fps_set(ini.get_int('general', 'fps'))


def _change_scale():
    gui.scale_set(ini.get_float('general', 'scale'))


def _change_thumbs():
    emc_thumbnailer.rebuild_workers_pool()


def _clear_thumbnails_cache():
    def _idler_cb(generator):
        try:
            fname = next(generator)
            os.remove(fname)
            dia.my_counter += 1
        except StopIteration:
            EmcDialog(style='cancel', title=_('Clear thumbnails cache'),
                      text='Operation completed, %d files deleted.' % dia.my_counter)
            dia.delete()
            return ecore.ECORE_CALLBACK_CANCEL
        return ecore.ECORE_CALLBACK_RENEW

    dia = EmcDialog(style='minimal', title=_('Clear thumbnails cache'),
                    spinner=True, text=_('Operation in progress, please wait...'))
    dia.my_counter = 0
    gen = utils.grab_files(os.path.join(utils.user_cache_dir, 'thumbs'))
    ecore.Idler(_idler_cb, gen)


def _clear_remotes_cache():
    def _idler_cb(generator):
        try:
            fname = next(generator)
            os.remove(fname)
            dia.my_counter += 1
        except StopIteration:
            EmcDialog(style='cancel', title=_('Clear online images cache'),
                      text='Operation completed, %d files deleted.' % dia.my_counter)
            dia.delete()
            return ecore.ECORE_CALLBACK_CANCEL
        return ecore.ECORE_CALLBACK_RENEW

    dia = EmcDialog(style='minimal', title=_('Clear online images cache'),
                    spinner=True, text=_('Operation in progress, please wait...'))
    dia.my_counter = 0
    gen = utils.grab_files(os.path.join(utils.user_cache_dir, 'remotes'))
    ecore.Idler(_idler_cb, gen)


def _vkeyb_layouts_list():
    dia = EmcDialog(title=_('Virtual keyboard layouts'), style='list',
                    done_cb=_vkeyb_layouts_select_cb)
    dia.button_add(_('Close'),
                   selected_cb=_vkeyb_layouts_close_cb, cb_data=dia)
    dia.button_add(_('Select'), default=True,
                   selected_cb=_vkeyb_layouts_select_cb, cb_data=dia)

    avail = ini.get_string_list('general', 'keyb_layouts')
    for k in sorted(gui.keyboard_layouts.keys()):
        name = gui.keyboard_layouts[k][0]
        end = 'icon/check_on' if k in avail else 'icon/check_off'
        it = dia.list_item_append(name, end=end)
        it.data['key'] = k


def _vkeyb_layouts_select_cb(obj, dia=None):
    if not dia:
        dia = obj
    it = dia.list_item_selected_get()
    key = it.data['key']

    avail = ini.get_string_list('general', 'keyb_layouts')