Exemplo n.º 1
0
class File_Saver(pride.gui.form.Scrollable_Window):

    defaults = {"data" : bytes(), "filename" : '', "autodelete" : False,
                "location" : "top"}
    subcomponents = {"vertical_slider" : Component(location=None),
                     "horizontal_slider" : Component(location=None),
        "_file_saver" : Component("pride.gui.programs.fileexplorer._File_Saver",
                                  h_range=(0, .1), location="left"),
        "directory_viewer" :
                  Component("pride.gui.programs.fileexplorer.Directory_Viewer",
                            location="left")}
    autoreferences = ("prompt", "file_saver", "directory_viewer")

    def create_subcomponents(self):
        super(File_Saver, self).create_subcomponents()
        window = self.main_window
        self.file_saver = window.create(self._file_saver_type, data=self.data,
                                        target_object=self,
                                        **self._file_saver_kwargs)
        self.directory_viewer = window.create(self.directory_viewer_type,
                                              **self.directory_viewer_kwargs)

    def save_data(self, overwrite=False):
        filename = os.path.join(self.directory_viewer.current_node,
                                self.filename)
        filename = os.path.expanduser(filename)
        already_exists = os.path.exists(filename)
        if already_exists and self.prompt is None:
            if overwrite == False:
                self.prompt = self.main_window.create(Overwrite_Prompt)
            #else:
            #    if self.prompt is not None and not self.prompt.deleted:
            #        self.prompt.delete()
            #        assert self.prompt is None
        if overwrite or not already_exists:
            size = len(self.data)
            units = ["bytes", "KB", "MB", "GB", "TB"]
            index = 0
            while size > 1024:
                index += 1
                size /= 1024.0
            self.show_status("Saving {0:.2f}{1} to {2}...".format(size, units[index], filename))
            try:
                with open(filename, "wb") as _file:
                    _file.write(self.data)
            except IOError:
                if os.path.exists(filename):
                    raise
                self.show_status("Unable to write to file {}; Ensure all directories exist and are spelled correctly and try again.".format(filename))
            else:
                if self.autodelete:
                    self.delete()
Exemplo n.º 2
0
class Theme_Editor(pride.gui.link.Linked_Form):

    defaults = {"target_theme" : None}
    subcomponents = {"form" :
                    Component("pride.gui.programs.themecustomizer2.Theme_Form"),
                     "tab_bar" : Component(include_new_tab_button=False),
                     "file_saver" :
                         Component("pride.gui.programs.fileexplorer.File_Saver",
                                   location="top", autodelete=True),
                     "file_selector" :
                     Component("pride.gui.programs.fileexplorer.File_Selector")}
    autoreferences = ("file_saver", "file_selector")

    def create_subcomponents(self):
        if self.target_theme is None:
            self.target_theme = self.theme
        theme = self.target_theme
        theme_editor_layout = generate_theme_editor_layout(theme)
        options_layout = generate_options_layout()
        self.layout = layout(links=(page("editor", theme_editor_layout),
                                    page("options", options_layout)))
        super(Theme_Editor, self).create_subcomponents()

    def save_theme(self):
        if self.file_saver is None:
            # have to use this window to make the result look "right"
            window = self.main_window.children[0].form.main_window
            file_saver = window.create(self.file_saver_type,
                                       data=self.theme.serialize(),
                                       **self.file_saver_kwargs)
            self.file_saver = file_saver
        else:
            self.file_saver.delete()

    def load_theme(self):
        if self.file_selector is None:
            # have to use this window to make the result look "right"
            window = self.main_window.children[0].form.main_window
            file_selector = window.create(self.file_selector_type,
                                          callback=self._load_theme,
                                          **self.file_selector_kwargs)
            self.file_selector = file_selector
        else:
            self.file_selector.delete()

    def _load_theme(self, filename):
        with open(filename, 'r') as _file:
            _bytes = _file.read()
        theme_colors = self.theme.deserialize(_bytes)
        self.theme.update_theme_colors(theme_colors)
