<commit_before># This file is part of ELiDE, frontend to LiSE, a framework for life simulation games.
# Copyright (c) <NAME>,  <EMAIL>
"""Grid of current values for some entity. Can be changed by the
user. Autoupdates when there's a change for any reason.

"""
from functools import partial
from kivy.properties import (
    BooleanProperty,
    DictProperty,
    NumericProperty,
    ObjectProperty,
    OptionProperty,
    ReferenceListProperty,
    StringProperty,
)
from kivy.logger import Logger
from kivy.clock import Clock
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.slider import Slider
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.lang import Builder
from .util import trigger


class StatRowListItem(Widget):
    """Mixin class for widgets that show a stat's current value.

    """
    key = ObjectProperty()
    "The stat I am about. Same as in the LiSE entity."
    value = ObjectProperty(None, allownone=True)
    "The present value of the stat."
    gett = ObjectProperty()
    "Getter function: takes stat, returns its present value."
    sett = ObjectProperty()
    "Setter function: takes stat and value, sets stat=value."
    listen = ObjectProperty()
    "Function that takes a function and calls it when the stat changes."
    unlisten = ObjectProperty()
    "Function that takes a ``listen``ed function and stops it listening."
    config = DictProperty()
    "Dictionary of some parameters for how to present myself."

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(value=self._bind_value)

    def _bind_value(self, *args):
        self.bind(value=self._push)
        self.unbind(value=self._bind_value)

    def on_listen(self, *args):
        self.listen(self._pull)
        self._pull()

    @trigger
    def _push(self, *args):
        self.sett(self.key, self.value)

    def _really_pull(self, *args):
        self.unbind(value=self._push)
        try:
            self.value = self.gett(self.key)
        except KeyError:
            Logger.info('StatRowListItem: {} deleted'.format(self.key))
        except TypeError:
            value = self.gett(self.key)
            Logger.warning("StatRowListItem: couldn't set value {} because it is type {}".format(
                value, type(value)
            ))
        self.bind(value=self._push)

    def _pull(self, *args, **kwargs):
        Clock.unschedule(self._really_pull)
        Clock.schedule_once(self._really_pull, 0)


class StatRowLabel(StatRowListItem, Label):
    """Display the current value of a stat as text."""


class StatRowTextInput(StatRowListItem, TextInput):
    """Display the current value of a stat and accept text input to change it."""
    def __init__(self, **kwargs):
        kwargs['multiline'] = False
        super().__init__(**kwargs)

        def lost_focus(self, *args):
            if not self.focus:
                self.upd_value()

        self.bind(
            on_enter=self.upd_value,
            on_text_validate=self.upd_value,
            on_focus=lost_focus
        )

    @trigger
    def upd_value(self, *args):
        if self.text not in ('', self.value):
            self.value = self.text
        self.text = ''


class StatRowToggleButton(StatRowListItem, ToggleButton):
    """Display the current value of a stat, 0 or 1, and let the user press a button to flip it."""
    true_text = StringProperty('1')
    """String to display when the stat is true."""
    false_text = StringProperty('0')
    """String to display when the stat is false."""

    def on_touch_up(self, *args):
        if self.parent is None:
            return
        if self.state == 'normal' and self.value != 0:
            self.value = 0
        elif self.state == 'down' and self.value != 1:
            self.value = 1


class StatRowSlider(StatRowListItem, Slider):
    """Display the current value of a numeric stat and let the user slide it."""
    need_set = BooleanProperty(False)
    """Internal. Usually False, becomes True briefly when the value has changed."""

    def __init__(self, **kwargs):
        self.value = kwargs['value']
        self.min = kwargs['min']
        self.max = kwargs['max']
        super().__init__(**kwargs)

    def on_listen(self, *args):
        self.listen(self._pull)
        self._pull()

    def on_value(self, *args):
        self.need_set = True

    def on_touch_up(self, *args):
        if self.need_set:<commit_msg>Fix twitchy sliders<commit_after># This file is part of ELiDE, frontend to LiSE, a framework for life simulation games.