Exemplo n.º 3
0
class Spinbox(Field):

    defaults = {"minimum" : None, "maximum" : None}
                # can only use either minimum or maximum but not both by default
                # must specify Spinbox type explicitly if min and max are used.
    subcomponents = {"entry" : Component("pride.gui.fields.Spinbox_Entry",
                                         location="left")}
    interface = (tuple(), ("minimum", "maximum"))

    def create_entry(self, location):
        container = self.create(pride.gui.gui.Container, location=location)
        entry_type = self.entry_type
        entry = self.entry = container.create(entry_type, parent_field=self,
                                              tip_bar_text=self.tip_bar_text,
                                               **self.entry_kwargs)
        if self.editable:
            subcontainer = container.create(pride.gui.gui.Container,
                                            location="left",
                                            w_range=(0, .05))
            kwargs = {"target_entry" : entry, "location" : "top"}
            self.inc_button = subcontainer.create(Increment_Button, **kwargs)
            assert kwargs == {"target_entry" : entry, "location" : "top"}
            self.dec_button = subcontainer.create(Decrement_Button, **kwargs)

    def handle_value_changed(self, old_value, new_value):
        return super(Spinbox, self).handle_value_changed(int(old_value), int(new_value))
Exemplo n.º 4
0
class Callable_Field(Field):

    defaults = {"orientation" : "side by side",
                "has_label" : False, "button_text" : '', "args" : tuple()}
    mutable_defaults = {"kwargs" : dict}
    subcomponents = {"entry" : Component("pride.gui.fields.Callable_Entry",
                                         scale_to_text=True)}
    interface = (tuple(), ("button_text", "args", "kwargs"))

    def create_entry(self, location):
        super(Callable_Field, self).create_entry(location)
        self.entry.text = self.entry.text # .text may not get set, if so then scale_to_text wont happen

    def delete(self):
        del self.kwargs
        super(Callable_Field, self).delete()
Exemplo n.º 5
0
class Media_Entry(Entry):

    subcomponents = {"player" : Component("pride.gui.fields.Media_Player")}
    autoreferences = ("player", )

    def _get_text(self):
        return ''
    def _set_text(self, value):
        super(Media_Entry, self)._set_text(value)
    text = property(_get_text, _set_text)

    def __init__(self, **kwargs):
        super(Media_Entry, self).__init__(**kwargs)
        self.create_subcomponents()

    def create_subcomponents(self):
        self.player = self.create(self.player_type,
                                  **self.player_kwargs)
Exemplo n.º 6
0
class Theme_Form(pride.gui.form.Form):

    subcomponents = {"form" :
                    Component("pride.gui.programs.themecustomizer2.Theme_Form")}

    def get_parent_theme_editor(self):
        parent = self.parent
        while not hasattr(parent, "target_theme"):
            parent = parent.parent
        return parent

    def handle_value_changed(self, field, old, new):
        self.get_parent_theme_editor().target_theme.update_theme_users()

    def save_theme(self):
        self.get_parent_theme_editor().save_theme()

    def load_theme(self):
        self.get_parent_theme_editor().load_theme()
Exemplo n.º 7
0
Arquivo: link.py Projeto: alyxd/pride
class Linked_Form(pride.gui.tabs.Tabbed_Window):

    subcomponents = {"form" : Component("pride.gui.form2.Remote_Form")}
    autoreferences = ("form", )

    def create_subcomponents(self):
        _layout = self.layout
        form_type = self.form_type
        tabs = []
        for page_id, page_layout in _layout[-1].get("links", tuple()):
            target = lazy_loaded(Linked_Form, layout=page_layout,
                                 form_type=form_type)
            tabs.append(tab_info(target, button_text=page_id,
                                 entry_kwargs={"scale_to_text" : False}))
        self.tab_bar_kwargs["tab_info"] = tabs
        super(Linked_Form, self).create_subcomponents()
        if not tabs:
            self.tab_bar.hide()
        if _layout[0]:
            self.form = self.main_window.create(form_type, layout=_layout)
Exemplo n.º 8
0
class Media_Player(pride.gui.link.Linked_Form):

    defaults = {"filename": ''}
    parser_args = ("filename", )
    parser_modifiers = {"filename": {"types": ("positional", )}}
    subcomponents = {"tab_bar": Component(include_new_tab_button=False)}

    def create_subcomponents(self):
        filename = self.filename
        alias = os.path.split(filename)[-1]
        manifest, manifest_data = load_resources((alias, filename))
        control_page = \
            page("controls",
                 layout(
                    row_info(0,
                         field_info("filename",
                                    field_type="pride.gui.fields.Media_Field",
                                    play_when_opened=True)),
                        manifest=manifest, filename=alias))
        resource_id = manifest[alias]
        store_resource(resource_id, manifest_data[alias])
        self.layout = control_page[1]  #layout(links=(control_page, ))
        super(Media_Player, self).create_subcomponents()
Exemplo n.º 9
0
class Slider_Field(Field):

    predefaults = {"_minimum" : 0, "_maximum" : 0}
    interface = (tuple(), ("minimum", "maximum"))
    subcomponents = {"entry" : Component("pride.gui.fields.Slider_Entry")}

    def _get_minimum(self):
        return self._minimum
    def _set_minimum(self, value):
        self._minimum = value
        if self.minimum == self.maximum:
            self.hide()
        else:
            self.show()
    minimum = property(_get_minimum, _set_minimum)

    def _get_maximum(self):
        return self._maximum
    def _set_maximum(self, value):
        self._maximum = value
        if self.minimum == self.maximum:
            self.hide()
        else:
            self.show()
        try:
            self.entry.max_button.entry.texture_invalid = True
        except AttributeError:
            pass
    maximum = property(_get_maximum, _set_maximum)

    def handle_transition_animation_end(self):
        super(Slider_Field, self).handle_transition_animation_end()
        self.update_position_from_value()

    def update_position_from_value(self):
        self.entry.continuum.update_position_from_value()
Exemplo n.º 10
0
Arquivo: form.py Projeto: alyxd/pride
class Scrollable_Window(pride.gui.gui.Window):

    predefaults = {"_x_scroll_value": 0, "_y_scroll_value": 0}
    autoreferences = ("main_window", "vertical_slider", "horizontal_slider")
    subcomponents = {
        "vertical_slider":
        Component("pride.gui.fields.Slider_Field",
                  location="right",
                  orientation="stacked",
                  w_range=(0, .025),
                  name="y_scroll_value",
                  minimum=0,
                  maximum=0,
                  has_label=False,
                  entry_kwargs={"orientation": "stacked"}),
        "horizontal_slider":
        Component("pride.gui.fields.Slider_Field",
                  h_range=(0, .025),
                  has_label=False,
                  name="x_scroll_value",
                  minimum=0,
                  maximum=0,
                  location="bottom",
                  orientation="side by side"),
        "main_window":
        Component("pride.gui.gui.Window", location="main")
    }
    interface = (tuple(), ("horizontal_slider_kwargs",
                           "vertical_slider_kwargs"))

    def _get_y_scroll_value(self):
        return self._y_scroll_value

    def _set_y_scroll_value(self, new_value):
        old_value = self._y_scroll_value
        self._y_scroll_value = new_value
        self.handle_y_scroll(old_value, new_value)

    y_scroll_value = property(_get_y_scroll_value, _set_y_scroll_value)

    def _get_x_scroll_value(self):
        return self._x_scroll_value

    def _set_x_scroll_value(self, new_value):
        old_value = self._x_scroll_value
        self._x_scroll_value = new_value
        self.handle_x_scroll(old_value, new_value)

    x_scroll_value = property(_get_x_scroll_value, _set_x_scroll_value)

    def __init__(self, **kwargs):
        super(Scrollable_Window, self).__init__(**kwargs)
        self.create_subcomponents()

    def create_subcomponents(self):
        self.main_window = self.create(self.main_window_type,
                                       **self.main_window_kwargs)
        kwargs = self.vertical_slider_kwargs
        location = kwargs["location"]
        if location is not None:
            slider_type = self.vertical_slider_type
            self.vertical_slider = self.create(slider_type,
                                               target_object=self,
                                               **kwargs)
        kwargs = self.horizontal_slider_kwargs
        location = kwargs["location"]
        if location is not None:
            slider_type = self.horizontal_slider_type
            self.horizontal_slider = self.create(slider_type,
                                                 target_object=self,
                                                 **kwargs)

    def handle_x_scroll(self, old_value, new_value):
        pass

    def handle_y_scroll(self, old_value, new_value):
        pass
Exemplo n.º 11
0
class Image_Field(Field):

    subcomponents = {"entry" : Component("pride.gui.fields.Image_Entry")}