# Copyright (c) <NAME>,  <EMAIL>
"""Grid of current values for some entity. Can be changed by the
user. Autoupdates when there's a change for any reason.

"""
from functools import partial
from kivy.properties import (
    BooleanProperty,
    DictProperty,
    NumericProperty,
    ObjectProperty,
    OptionProperty,
    ReferenceListProperty,
    StringProperty,
)
from kivy.logger import Logger
from kivy.clock import Clock
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.slider import Slider
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.lang import Builder
from .util import trigger


class StatRowListItem(Widget):
    """Mixin class for widgets that show a stat's current value.

    """
    key = ObjectProperty()
    "The stat I am about. Same as in the LiSE entity."
    value = ObjectProperty(None, allownone=True)
    "The present value of the stat."
    gett = ObjectProperty()
    "Getter function: takes stat, returns its present value."
    sett = ObjectProperty()
    "Setter function: takes stat and value, sets stat=value."
    listen = ObjectProperty()
    "Function that takes a function and calls it when the stat changes."
    unlisten = ObjectProperty()
    "Function that takes a ``listen``ed function and stops it listening."
    config = DictProperty()
    "Dictionary of some parameters for how to present myself."

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(value=self._bind_value)

    def _bind_value(self, *args):
        self.bind(value=self._push)
        self.unbind(value=self._bind_value)

    def on_listen(self, *args):
        self.listen(self._pull)
        self._pull()

    @trigger
    def _push(self, *args):
        self.sett(self.key, self.value)

    def _really_pull(self, *args):
        self.unbind(value=self._push)
        try:
            self.value = self.gett(self.key)
        except KeyError:
            Logger.info('StatRowListItem: {} deleted'.format(self.key))
        except TypeError:
            value = self.gett(self.key)
            Logger.warning("StatRowListItem: couldn't set value {} because it is type {}".format(
                value, type(value)
            ))
        self.bind(value=self._push)

    def _pull(self, *args, **kwargs):
        Clock.unschedule(self._really_pull)
        Clock.schedule_once(self._really_pull, 0)


class StatRowLabel(StatRowListItem, Label):
    """Display the current value of a stat as text."""


class StatRowTextInput(StatRowListItem, TextInput):
    """Display the current value of a stat and accept text input to change it."""
    def __init__(self, **kwargs):
        kwargs['multiline'] = False
        super().__init__(**kwargs)

        def lost_focus(self, *args):
            if not self.focus:
                self.upd_value()

        self.bind(
            on_enter=self.upd_value,
            on_text_validate=self.upd_value,
            on_focus=lost_focus
        )

    @trigger
    def upd_value(self, *args):
        if self.text not in ('', self.value):
            self.value = self.text
        self.text = ''


class StatRowToggleButton(StatRowListItem, ToggleButton):
    """Display the current value of a stat, 0 or 1, and let the user press a button to flip it."""
    true_text = StringProperty('1')
    """String to display when the stat is true."""
    false_text = StringProperty('0')
    """String to display when the stat is false."""

    def on_touch_up(self, *args):
        if self.parent is None:
            return
        if self.state == 'normal' and self.value != 0:
            self.value = 0
        elif self.state == 'down' and self.value != 1:
            self.value = 1


class StatRowSlider(StatRowListItem, Slider):
    """Display the current value of a numeric stat and let the user slide it."""
    need_set = BooleanProperty(False)
    """Internal. Usually False, becomes True briefly when the value has changed."""

    def __init__(self, **kwargs):
        self.value = kwargs['value']
        self.min = kwargs['min']
        self.max = kwargs['max']
        super().__init__(**kwargs)

    def _bind_value(self, *args):
        pass

    def _really_pull(self, *args):
        try:
            self.value = self.gett(self.key)
        except KeyError:
            Logger.info('StatRowListItem: {} deleted'.format(self.key))
        except TypeError:
            value = self.gett(self.key)
            Logger.warning("StatRowListItem: couldn't set value {} because it is type {}".format(
                value, type(value)
            ))

    def on_listen(self, *args):
        self.listen(self._pull)
        self._pull()

    def on_value(self, *args):
        self.need_set = True

    def on_touch_up(self, *args):
        if self.need_set:
{'fraction_non_alphanumeric': 0.10444974587698372, 'fraction_numerical': 0.0018670262420910693, 'mean_word_length': 2.6985040276179517, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3182929', 'n_tokens_mistral': 2881, 'n_tokens_neox': 2789, 'n_words': 880}