Exemplo n.º 12
0
class _Endcap(Text_Field):

    defaults = {"editable" : False, "has_label" : False}
    subcomponents = {"entry" : Component("pride.gui.fields._Endcap_Entry")}
Exemplo n.º 13
0
class Field(pride.gui.gui.Container):

    defaults = {"name" : '', "orientation" : "stacked",
                "_value_initialized" : False, "field_type" : None,
                "editable" : True, "location" : "left", "has_label" : True,
                "display_name" : ''}
    subcomponents = {"entry" : Component("pride.gui.fields.Entry"),
                     "label" : Component("pride.gui.gui.Container")}
    predefaults = {"target_object" : None}
    autoreferences = ("label", "parent_form", "entry")
    allowed_values = {"orientation" : ("stacked", "side by side")}
    interface = (tuple(), ("name", "orientation", "field_type", "editable",
                           "location", "has_label", "display_name",
                           "entry_kwargs"))

    def _get_value(self):
        try:
            return getattr(self.target_object, self.name)
        except (TypeError, AttributeError) as exception:
            try:
                return self.target_object[self.name]
            except TypeError:
                raise exception
    def _set_value(self, value):
        if self.editable:
            old_value = self.value
            if self.handle_value_changed(old_value, value):
                try:
                    setattr(self.target_object, self.name, value)
                except (TypeError, AttributeError) as exception:
                    assert hasattr(self, "target_object")
                    try: # duck typing might fail for mapping-like objects that don't restrict attribute assignment the way a dict does
                        self.target_object[self.name] = value
                    except TypeError:
                        if hasattr(self, "target_object") and hasattr(self, "name"):
                            raise exception

                self.entry.texture_invalid = True # updates text later
                parent_form = self.parent_form
                if parent_form is not None:
                    parent_form.handle_value_changed(self, old_value, value)
    value = property(_get_value, _set_value)

    def __init__(self, **kwargs):
        super(Field, self).__init__(**kwargs)
        self.create_subcomponents()

    def create_subcomponents(self):
        label_kwargs = self.label_kwargs
        orientation = self.orientation
        if orientation == "stacked":
            location = "top"
            label_kwargs.setdefault("scale_to_text", False)
            label_kwargs.setdefault("h_range", (0, .05))
        else:
            assert orientation == "side by side"
            location = "left"
        assert self.label is None
        self.create_label(location, **label_kwargs)
        self.create_entry(location)
        assert hasattr(self, "parent_form")

    def create_label(self, location, **label_kwargs):
        label_kwargs.setdefault("tip_bar_text", self.tip_bar_text)
        label_kwargs.setdefault("location", location)
        label_kwargs.setdefault("text", self.display_name or self.name)
        self.label = self.create(self.label_type, **label_kwargs)
        if not self.has_label:
            self.label.hide()

    def create_entry(self, location):
        kwargs = self.entry_kwargs
        kwargs.setdefault("location", location)
        entry_type = self.entry_type
        self.entry = self.create(entry_type, parent_field=self, **kwargs)

    def handle_value_changed(self, old_value, new_value):
        if old_value == new_value:
            return False
        self.alert("Value changing from {} to {}".format(old_value, new_value),
                    level=self.verbosity["handle_value_changed"])
        return True

    def delete(self):
        del self.entry_kwargs
        del self.target_object
        super(Field, self).delete()
Exemplo n.º 14
0
class Toggle(Field):

    subcomponents = {"entry" : Component("pride.gui.fields.Toggle_Entry")}
Exemplo n.º 15
0
Arquivo: form.py Projeto: alyxd/pride
class Form(Scrollable_Window):

    defaults = {"target_object": None, "max_rows": 4}
    subcomponents = {
        "row": Component("pride.gui.form.Row",
                         location="top",
                         h_range=(0, 1.0)),
        "horizontal_slider": Component(location=None)
    }
    mutable_defaults = {
        "rows": dict,
        "visible_rows": list,
        "layout": layout,
        "manifest": dict
    }
    interface = (tuple(), ("max_rows", "manifest"))

    hotkeys = {("\t", None): "handle_tab"}
    autoreferences = ("selected_entry", )

    def _get_fields(self):
        rows = self.rows
        return iterrows(rows)

    fields = property(_get_fields)

    def create_subcomponents(self):
        if self.target_object is None:
            self.target_object = self

        for key, value in self.layout[-1].iteritems():
            setattr(self, key, value)

        super(Form, self).create_subcomponents()

        _row_info = self.layout[0]
        max_rows = self.max_rows
        amount = max_rows
        # make a fixed number of visible rows
        # set the rows to represent the data of a given range of row_infos
        window = self.main_window
        self.visible_rows = [
            window.create(Visible_Row) for count in range(amount)
        ]
        visible_rows = self.visible_rows
        for row_no in range(amount):
            try:
                self.create_row(_row_info[row_no])
            except KeyError:
                if row_no in _row_info:
                    raise
                break

        self.load_rows()
        if self.selected_entry is None and self.rows:
            try:
                self.selected_entry = self.rows[0].fields[0].entry
            except IndexError:
                pass

        self.synchronize_scroll_bars()

    def unload_rows(self, new_row_indices):
        for row in self.visible_rows:
            row.unload_row(new_row_indices)

    def load_rows(self):
        start = self.y_scroll_value
        rows = self.rows
        visible_rows = self.visible_rows
        row_infos = self.layout[0]
        max_rows = self.max_rows
        amount = min(max_rows, len(row_infos))

        # must unload rows before calling load_row
        self.unload_rows(range(start, start + amount))
        for offset in range(amount):
            row_no = start + offset
            try:
                row = self.load_row(row_no)
            except KeyError:
                break
            visible_row = visible_rows[offset]
            row.show()
            visible_row.load_row(row)
            visible_row.show()

        excess = max_rows - amount
        if excess:
            for offset in range(excess):
                row_no = start + amount + offset
                visible_rows[row_no].hide()

    def load_row(self, row_no):
        try:
            return self.rows[row_no]
        except KeyError:
            self.create_row(self.layout[0][row_no])
            return self.rows[row_no]

    def create_row(self, _row_info):
        kwargs = copy.deepcopy(self.row_kwargs)
        row_type = self.row_type

        row_no, row_kwargs = _row_info[0], _row_info[-1]
        deep_update(kwargs, row_kwargs)
        kwargs.setdefault("row_number", row_no)

        window = self.main_window
        row = window.create(row_type, **kwargs)
        self.rows[row_no] = row
        _field_infos = _row_info[1:-1][0]
        for _field_info in _field_infos:
            self.create_field(_field_info, row)
        row.hide()
        window.remove(row)
        return row

    def create_field(self, _field_info, row):
        field_name, field_kwargs = _field_info
        target_object = field_kwargs.get("target_object", self.target_object)
        field_type = self.determine_field_type(target_object, field_name,
                                               field_kwargs)
        field_kwargs.setdefault("target_object", self.target_object)
        field_kwargs["name"] = field_name
        field = row.create(
            field_type,
            parent_form=self,
            field_no=sum(len(_row.fields) for _row in self.rows.values()),
            **field_kwargs)
        del field_kwargs["target_object"]
        row.fields.append(field)
        return field

    def determine_field_type(self, target_object, name, field_kwargs):
        field_type = field_kwargs.get("field_type", None)
        if field_type is None:
            try:
                value = getattr(target_object, name)
            except AttributeError as exception:
                try:
                    value = target_object[name]
                except TypeError:
                    raise exception
            #if hasattr(value, "field_type"):
            #    field_type = value.field_type

            # check for dropdowns before checking value
            if "values" in field_kwargs:
                field_type = "pride.gui.fields.Dropdown_Field"
            # check for Slider before checking for int/float
            elif "minimum" in field_kwargs and "maximum" in field_kwargs:
                field_type = "pride.gui.fields.Slider_Field"
            # must compare for bool before comparing for int; bool is a subclass of int
            elif isinstance(value, bool):
                field_type = "pride.gui.fields.Toggle"
            elif isinstance(value, int) or isinstance(value, float):
                field_type = "pride.gui.fields.Spinbox"
            elif isinstance(value, str):
                field_type = "pride.gui.fields.Text_Field"
            elif hasattr(value, "__call__"):
                field_type = "pride.gui.fields.Callable_Field"
            #elif isinstance(value, tuple) or isinstance(value, list):
            #    field_type = "pride.gui.widgets.formext.Tabbed_Form"
        if field_type is None:
            message = "Unable to determine field_type for {}"
            raise ValueError(
                message.format((target_object, name, value, field_kwargs)))
        return field_type

    def handle_value_changed(self, field, old, new):
        pass

    def synchronize_scroll_bars(self):
        slider = self.vertical_slider
        if slider is not None:
            slider.maximum = max(0, len(self.layout[0]) - self.max_rows)
            slider.update_position_from_value()
            slider.entry.texture_invalid = True
            self.pack()

    def handle_y_scroll(self, old, new):
        super(Form, self).handle_y_scroll(old, new)
        # y_scroll points to the current top row
        assert self.y_scroll_value == new, (self.y_scroll_value, new)
        self.load_rows()
        ## check if the selected entry is still visible, unselect it if not
        #row_no = self.selected_entry.parent_field.parent.row_number
        #amount = min(self.max_rows, len(self.layout[0]))
        #if row_no < new and row_no >= new + amount:
        #    self.selected_entry.deselect()
        #    new_entry = self.visible_rows[0]._current_row.fields[0].entry
        #    self.handle_entry_selected(new_entry, scroll=False)

    def handle_tab(self):
        # go to the next field in the row
        # if there are no more fields, go to the next row
        # if there are no more rows, go to the initial row
        entry = self.selected_entry
        field = entry.parent_field
        row = field.parent
        fields = row.fields
        field_index = fields.index(field)
        next_field_index = field_index + 1
        try:
            self.handle_entry_selected(fields[next_field_index].entry,
                                       scroll=True)
        except IndexError:
            rows = self.rows
            row_info = self.layout[0]
            row_count = len(row_info)
            row_index = row.row_number
            next_row_index = (row_index + 1) % row_count
            if next_row_index in row_info:
                if next_row_index not in rows:
                    self.create_row(row_info[row_index + 1])
                next_row = rows[next_row_index]
            else:
                next_row = rows[0]
            if not next_row.fields:
                has_fields = lambda row: row[1]
                has_any_fields = [
                    row for row in row_info.values() if has_fields(row)
                ]
                if not has_any_fields:
                    return
                for next_row_index in range(next_row_index, row_count):
                    if has_fields(row_info[next_row_index]):
                        break
                else:
                    for next_row_index in range(next_row_index + 1):
                        if has_fields(row_info[next_row_index]):
                            break
                if next_row_index not in rows:
                    self.create_row(row_info[next_row_index])
                next_row = rows[next_row_index]

            self.handle_entry_selected(next_row.fields[0].entry, scroll=True)

    def handle_entry_selected(self, entry, _needs_select=True, scroll=False):
        if self.selected_entry is not None:
            old_entry = self.selected_entry
            old_entry.deselect(entry)
        self.selected_entry = entry
        if _needs_select:
            self.sdl_window.user_input.select_active_item(entry)

        if scroll:
            row_no = entry.parent_field.parent.row_number
            max_index = len(self.layout[0]) - self.max_rows
            row_no = min(row_no, max_index)
            y_value = self.y_scroll_value
            if row_no < y_value:
                self.y_scroll_value = row_no
                self.handle_y_scroll(y_value, row_no)
            elif row_no > y_value + self.max_rows:
                self.y_scroll_value = row_no
                self.handle_y_scroll(y_value, self.y_scroll_value)
            elif row_no == max_index:
                self.y_scroll_value = row_no
                self.handle_y_scroll(y_value, row_no)
            self.synchronize_scroll_bars()

    def synchronize_fields(self):
        for field in self.fields:
            field.entry.texture_invalid = True

    def delete(self):
        self.rows.clear()
        del self.target_object
        del self.visible_rows
        super(Form, self).delete()
Exemplo n.º 16
0
class Dropdown_Field(Callable_Field):

    defaults = {"has_label" : True, "values" : tuple(),
                "orientation" : "side by side"}
    interface = (tuple(), ("values", ))
    subcomponents = {"entry" : Component("pride.gui.fields.Dropdown_Entry")}
Exemplo n.º 17
0
class Text_Field(Field):

    subcomponents = {"entry" : Component("pride.gui.fields.Text_Entry")}
Exemplo n.º 18
0
class Media_Field(Field):

    defaults = {"has_label" : False, "h_range" : (0, .25),
                "play_when_opened" : False,}
    subcomponents = {"entry" : Component("pride.gui.fields.Media_Entry")}
    interface = (tuple(), ("play_when_opened", ))