diff --git a/bin/myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk b/bin/uptimecheck-0.1-arm64-v8a_armeabi-v7a-debug.apk similarity index 86% rename from bin/myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk rename to bin/uptimecheck-0.1-arm64-v8a_armeabi-v7a-debug.apk index f22e05f..5bfe68b 100644 Binary files a/bin/myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk and b/bin/uptimecheck-0.1-arm64-v8a_armeabi-v7a-debug.apk differ diff --git a/buildozer.spec b/buildozer.spec index 9fcff8c..18b5de7 100644 --- a/buildozer.spec +++ b/buildozer.spec @@ -1,13 +1,13 @@ [app] # (str) Title of your application -title = My Application +title = Uptime Check # (str) Package name -package.name = myapp +package.name = uptimecheck # (str) Package domain (needed for android/ios packaging) -package.domain = org.test +package.domain = local.meko # (str) Source code where the main.py live source.dir = . @@ -37,7 +37,7 @@ version = 0.1 # (list) Application requirements # comma separated e.g. requirements = sqlite3,kivy -requirements = python3,kivy +requirements = python3,kivy,requests # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes diff --git a/kivy_venv/lib/python3.11/site-packages/__pycache__/asyncgui.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/__pycache__/asyncgui.cpython-311.pyc new file mode 100644 index 0000000..600c5a4 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/__pycache__/asyncgui.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/INSTALLER b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/INSTALLER similarity index 100% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/INSTALLER rename to kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/INSTALLER diff --git a/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/LICENSE b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/LICENSE new file mode 100644 index 0000000..ffa4a40 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/LICENSE @@ -0,0 +1,7 @@ +Copyright 2020 Nattōsai Mitō + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/METADATA b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/METADATA new file mode 100644 index 0000000..827a183 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/METADATA @@ -0,0 +1,57 @@ +Metadata-Version: 2.1 +Name: asyncgui +Version: 0.6.3 +Summary: A thin layer that helps to wrap a callback-style API in an async/await-style API +Home-page: https://github.com/gottadiveintopython/asyncgui +License: MIT +Keywords: async +Author: Nattōsai Mitō +Author-email: flow4re2c@gmail.com +Requires-Python: >=3.8.1,<4.0.0 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Topic :: Software Development :: Libraries +Requires-Dist: exceptiongroup (>=1.0.4,<2.0.0) ; python_version < "3.11" +Project-URL: Repository, https://github.com/gottadiveintopython/asyncgui +Description-Content-Type: text/markdown + +# AsyncGui + +A thin layer that helps to wrap a callback-style API in an async/await-style API. + +An async library that focuses on fast reaction. + +[Documentation](https://asyncgui.github.io/asyncgui/) + +## Installation + +Pin the minor version. + +```text +poetry add asyncgui@~0.6 +pip install "asyncgui>=0.6,<0.7" +``` + +## Tested on + +- CPython 3.8 +- CPython 3.9 +- CPython 3.10 +- CPython 3.11 +- CPython 3.12 (3.12.1 or later) + +## Async libraries that rely on this + +- [asynckivy](https://github.com/asyncgui/asynckivy) +- [asynctkinter](https://github.com/asyncgui/asynctkinter) +- [asyncpygame](https://github.com/asyncgui/asyncpygame) + diff --git a/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/RECORD b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/RECORD new file mode 100644 index 0000000..5dc9ca0 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/RECORD @@ -0,0 +1,7 @@ +__pycache__/asyncgui.cpython-311.pyc,, +asyncgui-0.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +asyncgui-0.6.3.dist-info/LICENSE,sha256=zdEfMrLu9-uJk1Y-D7fn_gqgODq71StrNs47LvNE5b0,1055 +asyncgui-0.6.3.dist-info/METADATA,sha256=OTiDgXiKJm39p7OP5DZQ6ZtiY6UU2tawUD1QfFIvbFs,1729 +asyncgui-0.6.3.dist-info/RECORD,, +asyncgui-0.6.3.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88 +asyncgui.py,sha256=89sbdDMVyRooyYsy7IqG7cLm8DJVY5U67K1kYQngBGE,27963 diff --git a/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/WHEEL b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/WHEEL new file mode 100644 index 0000000..258a6ff --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asyncgui-0.6.3.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: poetry-core 1.6.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/kivy_venv/lib/python3.11/site-packages/asyncgui.py b/kivy_venv/lib/python3.11/site-packages/asyncgui.py new file mode 100644 index 0000000..da09f01 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asyncgui.py @@ -0,0 +1,945 @@ +__all__ = ( + # core (exceptions) + 'ExceptionGroup', 'BaseExceptionGroup', 'InvalidStateError', 'Cancelled', + + # core + 'Aw_or_Task', 'start', 'Task', 'TaskState', 'disable_cancellation', 'open_cancel_scope', 'CancelScope', + 'dummy_task', 'current_task', '_current_task', 'sleep_forever', '_sleep_forever', + + # structured concurrency + 'wait_all', 'wait_any', 'and_', 'or_', 'wait_all_cm', 'wait_any_cm', 'move_on_when', + 'run_as_main', 'run_as_daemon', + 'open_nursery', 'Nursery', + + # bridge between async-world and sync-world + 'AsyncBox', 'AsyncEvent', + + # deprecated + 'Event', 'run_as_primary', 'run_as_secondary', +) +import types +import typing as T +from inspect import getcoroutinestate, CORO_CREATED, CORO_SUSPENDED, isawaitable +import sys +import itertools +from functools import cached_property, partial +import enum +from contextlib import asynccontextmanager + +# ----------------------------------------------------------------------------- +# Core +# ----------------------------------------------------------------------------- + +if sys.version_info < (3, 11): + from exceptiongroup import BaseExceptionGroup, ExceptionGroup +else: + BaseExceptionGroup = BaseExceptionGroup #: :meta private: + ExceptionGroup = ExceptionGroup #: :meta private: + +potential_bug_msg = \ + r"This may be a bug of this library. Please make a minimal code that reproduces the bug, and open an issue at " \ + r"the GitHub repository, then post the code there. (https://github.com/asyncgui/asyncgui)." + + +class InvalidStateError(Exception): + """The operation is not allowed in the current state.""" + + +class _Cancelled(BaseException): + @cached_property + def level(self) -> int: + return self.args[0] + + +Cancelled = (_Cancelled, GeneratorExit, ) +''' +Exception class that represents cancellation. +See :ref:`dealing-with-cancellation`. + +.. warning:: + + Actually, this is not an exception class but a tuple of exception classes for now. + But that's an implementation detail, and it might become an actual class in the future; + therefore, your code must be compatible in both cases. + +:meta hide-value: +''' + + +class TaskState(enum.Enum): + ''' + Enum class that represents the Task state. + ''' + + CREATED = enum.auto() + ''' + Waiting to start execution. + + :meta hide-value: + ''' + + STARTED = enum.auto() + ''' + Currently running or suspended. + + :meta hide-value: + ''' + + CANCELLED = enum.auto() + ''' + The execution has been cancelled. + The cause of cancellation can be either :meth:`Task.cancel` or an unhandled exception. + + :meta hide-value: + ''' + + FINISHED = enum.auto() + ''' + The execution has been completed. + + :meta hide-value: + ''' + + +_next_Task_uid = itertools.count().__next__ + + +class Task: + __slots__ = ( + '_uid', '_root_coro', '_state', '_result', '_on_end', + '_exc_caught', '_suppresses_exc', + '_cancel_disabled', '_cancel_depth', '_cancel_level', + ) + + def __init__(self, aw: T.Awaitable, /): + if not isawaitable(aw): + raise ValueError(str(aw) + " is not awaitable.") + self._uid = _next_Task_uid() + self._cancel_disabled = 0 + self._root_coro = self._wrapper(aw) + self._state = TaskState.CREATED + self._on_end = None + self._cancel_depth = 0 + self._cancel_level = None + self._exc_caught = None + self._suppresses_exc = False + + def __str__(self): + return f'Task(state={self._state.name}, uid={self._uid})' + + @property + def uid(self) -> int: + ''' + An unique integer assigned to the task. + This exists solely for inspection purposes. + ''' + return self._uid + + @property + def root_coro(self) -> T.Coroutine: + ''' + The starting point of the coroutine chain for the task. + This exists solely for inspection purposes. + ''' + return self._root_coro + + @property + def state(self) -> TaskState: + ''' + The current state of the task. + This exists solely for inspection purposes. + ''' + return self._state + + @property + def finished(self) -> bool: + '''Whether the task has been completed.''' + return self._state is TaskState.FINISHED + + @property + def cancelled(self) -> bool: + '''Whether the task has been cancelled.''' + return self._state is TaskState.CANCELLED + + @property + def result(self) -> T.Any: + '''Result of the task. If the task is not finished, :exc:`InvalidStateError` will be raised. ''' + state = self._state + if state is TaskState.FINISHED: + return self._result + elif state is TaskState.CANCELLED: + raise InvalidStateError(f"{self} was cancelled") + else: + raise InvalidStateError(f"Result of {self} is not ready") + + async def _wrapper(self, aw, /): + try: + self._state = TaskState.STARTED + self._result = await aw + except _Cancelled as e: + self._state = TaskState.CANCELLED + assert e.level == 0, potential_bug_msg + assert self._cancel_level == 0, potential_bug_msg + except Exception as e: + self._state = TaskState.CANCELLED + self._exc_caught = e + if not self._suppresses_exc: + raise + except: # noqa: E722 + self._state = TaskState.CANCELLED + raise + else: + self._state = TaskState.FINISHED + finally: + assert self._cancel_depth == 0, potential_bug_msg + if (on_end := self._on_end) is not None: + on_end(self) + + def cancel(self, _level=0, /): + '''Cancel the task as soon as possible.''' + if self._cancel_level is None: + self._cancel_level = _level + state = getcoroutinestate(self._root_coro) + if state is CORO_SUSPENDED: + if not self._cancel_disabled: + self._actual_cancel() + elif state is CORO_CREATED: + self._root_coro.close() + self._state = TaskState.CANCELLED + else: + self._cancel_level = min(self._cancel_level, _level) + + def _actual_cancel(self): + try: + self._root_coro.throw(_Cancelled(self._cancel_level))(self) + except StopIteration: + pass + else: + self._cancel_if_needed() + + close = cancel + '''An alias for :meth:`cancel`.''' + + @property + def _cancel_requested(self) -> bool: + return self._cancel_level is not None + + @property + def _is_cancellable(self) -> bool: + '''Whether the task can be cancelled immediately.''' + return (not self._cancel_disabled) and getcoroutinestate(self._root_coro) is CORO_SUSPENDED + + def _cancel_if_needed(self, getcoroutinestate=getcoroutinestate, CORO_SUSPENDED=CORO_SUSPENDED): + if (self._cancel_level is None) or self._cancel_disabled or \ + (getcoroutinestate(self._root_coro) is not CORO_SUSPENDED): + pass + else: + self._actual_cancel() + + def _step(self, *args, **kwargs): + coro = self._root_coro + if getcoroutinestate(coro) is not CORO_SUSPENDED: + return + try: + coro.send((args, kwargs, ))(self) + except StopIteration: + pass + else: + self._cancel_if_needed() + + def _throw_exc(self, exc): + '''停止中のTaskへ例外を投げる。Taskが停止中ではない場合は :exc:`InvalidStateError` が起こる。''' + coro = self._root_coro + if getcoroutinestate(coro) is not CORO_SUSPENDED: + raise InvalidStateError("Throwing an exception to an unstarted/running/closed task is not allowed.") + try: + coro.throw(exc)(self) + except StopIteration: + pass + else: + self._cancel_if_needed() + + +Aw_or_Task = T.Union[T.Awaitable, Task] + + +def start(aw: Aw_or_Task, /) -> Task: + '''*Immediately* start a Task/Awaitable. + + If the argument is a :class:`Task`, itself will be returned. If it's an :class:`typing.Awaitable`, + it will be wrapped in a Task, and that Task will be returned. + + .. code-block:: + + async def async_func(): + ... + + task = start(async_func()) + ''' + if isawaitable(aw): + task = Task(aw) + elif isinstance(aw, Task): + task = aw + if task._state is not TaskState.CREATED: + raise ValueError(f"{task} has already started") + else: + raise ValueError("Argument must be either a Task or an awaitable.") + + try: + task._root_coro.send(None)(task) + except StopIteration: + pass + else: + task._cancel_if_needed() + + return task + + +class CancelScope: + ''' + An equivalence of :class:`trio.CancelScope`. + You should not directly instantiate this, use :func:`open_cancel_scope`. + ''' + __slots__ = ('_task', '_level', 'cancelled_caught', 'cancel_called', ) + + def __init__(self, task: Task, /): + self._task = task + self.cancelled_caught = False #: Whether the scope caught a corresponding :class:`Cancelled` instance. + self.cancel_called = False #: Whether the :meth:`cancel` has been called. + + def __enter__(self) -> 'CancelScope': + t = self._task + t._cancel_depth = self._level = t._cancel_depth + 1 + return self + + def __exit__(self, exc_type, exc, __): + # LOAD_FAST + task = self._task + level = task._cancel_level + scope_level = self._level + + self._task = None + task._cancel_depth -= 1 + if level is not None: + if level == scope_level: + task._cancel_level = None + else: + assert level < scope_level, potential_bug_msg + if exc_type is not _Cancelled: + return + level = exc.level + if level == scope_level: + self.cancelled_caught = True + return True + else: + assert level < scope_level, potential_bug_msg + + @property + def closed(self) -> bool: + ''' + Whether this scope has been closed. + The cause of the closure of the scope can be either an exception occurred or the scope exited gracefully, + ''' + return self._task is None + + def cancel(self): + '''Cancel the execution inside this scope as soon as possible. ''' + if self.cancel_called: + return + self.cancel_called = True + if not self.closed: + self._task.cancel(self._level) + + +class open_cancel_scope: + ''' + Same as :class:`trio.CancelScope` except this one returns an async context manager. + + .. code-block:: + + async with open_cancel_scope() as scope: + ... + ''' + __slots__ = ('_scope', ) + + async def __aenter__(self) -> T.Awaitable[CancelScope]: + self._scope = CancelScope(await current_task()) + return self._scope.__enter__() + + async def __aexit__(self, *args): + return self._scope.__exit__(*args) + + +def _current_task(task): + return task._step(task) + + +@types.coroutine +def current_task(_f=_current_task) -> T.Awaitable[Task]: + '''Returns the Task instance corresponding to the caller. + + .. code-block:: + + task = await current_task() + ''' + return (yield _f)[0][0] + + +class disable_cancellation: + ''' + Return an async context manager that protects its code-block from cancellation. + + .. code-block:: + + async with disable_cancellation(): + await something # <- never gets cancelled + ''' + + __slots__ = ('_task', ) + + async def __aenter__(self): + self._task = task = await current_task() + task._cancel_disabled += 1 + + async def __aexit__(self, *__): + self._task._cancel_disabled -= 1 + + +def _sleep_forever(task): + pass + + +@types.coroutine +def sleep_forever(_f=_sleep_forever) -> T.Awaitable: + ''' + .. code-block:: + + await sleep_forever() + ''' + yield _f + + +dummy_task = Task(sleep_forever()) +''' +An already closed task. +This can be utilized to prevent the need for the common null validation mentioned below. + +*Before:* + +.. code-block:: + :emphasize-lines: 3, 6,7 + + class MyClass: + def __init__(self): + self._task = None + + def restart(self): + if self._task is not None: + self._task.cancel() + self._task = asyncgui.start(self.main()) + + async def main(self): + ... + +*After:* + +.. code-block:: + :emphasize-lines: 3, 6 + + class MyClass: + def __init__(self): + self._task = asyncgui.dummy_task + + def restart(self): + self._task.cancel() + self._task = asyncgui.start(self.main()) + + async def main(self): + ... +''' +dummy_task.cancel() + +# ----------------------------------------------------------------------------- +# Bridge between async-world and sync-world +# ----------------------------------------------------------------------------- + + +class AsyncEvent: + ''' + .. code-block:: + + async def async_fn(e): + args, kwargs = await e.wait() + assert args == (2, ) + assert kwargs == {'crow': 'raven', } + + args, kwargs = await e.wait() + assert args == (3, ) + assert kwargs == {'toad': 'frog', } + + e = AsyncEvent() + e.fire(1, crocodile='alligator') + start(async_fn(e)) + e.fire(2, crow='raven') + e.fire(3, toad='frog') + + .. warning:: + + This class is not designed for inter-task synchronization, unlike :class:`asyncio.Event`. + When multiple tasks simultaneously try to wait for the same event to fire, it will raise an exception. + ''' + __slots__ = ('_callback', ) + + def __init__(self): + self._callback = None + + def fire(self, *args, **kwargs): + if (f := self._callback) is not None: + f(*args, **kwargs) + + @types.coroutine + def wait(self): + if self._callback is not None: + raise InvalidStateError("There's already a task waiting for the event to fire.") + try: + return (yield self._attach_task) + finally: + self._callback = None + + def _attach_task(self, task): + self._callback = task._step + + +class AsyncBox: + ''' + .. code-block:: + + async def async_fn(b1, b2): + args, kwargs = await b1.get() + assert args == (1, ) + assert kwargs == {'crow': 'raven', } + + args, kwargs = await b2.get() + assert args == (2, ) + assert kwargs == {'frog': 'toad', } + + args, kwargs = await b1.get() + assert args == (1, ) + assert kwargs == {'crow': 'raven', } + + b1 = AsyncBox() + b2 = AsyncBox() + b1.put(1, crow='raven') + start(async_fn(b1, b2)) + b2.put(2, frog='toad') + + .. warning:: + + This class is not designed for inter-task synchronization, unlike :class:`asyncio.Event`. + When multiple tasks simultaneously try to get an item from the same box, it will raise an exception. + ''' + __slots__ = ('_item', '_callback', ) + + def __init__(self): + self._item = None + self._callback = None + + @property + def is_empty(self) -> bool: + '''Whether the box is empty.''' + return self._item is None + + def put(self, *args, **kwargs): + '''Put an item into the box if it's empty.''' + if self._item is None: + self.put_or_update(*args, **kwargs) + + def update(self, *args, **kwargs): + '''Replace the item in the box if there is one already.''' + if self._item is not None: + self.put_or_update(*args, **kwargs) + + def put_or_update(self, *args, **kwargs): + self._item = (args, kwargs, ) + if (callback := self._callback) is not None: + callback(*args, **kwargs) + + @types.coroutine + def get(self): + '''Get the item from the box if there is one. Otherwise, wait until it's put.''' + if self._callback is not None: + raise InvalidStateError("There's already a task waiting for an item to be put in the box.") + if self._item is None: + try: + return (yield self._attach_task) + finally: + self._callback = None + else: + return self._item + + def clear(self): + '''Remove the item from the box if there is one.''' + self._item = None + + _attach_task = AsyncEvent._attach_task + + +class Event: + ''' + Similar to :class:`asyncio.Event`. + The differences are: + + * :meth:`set` accepts any number of arguments but doesn't use them at all so it can be used as a callback function + in any library. + * :attr:`is_set` is a property not a function. + + .. code-block:: + + e = Event() + any_library.register_callback(e.set) + + .. deprecated:: 0.6.2 + + This class is deprecated, and will be removed before 1.0.0. + Use :class:`asyncgui_ext.synctools.event.Event` instead. + ''' + + __slots__ = ('_flag', '_waiting_tasks', ) + + def __init__(self): + self._flag = False + self._waiting_tasks = [] + + @property + def is_set(self) -> bool: + return self._flag + + def set(self, *args, **kwargs): + ''' + Set the event. + Unlike asyncio's, all tasks waiting for this event to be set will be resumed *immediately*. + ''' + if self._flag: + return + self._flag = True + tasks = self._waiting_tasks + self._waiting_tasks = [] + for t in tasks: + if t is not None: + t._step() + + def clear(self): + '''Unset the event.''' + self._flag = False + + @types.coroutine + def wait(self) -> T.Awaitable: + ''' + Wait for the event to be set. + Return *immediately* if it's already set. + ''' + if self._flag: + return + try: + tasks = self._waiting_tasks + idx = len(tasks) + yield tasks.append + finally: + tasks[idx] = None + + +# ----------------------------------------------------------------------------- +# Structured concurrency +# ----------------------------------------------------------------------------- + + +class TaskCounter: + ''' + (internal) + 数値が零になった事を通知する仕組みを持つカウンター。 + 親taskが自分の子task達の終了を待つのに用いる。 + ''' + + __slots__ = ('_box', '_n_tasks', ) + + def __init__(self, initial=0, /): + self._n_tasks = initial + self._box = AsyncBox() + + def increase(self): + self._n_tasks += 1 + + def decrease(self): + n = self._n_tasks - 1 + assert n >= 0, potential_bug_msg + self._n_tasks = n + if not n: + self._box.put() + + async def to_be_zero(self) -> T.Awaitable: + if self._n_tasks: + box = self._box + box._item = None + await box.get() + + def __bool__(self): + return not not self._n_tasks # 'not not' is not a typo + + +async def _wait_xxx(debug_msg, on_child_end, *aws: T.Iterable[Aw_or_Task]) -> T.Awaitable[T.Sequence[Task]]: + children = tuple(v if isinstance(v, Task) else Task(v) for v in aws) + if not children: + return children + counter = TaskCounter(len(children)) + parent = await current_task() + + try: + with CancelScope(parent) as scope: + on_child_end = partial(on_child_end, scope, counter) + for c in children: + c._suppresses_exc = True + c._on_end = on_child_end + start(c) + await counter.to_be_zero() + finally: + if counter: + for c in children: + c.cancel() + if counter: + try: + parent._cancel_disabled += 1 + await counter.to_be_zero() + finally: + parent._cancel_disabled -= 1 + exceptions = tuple(e for c in children if (e := c._exc_caught) is not None) + if exceptions: + raise ExceptionGroup(debug_msg, exceptions) + if (parent._cancel_level is not None) and (not parent._cancel_disabled): + await sleep_forever() + assert False, potential_bug_msg + return children + + +def _on_child_end__ver_all(scope, counter, child): + counter.decrease() + if child._exc_caught is not None: + scope.cancel() + + +def _on_child_end__ver_any(scope, counter, child): + counter.decrease() + if child._exc_caught is not None or child.finished: + scope.cancel() + + +_wait_xxx_type = T.Callable[..., T.Awaitable[T.Sequence[Task]]] +wait_all: _wait_xxx_type = partial(_wait_xxx, "wait_all()", _on_child_end__ver_all) +''' +Run multiple tasks concurrently, and wait for **all** of them to **end**. When any of them raises an exception, the +others will be cancelled, and the exception will be propagated to the caller, like :class:`trio.Nursery`. + +.. code-block:: + + tasks = await wait_all(async_fn1(), async_fn2(), async_fn3()) + if tasks[0].finished: + print("The return value of async_fn1() :", tasks[0].result) +''' +wait_any: _wait_xxx_type = partial(_wait_xxx, "wait_any()", _on_child_end__ver_any) +''' +Run multiple tasks concurrently, and wait for **any** of them to **finish**. As soon as that happens, the others will be +cancelled. When any of them raises an exception, the others will be cancelled, and the exception will be propagated to +the caller, like :class:`trio.Nursery`. + +.. code-block:: + + tasks = await wait_any(async_fn1(), async_fn2(), async_fn3()) + if tasks[0].finished: + print("The return value of async_fn1() :", tasks[0].result) +''' + + +@asynccontextmanager +async def _wait_xxx_cm(debug_msg, on_child_end, wait_bg, aw: Aw_or_Task): + counter = TaskCounter(1) + fg_task = await current_task() + bg_task = aw if isinstance(aw, Task) else Task(aw) + exc = None + + try: + with CancelScope(fg_task) as scope: + bg_task._on_end = partial(on_child_end, scope, counter) + bg_task._suppresses_exc = True + yield start(bg_task) + if wait_bg: + await counter.to_be_zero() + except Exception as e: + exc = e + finally: + bg_task.cancel() + if counter: + try: + fg_task._cancel_disabled += 1 + await counter.to_be_zero() + finally: + fg_task._cancel_disabled -= 1 + excs = tuple( + e for e in (exc, bg_task._exc_caught, ) + if e is not None + ) + if excs: + raise ExceptionGroup(debug_msg, excs) + if (fg_task._cancel_level is not None) and (not fg_task._cancel_disabled): + await sleep_forever() + assert False, potential_bug_msg + + +_wait_xxx_cm_type = T.Callable[[Aw_or_Task], T.AsyncContextManager[Task]] +wait_all_cm: _wait_xxx_cm_type = partial(_wait_xxx_cm, "wait_all_cm()", _on_child_end__ver_all, True) +''' +The context manager form of :func:`wait_all`. + +.. code-block:: + + async with wait_all_cm(async_fn()) as bg_task: + ... +''' +wait_any_cm: _wait_xxx_cm_type = partial(_wait_xxx_cm, "wait_any_cm()", _on_child_end__ver_any, False) +''' +The context manager form of :func:`wait_any`, an equivalence of :func:`trio_util.move_on_when`. + +.. code-block:: + + async with wait_any_cm(async_fn()) as bg_task: + ... +''' +run_as_main: _wait_xxx_cm_type = partial(_wait_xxx_cm, "run_as_main()", _on_child_end__ver_any, True) +''' +.. code-block:: + + async with run_as_main(async_fn()) as task: + ... + +.. note:: + + You need to use its older name, ``run_as_primary``, if you are using ``asyncgui`` 0.6.2 or older. +''' +run_as_daemon: _wait_xxx_cm_type = partial(_wait_xxx_cm, "run_as_daemon()", _on_child_end__ver_all, False) +''' +.. code-block:: + + async with run_as_daemon(async_fn()) as bg_task: + ... +''' + + +class Nursery: + ''' + Similar to :class:`trio.Nursery`. + You should not directly instantiate this, use :func:`open_nursery`. + ''' + + __slots__ = ('_closed', '_children', '_scope', '_counters', '_callbacks', '_gc_in_every', '_n_until_gc', ) + + def __init__(self, scope, counter, daemon_counter, gc_in_every): + self._gc_in_every = self._n_until_gc = gc_in_every + self._closed = False + self._children = [] + self._scope = scope + self._counters = (daemon_counter, counter, ) + self._callbacks = ( + partial(_on_child_end__ver_all, scope, daemon_counter), + partial(_on_child_end__ver_all, scope, counter), + ) + + def start(self, aw: Aw_or_Task, /, *, daemon=False) -> Task: + ''' + *Immediately* start a Task/Awaitable under the supervision of the nursery. + + If the argument is a :class:`Task`, itself will be returned. If it's an :class:`typing.Awaitable`, + it will be wrapped in a Task, and that Task will be returned. + + The ``daemon`` parameter acts like the one in the :mod:`threading` module. + When only daemon tasks are left, they get cancelled, and the nursery closes. + ''' + if self._closed: + raise InvalidStateError("Nursery has been already closed") + if not self._n_until_gc: + self._collect_garbage() + self._n_until_gc = self._gc_in_every + self._n_until_gc -= 1 + child = aw if isinstance(aw, Task) else Task(aw) + child._suppresses_exc = True + child._on_end = self._callbacks[not daemon] + self._counters[not daemon].increase() + self._children.append(child) + return start(child) + + def _collect_garbage(self, STARTED=TaskState.STARTED): + self._children = [ + c for c in self._children + if c.state is STARTED or c._exc_caught is not None + ] + + def close(self): + '''Cancel all the child tasks in the nursery as soon as possible. ''' + self._closed = True + self._scope.cancel() + + @property + def closed(self) -> bool: + return self._closed + + +@asynccontextmanager +async def open_nursery(*, _gc_in_every=1000) -> T.AsyncIterator[Nursery]: + ''' + Similar to :func:`trio.open_nursery`. + + .. code-block:: + + async with open_nursery() as nursery: + nursery.start(async_fn1()) + nursery.start(async_fn2(), daemon=True) + ''' + exc = None + parent = await current_task() + counter = TaskCounter() + daemon_counter = TaskCounter() + + try: + with CancelScope(parent) as scope: + nursery = Nursery(scope, counter, daemon_counter, _gc_in_every) + yield nursery + await counter.to_be_zero() + except Exception as e: + exc = e + finally: + nursery._closed = True + children = nursery._children + for c in children: + c.cancel() + try: + parent._cancel_disabled += 1 + await daemon_counter.to_be_zero() + await counter.to_be_zero() + finally: + parent._cancel_disabled -= 1 + excs = tuple( + e for e in itertools.chain((exc, ), (c._exc_caught for c in children)) + if e is not None + ) + if excs: + raise ExceptionGroup("Nursery", excs) + if (parent._cancel_level is not None) and (not parent._cancel_disabled): + await sleep_forever() + assert False, potential_bug_msg + + +# ----------------------------------------------------------------------------- +# Aliases +# ----------------------------------------------------------------------------- +run_as_primary = run_as_main +run_as_secondary = run_as_daemon +and_ = wait_all #: An alias for :func:`wait_all`. +or_ = wait_any #: An alias for :func:`wait_any`. +move_on_when = wait_any_cm #: An alias for :func:`wait_any_cm`. diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/INSTALLER b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/LICENSE b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/LICENSE new file mode 100644 index 0000000..4f113c4 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/LICENSE @@ -0,0 +1,7 @@ +Copyright 2019 gottadiveintopython + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/METADATA b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/METADATA new file mode 100644 index 0000000..1cc4a2c --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/METADATA @@ -0,0 +1,177 @@ +Metadata-Version: 2.1 +Name: asynckivy +Version: 0.6.4 +Summary: Async library for Kivy +Home-page: https://github.com/asyncgui/asynckivy +License: MIT +Keywords: async,kivy +Author: Nattōsai Mitō +Author-email: flow4re2c@gmail.com +Requires-Python: >=3.9,<4.0 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Topic :: Software Development :: Libraries +Requires-Dist: asyncgui (>=0.6,<0.7) +Project-URL: Repository, https://github.com/asyncgui/asynckivy +Description-Content-Type: text/markdown + +# AsyncKivy + +[Youtube](https://www.youtube.com/playlist?list=PLNdhqAjzeEGjTpmvNck4Uykps8s9LmRTJ) +[日本語doc](README_jp.md) + +`asynckivy` is an async library that saves you from ugly callback-style code, +like most of async libraries do. +Let's say you want to do: + +1. `print('A')` +1. wait for 1sec +1. `print('B')` +1. wait for a button to be pressed +1. `print('C')` + +in that order. +Your code would look like this: + +```python +from kivy.clock import Clock + +def what_you_want_to_do(button): + print('A') + + def one_sec_later(__): + print('B') + button.bind(on_press=on_button_press) + Clock.schedule_once(one_sec_later, 1) + + def on_button_press(button): + button.unbind(on_press=on_button_press) + print('C') + +what_you_want_to_do(...) +``` + +It's not easy to understand. +If you use `asynckivy`, the code above will become: + +```python +import asynckivy as ak + +async def what_you_want_to_do(button): + print('A') + await ak.sleep(1) + print('B') + await ak.event(button, 'on_press') + print('C') + +ak.start(what_you_want_to_do(...)) +``` + +## Installation + +Pin the minor version. + +```text +poetry add asynckivy@~0.6 +pip install "asynckivy>=0.6,<0.7" +``` + +## Usage + +```python +import asynckivy as ak + +async def some_task(button): + # waits for 2 seconds to elapse + dt = await ak.sleep(2) + print(f'{dt} seconds have elapsed') + + # waits for a button to be pressed + await ak.event(button, 'on_press') + + # waits for the value of 'button.x' to change + __, x = await ak.event(button, 'x') + print(f'button.x is now {x}') + + # waits for the value of 'button.x' to become greater than 100 + if button.x <= 100: + __, x = await ak.event(button, 'x', filter=lambda __, x: x>100) + print(f'button.x is now {x}') + + # waits for either 5 seconds to elapse or a button to be pressed. + # i.e. waits at most 5 seconds for a button to be pressed + tasks = await ak.wait_any( + ak.sleep(5), + ak.event(button, 'on_press'), + ) + print("Timeout" if tasks[0].finished else "The button was pressed") + + # same as the above + async with ak.move_on_after(5) as bg_task: + await ak.event(button, 'on_press') + print("Timeout" if bg_task.finished else "The button was pressed") + + # waits for both 5 seconds to elapse and a button to be pressed. + tasks = await ak.wait_all( + ak.sleep(5), + ak.event(button, 'on_press'), + ) + + # nest as you want. + # waits for a button to be pressed, and either 5 seconds to elapse or 'other_async_func' to complete. + tasks = await ak.wait_all( + ak.event(button, 'on_press'), + ak.wait_any( + ak.sleep(5), + other_async_func(), + ), + ) + child_tasks = tasks[1].result + print("5 seconds elapsed" if child_tasks[0].finished else "other_async_func has completed") + +ak.start(some_task(some_button)) +``` + +For more details, read the [documentation](https://asyncgui.github.io/asynckivy/). + +## Tested on + +- CPython 3.8 + Kivy 2.3.0 +- CPython 3.9 + Kivy 2.3.0 +- CPython 3.10 + Kivy 2.3.0 +- CPython 3.11 + Kivy 2.3.0 +- CPython 3.12 + Kivy 2.3.0 (3.12.0 is not supported due to [this issue](https://github.com/python/cpython/issues/111058)) + +## Why this even exists + +Kivy supports two legitimate async libraries, [asyncio][asyncio] and [Trio][trio], starting from version 2.0.0, so developing another one seems like [reinventing the wheel][reinventing]. +Actually, I started this one just to learn how the async/await syntax works, so it initially was "reinventing the wheel". + +But after playing with Trio and Kivy for a while, I noticed that Trio is not suitable for the situation where fast reactions are required e.g. touch events. +The same is true of asyncio. +You can confirm that by running `investigation/why_xxx_is_not_suitable_for_handling_touch_events.py`, and mashing a mouse button as quickly as possible. +You'll see sometimes `up` is not paired with `down`. +You'll see the coordinates aren't relative to the `RelativeLayout` even though the `target` belongs to it. + +The cause of those problems is that `trio.Event.set()` and `asyncio.Event.set()` don't *immediately* resume the tasks waiting for the `Event` to be set. +They just schedule the tasks to resume. +Same thing can be said to `nursery.start_soon()` and `asyncio.create_task()`. + +Trio and asyncio are async **I/O** libraries after all. +They probably don't have to immediately resumes/starts tasks, which I think necessary for touch handling in Kivy. +(If you fail to handle touches promptly, their state might undergo changes, leaving no time to wait for tasks to resume/start). +Their core design might not be suitable for GUI in the first place. +That's why I'm still developing this `asynckivy` library to this day. + +[asyncio]:https://docs.python.org/3/library/asyncio.html +[trio]:https://trio.readthedocs.io/en/stable/ +[reinventing]:https://en.wikipedia.org/wiki/Reinventing_the_wheel + diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/RECORD b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/RECORD new file mode 100644 index 0000000..b40079e --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/RECORD @@ -0,0 +1,31 @@ +asynckivy-0.6.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +asynckivy-0.6.4.dist-info/LICENSE,sha256=2jxtLdIltPBFl7vb9bLmquYKRJiyidCvO_DhOgFWIe8,1059 +asynckivy-0.6.4.dist-info/METADATA,sha256=P3n9htW_NrrBuy5BHojYoUgkePfNn2y4h__APrwdK5w,5876 +asynckivy-0.6.4.dist-info/RECORD,, +asynckivy-0.6.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88 +asynckivy/__init__.py,sha256=Ttzd2FLPuQEAPrNINViuIK8Yj4i5swu2wKKkl0vCMoA,1285 +asynckivy/__pycache__/__init__.cpython-311.pyc,, +asynckivy/__pycache__/_anim_attrs.cpython-311.pyc,, +asynckivy/__pycache__/_anim_with_xxx.cpython-311.pyc,, +asynckivy/__pycache__/_animation.cpython-311.pyc,, +asynckivy/__pycache__/_event.cpython-311.pyc,, +asynckivy/__pycache__/_exceptions.cpython-311.pyc,, +asynckivy/__pycache__/_interpolate.cpython-311.pyc,, +asynckivy/__pycache__/_n_frames.cpython-311.pyc,, +asynckivy/__pycache__/_sleep.cpython-311.pyc,, +asynckivy/__pycache__/_threading.cpython-311.pyc,, +asynckivy/__pycache__/_touch.cpython-311.pyc,, +asynckivy/__pycache__/_utils.cpython-311.pyc,, +asynckivy/__pycache__/vanim.cpython-311.pyc,, +asynckivy/_anim_attrs.py,sha256=VCWAPMFtwZU4HOdfhcFDR1JIvjMDW-nuaSvn2MAnu3Q,3838 +asynckivy/_anim_with_xxx.py,sha256=IzJ-NYCJI9mFgOH1oRtZ0VLcsIY7TNjf88VuaoU9Lo4,3516 +asynckivy/_animation.py,sha256=6J2vwvXXJJegLk48nx4KrHYrZM5uZiulE6pTH4n9A4U,3589 +asynckivy/_event.py,sha256=_1O6bKZXZKkV5a-i4Qo3pmZHU1jCobf6bwIS9TUJG-U,1711 +asynckivy/_exceptions.py,sha256=Pg2qkGaVbF2OgVrfcxqOPobEgvavAPYr4RZRDtvyV-o,764 +asynckivy/_interpolate.py,sha256=ojjQhiND4-rkTol5q79R2eblXL-2XhQPQMzWovSkDoU,2252 +asynckivy/_n_frames.py,sha256=Rwtc-9nVBGT-IT5dRwQBowAS0ENBEnrzQKxVhPp4qoE,868 +asynckivy/_sleep.py,sha256=qiNN_4PUJiz8pxnLqUykHSLcZhSLuLnHnfekTTEKDWQ,3354 +asynckivy/_threading.py,sha256=onV5x3H0qfDYzHs3PRIprxlJR3dpSbdZWjjChRXI35E,1621 +asynckivy/_touch.py,sha256=C_Z3qoYNVPE-KWYrc56Q4Uj79sLK2V0L_6Pj6ZTdPYU,7669 +asynckivy/_utils.py,sha256=qr4__ywCImXrfNdxnxAfn7PLux1KGAwWud_Pzb9ixVo,7705 +asynckivy/vanim.py,sha256=-9kRfu3yJsKX8Z4xp8Wm6cOfUxzg54oeohUDV1FKktA,608 diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/WHEEL b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/WHEEL new file mode 100644 index 0000000..d73ccaa --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy-0.6.4.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: poetry-core 1.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__init__.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/__init__.py new file mode 100644 index 0000000..9ea8d91 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/__init__.py @@ -0,0 +1,42 @@ +__all__ = ( + 'MotionEventAlreadyEndedError', + 'anim_attrs', + 'anim_attrs_abbr', + 'anim_with_dt', + 'anim_with_dt_et', + 'anim_with_dt_et_ratio', + 'anim_with_et', + 'anim_with_ratio', + 'animate', + 'create_texture_from_text', + 'event', + 'fade_transition', + 'interpolate', + 'move_on_after', + 'n_frames', + 'repeat_sleeping', + 'rest_of_touch_events', + 'run_in_executor', + 'run_in_thread', + 'sleep', + 'sleep_free', + 'suppress_event', + 'sync_attr', + 'sync_attrs', + 'touch_up_event', + 'transform', + 'watch_touch', +) + +from asyncgui import * +from ._exceptions import MotionEventAlreadyEndedError +from ._sleep import sleep, sleep_free, repeat_sleeping, move_on_after +from ._event import event +from ._anim_with_xxx import anim_with_dt, anim_with_et, anim_with_ratio, anim_with_dt_et, anim_with_dt_et_ratio +from ._animation import animate +from ._anim_attrs import anim_attrs, anim_attrs_abbr +from ._interpolate import interpolate, fade_transition +from ._touch import watch_touch, rest_of_touch_events, rest_of_touch_moves, touch_up_event +from ._threading import run_in_executor, run_in_thread +from ._n_frames import n_frames +from ._utils import transform, suppress_event, create_texture_from_text, sync_attr, sync_attrs diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..cb01734 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_anim_attrs.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_anim_attrs.cpython-311.pyc new file mode 100644 index 0000000..0c78636 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_anim_attrs.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_anim_with_xxx.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_anim_with_xxx.cpython-311.pyc new file mode 100644 index 0000000..2a009b5 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_anim_with_xxx.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_animation.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_animation.cpython-311.pyc new file mode 100644 index 0000000..d8a1b54 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_animation.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_event.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_event.cpython-311.pyc new file mode 100644 index 0000000..986515e Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_event.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_exceptions.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_exceptions.cpython-311.pyc new file mode 100644 index 0000000..2ded891 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_exceptions.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_interpolate.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_interpolate.cpython-311.pyc new file mode 100644 index 0000000..07eda71 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_interpolate.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_n_frames.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_n_frames.cpython-311.pyc new file mode 100644 index 0000000..5921471 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_n_frames.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_sleep.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_sleep.cpython-311.pyc new file mode 100644 index 0000000..aa10265 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_sleep.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_threading.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_threading.cpython-311.pyc new file mode 100644 index 0000000..fdefe0c Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_threading.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_touch.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_touch.cpython-311.pyc new file mode 100644 index 0000000..0bfeeba Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_touch.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_utils.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_utils.cpython-311.pyc new file mode 100644 index 0000000..03c56a1 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/_utils.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/vanim.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/vanim.cpython-311.pyc new file mode 100644 index 0000000..881c65c Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/asynckivy/__pycache__/vanim.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_anim_attrs.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_anim_attrs.py new file mode 100644 index 0000000..da85092 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_anim_attrs.py @@ -0,0 +1,114 @@ +__all__ = ('anim_attrs', 'anim_attrs_abbr', ) +import typing as T +import types +from functools import partial +import kivy.clock +from kivy.animation import AnimationTransition +import asyncgui + + +def _update(setattr, zip, min, obj, duration, transition, output_seq_type, anim_params, task, p_time, dt): + time = p_time[0] + dt + p_time[0] = time + + # calculate progression + progress = min(1., time / duration) + t = transition(progress) + + # apply progression on obj + for attr_name, org_value, slope, is_seq in anim_params: + if is_seq: + new_value = output_seq_type( + slope_elem * t + org_elem + for org_elem, slope_elem in zip(org_value, slope) + ) + setattr(obj, attr_name, new_value) + else: + setattr(obj, attr_name, slope * t + org_value) + + # time to stop ? + if progress >= 1.: + task._step() + return False + + +_update = partial(_update, setattr, zip, min) + + +@types.coroutine +def _anim_attrs( + obj, duration, step, transition, output_seq_type, animated_properties, + getattr=getattr, isinstance=isinstance, tuple=tuple, str=str, partial=partial, native_seq_types=(tuple, list), + zip=zip, Clock=kivy.clock.Clock, AnimationTransition=AnimationTransition, + _update=_update, _current_task=asyncgui._current_task, _sleep_forever=asyncgui._sleep_forever, /): + if isinstance(transition, str): + transition = getattr(AnimationTransition, transition) + + # get current values & calculate slopes + anim_params = tuple( + ( + org_value := getattr(obj, attr_name), + is_seq := isinstance(org_value, native_seq_types), + ( + org_value := tuple(org_value), + slope := tuple(goal_elem - org_elem for goal_elem, org_elem in zip(goal_value, org_value)), + ) if is_seq else (slope := goal_value - org_value), + ) and (attr_name, org_value, slope, is_seq, ) + for attr_name, goal_value in animated_properties.items() + ) + + try: + clock_event = Clock.schedule_interval( + partial(_update, obj, duration, transition, output_seq_type, anim_params, (yield _current_task)[0][0], + [0., ]), + step, + ) + yield _sleep_forever + finally: + clock_event.cancel() + + +def anim_attrs(obj, *, duration=1.0, step=0, transition=AnimationTransition.linear, output_seq_type=tuple, + **animated_properties) -> T.Awaitable: + ''' + Animates attibutes of any object. + + .. code-block:: + + import types + + obj = types.SimpleNamespace(x=0, size=(200, 300)) + await anim_attrs(obj, x=100, size=(400, 400)) + + The ``output_seq_type`` parameter: + + .. code-block:: + + obj = types.SimpleNamespace(size=(200, 300)) + await anim_attrs(obj, size=(400, 400), output_seq_type=list) + assert type(obj.size) is list + + .. warning:: + + Unlike :class:`kivy.animation.Animation`, this one does not support dictionary-type and nested-sequence. + + .. code-block:: + + await anim_attrs(obj, pos_hint={'x': 1.}) # not supported + await anim_attrs(obj, nested_sequence=[[10, 20, ]]) # not supported + + await anim_attrs(obj, color=(1, 0, 0, 1), pos=(100, 200)) # OK + + .. versionadded:: 0.6.1 + ''' + return _anim_attrs(obj, duration, step, transition, output_seq_type, animated_properties) + + +def anim_attrs_abbr(obj, *, d=1.0, s=0, t=AnimationTransition.linear, output_seq_type=tuple, + **animated_properties) -> T.Awaitable: + ''' + :func:`anim_attrs` cannot animate attributes named ``step``, ``duration`` and ``transition`` but this one can. + + .. versionadded:: 0.6.1 + ''' + return _anim_attrs(obj, d, s, t, output_seq_type, animated_properties) diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_anim_with_xxx.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_anim_with_xxx.py new file mode 100644 index 0000000..97f104c --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_anim_with_xxx.py @@ -0,0 +1,146 @@ +__all__ = ( + 'anim_with_dt', 'anim_with_et', 'anim_with_ratio', 'anim_with_dt_et', 'anim_with_dt_et_ratio', +) + +from ._sleep import repeat_sleeping + + +async def anim_with_dt(*, step=0): + ''' + An async form of :meth:`kivy.clock.Clock.schedule_interval`. The following callback-style code: + + .. code-block:: + + def callback(dt): + print(dt) + if some_condition: + return False + + Clock.schedule_interval(callback, 0.1) + + is equivalent to the following async-style code: + + .. code-block:: + + async for dt in anim_with_dt(step=0.1): + print(dt) + if some_condition: + break + + .. versionadded:: 0.6.1 + ''' + async with repeat_sleeping(step=step) as sleep: + while True: + yield await sleep() + + +async def anim_with_et(*, step=0): + ''' + Same as :func:`anim_with_dt` except this one generates the total elapsed time of the loop instead of the elapsed + time between frames. + + .. code-block:: + + timeout = 3.0 + async for et in anim_with_et(...): + ... + if et > timeout: + break + + You can calculate ``et`` by yourself if you want to: + + .. code-block:: + + et = 0. + timeout = 3.0 + async for dt in anim_with_dt(...): + et += dt + ... + if et > timeout: + break + + which should be as performant as the former. + + .. versionadded:: 0.6.1 + ''' + et = 0. + async with repeat_sleeping(step=step) as sleep: + while True: + et += await sleep() + yield et + + +async def anim_with_dt_et(*, step=0): + ''' + :func:`anim_with_dt` and :func:`anim_with_et` combined. + + .. code-block:: + + async for dt, et in anim_with_dt_et(...): + ... + + .. versionadded:: 0.6.1 + ''' + et = 0. + async with repeat_sleeping(step=step) as sleep: + while True: + dt = await sleep() + et += dt + yield dt, et + + +async def anim_with_ratio(*, duration=1., step=0): + ''' + Same as :func:`anim_with_et` except this one generates the total progression ratio of the loop. + + .. code-block:: + + async for p in anim_with_ratio(duration=3.0): + print(p * 100, "%") + + If you want to progress at a non-consistant rate, :class:`kivy.animation.AnimationTransition` may be helpful. + + .. code-block:: + + from kivy.animation import AnimationTransition + + in_cubic = AnimationTransition.in_cubic + + async for p in anim_with_ratio(duration=3.0): + p = in_cubic(p) + print(p * 100, "%") + + .. versionadded:: 0.6.1 + ''' + async with repeat_sleeping(step=step) as sleep: + if not duration: + await sleep() + yield 1.0 + return + et = 0. + while et < duration: + et += await sleep() + yield et / duration + + +async def anim_with_dt_et_ratio(*, duration=1., step=0): + ''' + :func:`anim_with_dt`, :func:`anim_with_et` and :func:`anim_with_ratio` combined. + + .. code-block:: + + async for dt, et, p in anim_with_dt_et_ratio(...): + ... + + .. versionadded:: 0.6.1 + ''' + async with repeat_sleeping(step=step) as sleep: + if not duration: + dt = await sleep() + yield dt, dt, 1.0 + return + et = 0. + while et < duration: + dt = await sleep() + et += dt + yield dt, et, et / duration diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_animation.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_animation.py new file mode 100644 index 0000000..9c19a68 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_animation.py @@ -0,0 +1,115 @@ +__all__ = ('animate', ) +import typing as T +import types +from functools import partial +from kivy.clock import Clock +from kivy.animation import AnimationTransition +from asyncgui import _sleep_forever, _current_task + + +@types.coroutine +def animate(obj, *, duration=1.0, step=0, transition=AnimationTransition.linear, **animated_properties) -> T.Awaitable: + ''' + Animates attibutes of any object. This is basically an async form of :class:`kivy.animation.Animation`. + + .. code-block:: + + import types + + obj = types.SimpleNamespace(x=0, size=(200, 300, )) + await animate(obj, x=100, size=(400, 400)) + + Kivy has two compound animations, :class:`kivy.animation.Sequence` and :class:`kivy.animation.Parallel`. + You can achieve the same functionality as them in asynckivy as follows: + + .. code-block:: + + import asynckivy as ak + + async def sequential_animation(widget): + await ak.animate(widget, x=100) + await ak.animate(widget, x=0) + + async def parallel_animation(widget): + await ak.wait_all( + ak.animate(widget, x=100), + ak.animate(widget, y=100, duration=2), + ) + + .. deprecated:: 0.6.1 + + This will be removed before version 1.0.0. + Use :func:`asynckivy.anim_attrs` or :func:`asynckivy.anim_attrs_abbr` instead. + ''' + if not duration: + for key, value in animated_properties.items(): + setattr(obj, key, value) + return + if isinstance(transition, str): + transition = getattr(AnimationTransition, transition) + + # get current values + properties = {} + for key, value in animated_properties.items(): + original_value = getattr(obj, key) + if isinstance(original_value, (tuple, list)): + original_value = original_value[:] + elif isinstance(original_value, dict): + original_value = original_value.copy() + properties[key] = (original_value, value) + + try: + clock_event = Clock.schedule_interval( + partial(_update, obj, duration, transition, properties, (yield _current_task)[0][0], [0., ]), + step, + ) + yield _sleep_forever + finally: + clock_event.cancel() + + +def _calculate(isinstance, list, tuple, dict, range, len, a, b, t): + '''The logic of this function is identical to 'kivy.animation.Animation._calculate()' + ''' + if isinstance(a, list) or isinstance(a, tuple): + if isinstance(a, list): + tp = list + else: + tp = tuple + return tp([_calculate(a[x], b[x], t) for x in range(len(a))]) + elif isinstance(a, dict): + d = {} + for x in a: + if x not in b: + # User requested to animate only part of the dict. + # Copy the rest + d[x] = a[x] + else: + d[x] = _calculate(a[x], b[x], t) + return d + else: + return (a * (1. - t)) + (b * t) + + +def _update(setattr, _calculate, obj, duration, transition, properties, task, p_time, dt): + time = p_time[0] + dt + p_time[0] = time + + # calculate progression + progress = min(1., time / duration) + t = transition(progress) + + # apply progression on obj + for key, values in properties.items(): + a, b = values + value = _calculate(a, b, t) + setattr(obj, key, value) + + # time to stop ? + if progress >= 1.: + task._step() + return False + + +_calculate = partial(_calculate, isinstance, list, tuple, dict, range, len) +_update = partial(_update, setattr, _calculate) diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_event.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_event.py new file mode 100644 index 0000000..b03637b --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_event.py @@ -0,0 +1,57 @@ +__all__ = ('event', ) + +import typing as T +import types +from functools import partial +from asyncgui import _current_task, _sleep_forever + + +@types.coroutine +def event(event_dispatcher, event_name, *, filter=None, stop_dispatching=False) -> T.Awaitable[tuple]: + ''' + Returns an awaitable that can be used to wait for: + + * a Kivy event to occur. + * a Kivy property's value to change. + + .. code-block:: + + # Wait for a button to be pressed. + await event(button, 'on_press') + + # Wait for an 'on_touch_down' event to occur. + __, touch = await event(widget, 'on_touch_down') + + # Wait for 'widget.x' to change. + __, x = await ak.event(widget, 'x') + + + The ``filter`` parameter: + + .. code-block:: + + # Wait for an 'on_touch_down' event to occur inside a widget. + __, touch = await event(widget, 'on_touch_down', filter=lambda w, t: w.collide_point(*t.opos)) + + # Wait for 'widget.x' to become greater than 100. + if widget.x <= 100: + await event(widget, 'x', filter=lambda __, x: x > 100) + + The ``stop_dispatching`` parameter: + + It only works for events not for properties. + See :ref:`kivys-event-system` for details. + ''' + task = (yield _current_task)[0][0] + bind_id = event_dispatcher.fbind(event_name, partial(_callback, filter, task, stop_dispatching)) + assert bind_id # check if binding succeeded + try: + return (yield _sleep_forever)[0] + finally: + event_dispatcher.unbind_uid(event_name, bind_id) + + +def _callback(filter, task, stop_dispatching, *args, **kwargs): + if (filter is None) or filter(*args, **kwargs): + task._step(*args) + return stop_dispatching diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_exceptions.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_exceptions.py new file mode 100644 index 0000000..3fc7eaf --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_exceptions.py @@ -0,0 +1,27 @@ +__all__ = ( + 'MotionEventAlreadyEndedError', +) + + +class MotionEventAlreadyEndedError(Exception): + ''' + This error occurs when an already-ended touch is passed to an asynckivy API that expects an ongoing touch. + For instance: + + .. code-block:: + :emphasize-lines: 4 + + import asynckivy as ak + + class MyWidget(Widget): + def on_touch_up(self, touch): # not 'on_touch_down', oops! + ak.start(self.handle_touch(touch)) + return True + + async def handle_touch(self, touch): + try: + async for __ in ak.rest_of_touch_events(widget, touch): + ... + except ak.MotionEventAlreadyEndedError: + ... + ''' diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_interpolate.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_interpolate.py new file mode 100644 index 0000000..193e520 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_interpolate.py @@ -0,0 +1,75 @@ +__all__ = ('interpolate', 'fade_transition', ) +import typing as T +from contextlib import asynccontextmanager +from kivy.animation import AnimationTransition + +from ._anim_with_xxx import anim_with_ratio + + +linear = AnimationTransition.linear + + +async def interpolate(start, end, *, duration=1.0, step=0, transition=linear) -> T.AsyncIterator: + ''' + Interpolates between the values ``start`` and ``end`` in an async-manner. + Inspired by wasabi2d's interpolate_. + + .. code-block:: + + async for v in interpolate(0, 100, duration=1.0, step=.3): + print(int(v)) + + ============ ====== + elapsed time output + ============ ====== + 0 sec 0 + 0.3 sec 30 + 0.6 sec 60 + 0.9 sec 90 + **1.2 sec** 100 + ============ ====== + + .. _interpolate: https://wasabi2d.readthedocs.io/en/stable/coros.html#clock.coro.interpolate + ''' + if isinstance(transition, str): + transition = getattr(AnimationTransition, transition) + + slope = end - start + yield transition(0.) * slope + start + async for p in anim_with_ratio(step=step, duration=duration): + if p >= 1.0: + break + yield transition(p) * slope + start + yield transition(1.) * slope + start + + +@asynccontextmanager +async def fade_transition(*widgets, duration=1.0, step=0) -> T.AsyncContextManager: + ''' + Returns an async context manager that: + + * fades-out the given widgets on ``__aenter__``. + * fades-in the given widgets on ``__aexit__``. + + .. code-block:: + + async with fade_transition(widget1, widget2): + ... + + The ``widgets`` don't have to be actual Kivy widgets. + Anything that has an attribute named ``opacity`` would work. + ''' + half_duration = duration / 2. + org_opas = tuple(w.opacity for w in widgets) + try: + async for p in anim_with_ratio(duration=half_duration, step=step): + p = 1.0 - p + for w, o in zip(widgets, org_opas): + w.opacity = p * o + yield + async for p in anim_with_ratio(duration=half_duration, step=step): + for w, o in zip(widgets, org_opas): + w.opacity = p * o + finally: + for w, o in zip(widgets, org_opas): + w.opacity = o diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_n_frames.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_n_frames.py new file mode 100644 index 0000000..7d91868 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_n_frames.py @@ -0,0 +1,43 @@ +__all__ = ('n_frames', ) + +import typing as T +import types +from kivy.clock import Clock +from asyncgui import _current_task, _sleep_forever + + +@types.coroutine +def n_frames(n: int) -> T.Awaitable: + ''' + Waits for a specified number of frames. + + .. code-block:: + + await n_frames(2) + + If you want to wait for one frame, :func:`asynckivy.sleep` is preferable for a performance reason. + + .. code-block:: + + await sleep(0) + ''' + if n < 0: + raise ValueError(f"Waiting for {n} frames doesn't make sense.") + if not n: + return + + task = (yield _current_task)[0][0] + + def callback(dt): + nonlocal n + n -= 1 + if not n: + task._step() + return False + + clock_event = Clock.schedule_interval(callback, 0) + + try: + yield _sleep_forever + finally: + clock_event.cancel() diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_sleep.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_sleep.py new file mode 100644 index 0000000..d25e33e --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_sleep.py @@ -0,0 +1,125 @@ +__all__ = ('sleep', 'sleep_free', 'repeat_sleeping', 'move_on_after', ) + +import typing as T +import types + +from kivy.clock import Clock +from asyncgui import _current_task, _sleep_forever, move_on_when, Task, Cancelled + + +@types.coroutine +def sleep(duration) -> T.Awaitable[float]: + ''' + An async form of :meth:`kivy.clock.Clock.schedule_once`. + + .. code-block:: + + dt = await sleep(5) # wait for 5 seconds + ''' + task = (yield _current_task)[0][0] + clock_event = Clock.create_trigger(task._step, duration, False, False) + clock_event() + + try: + return (yield _sleep_forever)[0][0] + except Cancelled: + clock_event.cancel() + raise + + +@types.coroutine +def sleep_free(duration) -> T.Awaitable[float]: + ''' + An async form of :meth:`kivy.clock.Clock.schedule_once_free`. + + .. code-block:: + + dt = await sleep_free(5) # wait for 5 seconds + ''' + task = (yield _current_task)[0][0] + clock_event = Clock.create_trigger_free(task._step, duration, False, False) + clock_event() + + try: + return (yield _sleep_forever)[0][0] + except Cancelled: + clock_event.cancel() + raise + + +class repeat_sleeping: + ''' + Returns an async context manager that provides an efficient way to repeat sleeping. + + When there is a piece of code like this: + + .. code-block:: + + while True: + await sleep(0) + ... + + it can be translated to: + + .. code-block:: + + async with repeat_sleeping(step=0) as sleep: + while True: + await sleep() + ... + + The latter is more suitable for situations requiring frequent sleeps, such as moving an object in every frame. + + **Restriction** + + You are not allowed to perform any kind of async operations inside the with-block except you can + ``await`` the return value of the function that is bound to the identifier of the as-clause. + + .. code-block:: + + async with repeat_sleeping(step=0) as sleep: + await sleep() # OK + await something_else # NOT ALLOWED + async with async_context_manager: # NOT ALLOWED + ... + async for __ in async_iterator: # NOT ALLOWED + ... + ''' + + __slots__ = ('_step', '_trigger', ) + + @types.coroutine + def _sleep(_f=_sleep_forever): + return (yield _f)[0][0] + + def __init__(self, *, step=0): + self._step = step + + @types.coroutine + def __aenter__(self, _sleep=_sleep) -> T.Awaitable[T.Callable[[], T.Awaitable[float]]]: + task = (yield _current_task)[0][0] + self._trigger = Clock.create_trigger(task._step, self._step, True, False) + self._trigger() + return _sleep + + async def __aexit__(self, exc_type, exc_val, exc_tb): + self._trigger.cancel() + + +def move_on_after(seconds: float) -> T.AsyncContextManager[Task]: + ''' + Returns an async context manager that applies a time limit to its code block, + like :func:`trio.move_on_after` does. + + .. code-block:: + + async with move_on_after(seconds) as bg_task: + ... + if bg_task.finished: + print("The code block was interrupted due to a timeout") + else: + print("The code block exited gracefully.") + + .. versionadded:: 0.6.1 + ''' + return move_on_when(sleep(seconds)) diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_threading.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_threading.py new file mode 100644 index 0000000..7094fad --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_threading.py @@ -0,0 +1,64 @@ +__all__ = ('run_in_thread', 'run_in_executor', ) +import typing as T +from threading import Thread +from concurrent.futures import ThreadPoolExecutor +from kivy.clock import Clock +import asyncgui + + +def _wrapper(func, ev): + ret = None + exc = None + try: + ret = func() + except Exception as e: + exc = e + finally: + Clock.schedule_once(lambda __: ev.fire(ret, exc)) + + +async def run_in_thread(func, *, daemon=None) -> T.Awaitable: + ''' + Creates a new thread, runs a function within it, then waits for the completion of that function. + + .. code-block:: + + return_value = await run_in_thread(func) + + See :ref:`io-in-asynckivy` for details. + ''' + ev = asyncgui.AsyncEvent() + Thread( + name='asynckivy.run_in_thread', + target=_wrapper, daemon=daemon, args=(func, ev, ), + ).start() + ret, exc = (await ev.wait())[0] + if exc is not None: + raise exc + return ret + + +async def run_in_executor(executor: ThreadPoolExecutor, func) -> T.Awaitable: + ''' + Runs a function within a :class:`concurrent.futures.ThreadPoolExecutor`, and waits for the completion of the + function. + + .. code-block:: + + executor = ThreadPoolExecutor() + ... + return_value = await run_in_executor(executor, func) + + See :ref:`io-in-asynckivy` for details. + ''' + ev = asyncgui.AsyncEvent() + future = executor.submit(_wrapper, func, ev) + try: + ret, exc = (await ev.wait())[0] + except asyncgui.Cancelled: + future.cancel() + raise + assert future.done() + if exc is not None: + raise exc + return ret diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_touch.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_touch.py new file mode 100644 index 0000000..469e4cb --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_touch.py @@ -0,0 +1,196 @@ +__all__ = ('watch_touch', 'rest_of_touch_moves', 'rest_of_touch_events', 'touch_up_event', ) + +import typing as T +import types +from functools import partial +from asyncgui import wait_any, current_task +from ._exceptions import MotionEventAlreadyEndedError +from ._sleep import sleep +from ._event import event + + +class watch_touch: + ''' + Returns an async context manager that provides an easy way to handle touch events. + + .. code-block:: + + async with watch_touch(widget, touch) as in_progress: + while await in_progress(): + print('on_touch_move') + print('on_touch_up') + + The ``await in_progress()`` waits for either an ``on_touch_move`` event or an ``on_touch_up`` event to occur, and + returns True or False respectively when they occurred. + + **Caution** + + * You are not allowed to perform any kind of async operations inside the with-block except ``await in_progress()``. + + .. code-block:: + + async with watch_touch(widget, touch) as in_progress: + await in_progress() # OK + await something_else # NOT ALLOWED + async with async_context_manager: # NOT ALLOWED + ... + async for __ in async_iterator: # NOT ALLOWED + ... + + * If the ``widget`` is the type of widget that grabs touches by itself, such as :class:`kivy.uix.button.Button`, + you probably want to set the ``stop_dispatching`` parameter to True in most cases. + * There are widgets/behaviors that can simulate a touch (e.g. :class:`kivy.uix.scrollview.ScrollView`, + :class:`kivy.uix.behaviors.DragBehavior` and ``kivy_garden.draggable.KXDraggableBehavior``). + If many such widgets are in the parent stack of the ``widget``, this API might mistakenly raise a + :exc:`asynckivy.MotionEventAlreadyEndedError`. If that happens, increase the ``timeout`` parameter. + ''' + __slots__ = ('_widget', '_touch', '_stop_dispatching', '_timeout', '_uid_up', '_uid_move', '_no_cleanup', ) + + def __init__(self, widget, touch, *, stop_dispatching=False, timeout=1.): + self._widget = widget + self._touch = touch + self._stop_dispatching = stop_dispatching + self._timeout = timeout + self._no_cleanup = False + + def _on_touch_up_sd(step, touch, w, t): + if t is touch: + if t.grab_current is w: + t.ungrab(w) + step(False) + return True + + def _on_touch_move_sd(step, touch, w, t): + if t is touch: + if t.grab_current is w: + step(True) + return True + + def _on_touch_up(step, touch, w, t): + if t.grab_current is w and t is touch: + t.ungrab(w) + step(False) + return True + + def _on_touch_move(step, touch, w, t): + if t.grab_current is w and t is touch: + step(True) + return True + + _callbacks = ((_on_touch_up_sd, _on_touch_move_sd, ), (_on_touch_up, _on_touch_move, ), ) + del _on_touch_up, _on_touch_move, _on_touch_up_sd, _on_touch_move_sd + + @staticmethod + @types.coroutine + def _true_if_touch_move_false_if_touch_up() -> bool: + return (yield lambda step_coro: None)[0][0] + + @staticmethod + @types.coroutine + def _always_false() -> bool: + return False + yield # just to make this function a generator function + + async def __aenter__(self) -> T.Awaitable[T.Callable[[], T.Awaitable[bool]]]: + touch = self._touch + widget = self._widget + if touch.time_end != -1: + # `on_touch_up` might have been already fired so we need to find out it actually was or not. + tasks = await wait_any( + sleep(self._timeout), + event(widget, 'on_touch_up', filter=lambda w, t: t is touch), + ) + if tasks[0].finished: + raise MotionEventAlreadyEndedError(f"MotionEvent(uid={touch.uid}) has already ended") + self._no_cleanup = True + return self._always_false + step = (await current_task())._step + on_touch_up, on_touch_move = self._callbacks[not self._stop_dispatching] + touch.grab(widget) + self._uid_up = widget.fbind('on_touch_up', partial(on_touch_up, step, touch)) + self._uid_move = widget.fbind('on_touch_move', partial(on_touch_move, step, touch)) + assert self._uid_up + assert self._uid_move + return self._true_if_touch_move_false_if_touch_up + + async def __aexit__(self, *args): + if self._no_cleanup: + return + w = self._widget + self._touch.ungrab(w) + w.unbind_uid('on_touch_up', self._uid_up) + w.unbind_uid('on_touch_move', self._uid_move) + + +async def touch_up_event(widget, touch, *, stop_dispatching=False, timeout=1.) -> T.Awaitable: + ''' + *(experimental state)* + + Returns an awaitable that can be used to wait for the ``on_touch_up`` event of the given ``touch`` to occur. + + .. code-block:: + + __, touch = await event(widget, 'on_touch_down') + ... + await touch_up_event(widget, touch) + + You might wonder what the differences are compared to the code below. + + .. code-block:: + :emphasize-lines: 3 + + __, touch = await event(widget, 'on_touch_down') + ... + await event(widget, 'on_touch_up', filter=lambda w, t: t is touch) + + The latter has two problems: + If the ``on_touch_up`` event of the ``touch`` occurred before the highlighted line, + the execution will halt indefinitely at that point. + Even if the event didn't occur before that line, the execution still might halt because + `Kivy does not guarantee`_ that all touch events are delivered to all widgets. + + This API takes care of both problems in the same way as :func:`watch_touch`. + If the ``on_touch_up`` event has already occurred, it raises a :exc:`MotionEventAlreadyEndedError` exception. + And it grabs/ungrabs the ``touch`` so that it won't miss any touch events. + + Needless to say, if you want to wait for both ``on_touch_move`` and ``on_touch_up`` events at the same time, + use :func:`watch_touch` or :func:`rest_of_touch_events` instead. + + .. _Kivy does not guarantee: https://kivy.org/doc/stable/guide/inputs.html#grabbing-touch-events + ''' + touch.grab(widget) + try: + awaitable = event( + widget, 'on_touch_up', stop_dispatching=stop_dispatching, + filter=lambda w, t: t.grab_current is w and t is touch, + ) + if touch.time_end == -1: + await awaitable + else: + tasks = await wait_any(sleep(timeout), awaitable) + if tasks[0].finished: + raise MotionEventAlreadyEndedError(f"MotionEvent(uid={touch.uid}) has already ended") + finally: + touch.ungrab(widget) + + +async def rest_of_touch_events(widget, touch, *, stop_dispatching=False, timeout=1.) -> T.AsyncIterator[None]: + ''' + Returns an async iterator that iterates the number of times ``on_touch_move`` occurs, + and ends the iteration when ``on_touch_up`` occurs. + + .. code-block:: + + async for __ in rest_of_touch_events(widget, touch): + print('on_touch_move') + print('on_touch_up') + + This is a wrapper for :class:`watch_touch`. Although this one, I believe, is more intuitive than + :class:`watch_touch`, it has a couple of disadvantages - see :ref:`the-problem-with-async-generators`. + ''' + async with watch_touch(widget, touch, stop_dispatching=stop_dispatching, timeout=timeout) as in_progress: + while await in_progress(): + yield + + +rest_of_touch_moves = rest_of_touch_events diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/_utils.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/_utils.py new file mode 100644 index 0000000..0fb04f5 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/_utils.py @@ -0,0 +1,256 @@ +__all__ = ('transform', 'suppress_event', 'create_texture_from_text', 'sync_attr', 'sync_attrs', ) +import typing as T +from contextlib import contextmanager +from functools import partial + +from kivy.event import EventDispatcher +from kivy.graphics import PushMatrix, PopMatrix, InstructionGroup +from kivy.graphics.texture import Texture +from kivy.core.text import Label as CoreLabel +from kivy.core.text.markup import MarkupLabel as CoreMarkupLabel + + +@contextmanager +def transform(widget, *, use_outer_canvas=False) -> T.ContextManager[InstructionGroup]: + ''' + Returns a context manager that sandwiches the ``widget``'s existing canvas instructions between + a :class:`kivy.graphics.PushMatrix` and a :class:`kivy.graphics.PopMatrix`, and inserts an + :class:`kivy.graphics.InstructionGroup` right next to the ``PushMatrix``. Those three instructions will be removed + when the context manager exits. + + This may be useful when you want to animate a widget. + + **Usage** + + .. code-block:: + + from kivy.graphics import Rotate + + async def rotate_widget(widget, *, angle=360.): + with transform(widget) as ig: # <- InstructionGroup + ig.add(rotate := Rotate(origin=widget.center)) + await anim_attrs(rotate, angle=angle) + + If the position or size of the ``widget`` changes during the animation, you might need :class:`sync_attr`. + + **The use_outer_canvas parameter** + + While the context manager is active, the content of the widget's canvas would be: + + .. code-block:: yaml + + # ... represents existing instructions + + Widget: + canvas.before: + ... + canvas: + PushMatrix + InstructionGroup + ... + PopMatrix + canvas.after: + ... + + but if ``use_outer_canvas`` is True, it would be: + + .. code-block:: yaml + + Widget: + canvas.before: + PushMatrix + InstructionGroup + ... + canvas: + ... + canvas.after: + ... + PopMatrix + ''' + + c = widget.canvas + if use_outer_canvas: + before = c.before + after = c.after + push_mat_idx = 0 + ig_idx = 1 + else: + c.before # ensure 'canvas.before' exists + + # Index starts from 1 because 'canvas.before' is sitting at index 0 and we usually want it to remain first. + # See https://github.com/kivy/kivy/issues/7945 for details. + push_mat_idx = 1 + ig_idx = 2 + before = after = c + + push_mat = PushMatrix() + ig = InstructionGroup() + pop_mat = PopMatrix() + + before.insert(push_mat_idx, push_mat) + before.insert(ig_idx, ig) + after.add(pop_mat) + try: + yield ig + finally: + after.remove(pop_mat) + before.remove(ig) + before.remove(push_mat) + + +class suppress_event: + ''' + Returns a context manager that prevents the callback functions (including the default handler) bound to an event + from being called. + + .. code-block:: + :emphasize-lines: 4 + + from kivy.uix.button import Button + + btn = Button() + btn.bind(on_press=lambda __: print("pressed")) + with suppress_event(btn, 'on_press'): + btn.dispatch('on_press') + + The above code prints nothing because the callback function won't be called. + + Strictly speaking, this context manager doesn't prevent all callback functions from being called. + It only prevents the callback functions that were bound to an event before the context manager enters. + Thus, the following code prints ``pressed``. + + .. code-block:: + :emphasize-lines: 5 + + from kivy.uix.button import Button + + btn = Button() + with suppress_event(btn, 'on_press'): + btn.bind(on_press=lambda __: print("pressed")) + btn.dispatch('on_press') + + .. warning:: + + You need to be careful when you suppress an ``on_touch_xxx`` event. + See :ref:`kivys-event-system` for details. + ''' + __slots__ = ('_dispatcher', '_name', '_bind_uid', '_filter', ) + + def __init__(self, event_dispatcher, event_name, *, filter=lambda *args, **kwargs: True): + self._dispatcher = event_dispatcher + self._name = event_name + self._filter = filter + + def __enter__(self): + self._bind_uid = self._dispatcher.fbind(self._name, self._filter) + + def __exit__(self, *args): + self._dispatcher.unbind_uid(self._name, self._bind_uid) + + +def create_texture_from_text(*, markup=False, **label_kwargs) -> Texture: + ''' + .. code-block:: + + from kivy.metrics import sp + + texture = create_texture_from_text( + text='Hello', + font_size=sp(50), + font_name='Roboto', + color=(1, 0, 0, 1), + ) + + The keyword arguments are similar to :external:kivy:doc:`api-kivy.uix.label` 's. + ''' + core_cls = CoreMarkupLabel if markup else CoreLabel + core = core_cls(**label_kwargs) + core.refresh() + return core.texture + + +class sync_attr: + ''' + Returns a context manager that creates one-directional binding between attributes. + + .. code-block:: + + import types + + widget = Widget() + obj = types.SimpleNamespace() + + with sync_attr(from_=(widget, 'x'), to_=(obj, 'xx')): + widget.x = 10 + assert obj.xx == 10 # synchronized + obj.xx = 20 + assert widget.x == 10 # but not the other way around + + This can be particularly useful when combined with :func:`transform`. + + .. code-block:: + + from kivy.graphics import Rotate + + async def rotate_widget(widget, *, angle=360.): + with transform(widget) as ig: + ig.add(rotate := Rotate(origin=widget.center)) + with sync_attr(from_=(widget, 'center'), to_=(rotate, 'origin')): + await anim_attrs(rotate, angle=angle) + + .. versionadded:: 0.6.1 + ''' + __slots__ = ('_from', '_to', '_bind_uid', ) + + def __init__(self, from_: T.Tuple[EventDispatcher, str], to_: T.Tuple[T.Any, str]): + self._from = from_ + self._to = to_ + + def _sync(setattr, obj, attr_name, event_dispatcher, new_value): + setattr(obj, attr_name, new_value) + + def __enter__(self, partial=partial, sync=partial(_sync, setattr)): + self._bind_uid = self._from[0].fbind(self._from[1], partial(sync, *self._to)) + + def __exit__(self, *args): + self._from[0].unbind_uid(self._from[1], self._bind_uid) + + del _sync + + +class sync_attrs: + ''' + When multiple :class:`sync_attr` calls take the same ``from_`` argument, they can be merged into a single + :class:`sync_attrs` call. For instance, the following code: + + .. code-block:: + + with sync_attr((widget, 'x'), (obj1, 'x')), sync_attr((widget, 'x'), (obj2, 'xx')): + ... + + can be replaced with the following one: + + .. code-block:: + + with sync_attrs((widget, 'x'), (obj1, 'x'), (obj2, 'xx')): + ... + + .. versionadded:: 0.6.1 + ''' + __slots__ = ('_from', '_to', '_bind_uid', ) + + def __init__(self, from_: T.Tuple[EventDispatcher, str], *to_): + self._from = from_ + self._to = to_ + + def _sync(setattr, to_, event_dispatcher, new_value): + for obj, attr_name in to_: + setattr(obj, attr_name, new_value) + + def __enter__(self, partial=partial, sync=partial(_sync, setattr)): + self._bind_uid = self._from[0].fbind(self._from[1], partial(sync, self._to)) + + def __exit__(self, *args): + self._from[0].unbind_uid(self._from[1], self._bind_uid) + + del _sync diff --git a/kivy_venv/lib/python3.11/site-packages/asynckivy/vanim.py b/kivy_venv/lib/python3.11/site-packages/asynckivy/vanim.py new file mode 100644 index 0000000..d588a3e --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/asynckivy/vanim.py @@ -0,0 +1,20 @@ +__all__ = ( + 'dt', 'delta_time', + 'et', 'elapsed_time', + 'dt_et', 'delta_time_elapsed_time', + 'progress', + 'dt_et_progress', 'delta_time_elapsed_time_progress', +) + +import warnings +from . import _anim_with_xxx + + +warnings.warn("The 'vanim' module is deprecated. Use 'asynckivy.anim_with_xxx' instead.") + + +delta_time = dt = _anim_with_xxx.anim_with_dt +elapsed_time = et = _anim_with_xxx.anim_with_et +progress = _anim_with_xxx.anim_with_ratio +delta_time_elapsed_time = dt_et = _anim_with_xxx.anim_with_dt_et +delta_time_elapsed_time_progress = dt_et_progress = _anim_with_xxx.anim_with_dt_et_ratio diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/RECORD b/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/RECORD deleted file mode 100644 index 1b88c37..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/RECORD +++ /dev/null @@ -1,394 +0,0 @@ -../../../bin/kivymd.add_view,sha256=u2N52U9NKr85se5a66gdG5Old498YxKwDezJ-cwIZAY,266 -../../../bin/kivymd.create_project,sha256=6LnjVohJ7V3MZYfVCtWqtyHHaku6Io-y0pN1BFPmDAM,272 -../../../bin/kivymd.make_release,sha256=hKmHIsjNRMSeSS3A2PNqeer_kEliqi6NhzI9bmLc0Zo,269 -kivymd-1.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -kivymd-1.2.0.dist-info/LICENSE,sha256=bWmhpIowwWDSSAQwBDm2S0_cUBhZc2yzQ0DwcT9-TrY,1691 -kivymd-1.2.0.dist-info/METADATA,sha256=GNIP7_ZragUNLOP6JBXj04nv3clgw33m1MlflQ8a9g4,15020 -kivymd-1.2.0.dist-info/RECORD,, -kivymd-1.2.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd-1.2.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91 -kivymd-1.2.0.dist-info/entry_points.txt,sha256=1-yhsSzIhBNRiKNTmevRDT02q8qzg3upZcWAyrr880w,342 -kivymd-1.2.0.dist-info/top_level.txt,sha256=ABq82F4nFM8sy3xAhxiO5XXT_lAen0YqiDD29qRiPhc,7 -kivymd/__init__.py,sha256=Lk1_FB7hhUcfOVc2hAVZdmpJa9RStEhpKf3Gx-Nm1C8,2158 -kivymd/__pycache__/__init__.cpython-311.pyc,, -kivymd/__pycache__/_version.cpython-311.pyc,, -kivymd/__pycache__/app.cpython-311.pyc,, -kivymd/__pycache__/color_definitions.cpython-311.pyc,, -kivymd/__pycache__/factory_registers.cpython-311.pyc,, -kivymd/__pycache__/font_definitions.cpython-311.pyc,, -kivymd/__pycache__/icon_definitions.cpython-311.pyc,, -kivymd/__pycache__/material_resources.cpython-311.pyc,, -kivymd/__pycache__/theming.cpython-311.pyc,, -kivymd/__pycache__/theming_dynamic_text.cpython-311.pyc,, -kivymd/_version.py,sha256=KnOtqZaS5l4zlFEKhhqjLzpQaqc4Kmdc5stnQiKUDYs,140 -kivymd/app.py,sha256=M1rwjNfNURnCdhVB_Rk7Hz5cljpwJxN8T6UhKkR4qaI,4222 -kivymd/color_definitions.py,sha256=vkOEWwRem3-Vh4dOIyJdSPrg88kyLaD6QZtpx7ecuV0,21550 -kivymd/effects/__init__.py,sha256=ySU96kLlmPF4QB-hDa0WM_Y0Odq1MPSR568yI_hiaqI,24 -kivymd/effects/__pycache__/__init__.cpython-311.pyc,, -kivymd/effects/fadingedge/__init__.py,sha256=ED7rP0TF96RxwjtLhj3KdAfqo7-YQuA4B10jnWuuMEg,41 -kivymd/effects/fadingedge/__pycache__/__init__.cpython-311.pyc,, -kivymd/effects/fadingedge/__pycache__/fadingedge.cpython-311.pyc,, -kivymd/effects/fadingedge/fadingedge.py,sha256=ZM3JRhQ7kvNuj8Z52VUq6MLF2sh7BEoa4_5oc7-mvcg,6054 -kivymd/effects/roulettescroll/__init__.py,sha256=Ep2YTxf03Y_A2GbosQIsm8AFsuOeE-w5VPL_NxckTbY,49 -kivymd/effects/roulettescroll/__pycache__/__init__.cpython-311.pyc,, -kivymd/effects/roulettescroll/__pycache__/roulettescroll.cpython-311.pyc,, -kivymd/effects/roulettescroll/roulettescroll.py,sha256=b4pJtyKDUqRzSGW4iIZpgUWV91QlRxgUXaPreBUVVEI,8092 -kivymd/effects/stiffscroll/__init__.py,sha256=tkGDtFz6s7W3iFtHRDo6NYWadL85cn7GXKAQQfpiJRk,43 -kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc,, -kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc,, -kivymd/effects/stiffscroll/stiffscroll.py,sha256=3bSj43xOzhBcBSn58iLUiaNWevlHuO8seklAyfvZsJE,7117 -kivymd/factory_registers.py,sha256=0wC2kYMlYCNdShEzETUWEyLsESwwDgnGrgsvVL3t7-M,6431 -kivymd/font_definitions.py,sha256=2-4eWkHy4GUT_HhIr5GSEK7CUd71th6Mvi3QAPibkTA,1628 -kivymd/fonts/Roboto-Black.ttf,sha256=OHLps5dgobWaweGSYz27O1jllbTUI5MKx97VJemuJeA,171480 -kivymd/fonts/Roboto-BlackItalic.ttf,sha256=AT0ipPsmOK26KFVe4ZNm9FhfbcUzt8My9JMaIxSXyyI,177552 -kivymd/fonts/Roboto-Bold.ttf,sha256=fQuZHuPgvnrwGtfqjNK-6mwAol5nmgImtnN_B5qv_4Y,170760 -kivymd/fonts/Roboto-BoldItalic.ttf,sha256=pLysFPQZqX3gkXGYpLxRw-1PxKPbn2ilEC8jZk7gE1Q,174952 -kivymd/fonts/Roboto-Italic.ttf,sha256=X86Lb4up9NGfDVNeJB1WorjnK7B-ffcR2WjQku9_n8o,173932 -kivymd/fonts/Roboto-Light.ttf,sha256=ptND1CW8ONuQFS-gYFixxzkeypJk8zTvZcHOF1CFxvY,170420 -kivymd/fonts/Roboto-LightItalic.ttf,sha256=Nkoj4Txkk3w_zqPbd4YouJN5yJOEm7reblv4PF9gXGo,176616 -kivymd/fonts/Roboto-Medium.ttf,sha256=8gXMURgh6lYHihBVV_zqYlMSlATUEcmX4YZvvQBqu2g,172064 -kivymd/fonts/Roboto-MediumItalic.ttf,sha256=8Xfu0Q0kcNE-xo0EkHpYKCnQ7oKB-KAqkG9pVMeBblg,176864 -kivymd/fonts/Roboto-Regular.ttf,sha256=eehRQEZX2sIQaz0irSVtR4JKmldlRY7bcskQKkWBbZU,171676 -kivymd/fonts/Roboto-Thin.ttf,sha256=PZH3qmnLf3BkA1iVxWasXLmyCEWC01Gvcme7Tg-6YPU,171904 -kivymd/fonts/Roboto-ThinItalic.ttf,sha256=9eiaNEiUpg8PmPHAGCulH1BG4p3eMRiCDTkCVEWuqug,176300 -kivymd/fonts/materialdesignicons-webfont.ttf,sha256=pY7LVPRe7Br628ITFNHwkyzwCeXLx_MiXX5KThtx72s,1279992 -kivymd/icon_definitions.py,sha256=NPLejj2aOoR3N97zW8H8K2Sw7ECqYXQ_xLALkD0Yo-c,276638 -kivymd/images/alpha_layer.png,sha256=FRlE7o8oQebgftB_P9I-o-a6mslCr7aIrY3Zo6QGuAs,553 -kivymd/images/black.png,sha256=2oJF5FzBeTXDdA7lE2kQ_ftDv8TRtCOiTQtfvCf_qlM,147 -kivymd/images/blue.png,sha256=vOIOgEL_pAc4anbPSOhe6dxcEYi58dh3jlprNc36ASQ,147 -kivymd/images/folder.png,sha256=xY9uUYegh7hDzFI4iPEA-zyFBzq9IE007zaJGGY5JY0,2311 -kivymd/images/green.png,sha256=GK69rWfb7kTIlxD8nPjSq1X6k06SO1AxstcJLskJtp4,147 -kivymd/images/logo/kivymd-icon-128.png,sha256=VjWHaIJ-MSyP7ZnM25xgBfp_wG4vbQhr8B8QOTcXeaM,19826 -kivymd/images/logo/kivymd-icon-256.png,sha256=5iJVryvz0D-IvqLGTsaeJlYhZYk2R7OxskKiNgw25Ks,31943 -kivymd/images/logo/kivymd-icon-512.png,sha256=JAtfTEA7AWBPcMhFGqlwSQmQSq-lWAEJ8Y98qmDe0I0,54349 -kivymd/images/red.png,sha256=_4J3FtVS8IKWHCmr2e9GOy2cOGKmwV_0lzAbQf1IKLM,147 -kivymd/images/transparent.png,sha256=yM2bydAM4U0tnbs4zAuK2GnCC6I6NgAIfpw7rQhG1BQ,156 -kivymd/images/yellow.png,sha256=TH_ecR8dfP9R-8zYD4Ez24qZjaEbDTgJ0RcIcbHBIeE,147 -kivymd/material_resources.py,sha256=Ph4x6f5Lp7XOI4jqIkOBo_tZ_yMUPZDToO34A7akOlo,1763 -kivymd/theming.py,sha256=hQ5RfjoQlE8hWQKdQ2ZVOF_83ok-o8o0BzR-Kv5XDmA,58553 -kivymd/theming_dynamic_text.py,sha256=5TaO0Tc98EqK4-qTDMUO4FQHIU_wVxk6Y2GHhD6UcRk,2920 -kivymd/toast/__init__.py,sha256=1gkx40QSHU_0YprtsIJfog8Nnj6t_ZuXMLGhI7QZ0ww,238 -kivymd/toast/__pycache__/__init__.cpython-311.pyc,, -kivymd/toast/androidtoast/__init__.py,sha256=CCs95Gih3ri4OcO1J-xPFVmhGKPdY9idW3-V0mIjQ_s,226 -kivymd/toast/androidtoast/__pycache__/__init__.cpython-311.pyc,, -kivymd/toast/androidtoast/__pycache__/androidtoast.cpython-311.pyc,, -kivymd/toast/androidtoast/androidtoast.py,sha256=cpbgUhZUjOU1go4Sn-qOo9h61Qhk4EAx1SFI9b4tC8o,2363 -kivymd/toast/kivytoast/__init__.py,sha256=mFY2Qi4xK_ttQxx7DnEg7XZxX68he0Hr09rZ60Pm95A,51 -kivymd/toast/kivytoast/__pycache__/__init__.cpython-311.pyc,, -kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-311.pyc,, -kivymd/toast/kivytoast/kivytoast.py,sha256=jRLOmiUV2Hf_09tTxnEfJUM5lEBZWfo_wEmgC9zLq5M,4135 -kivymd/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/tools/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/__pycache__/argument_parser.cpython-311.pyc,, -kivymd/tools/argument_parser.py,sha256=oxgJoS5WZH_ATDlaEU0HDtm7ve4DOJ23CnOILIBygy8,3193 -kivymd/tools/hotreload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc,, -kivymd/tools/hotreload/app.py,sha256=cJxyUxz1GbQ58pgPY3GZNSl-CoawoPUPoCUF3lECltI,16803 -kivymd/tools/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/packaging/pyinstaller/__init__.py,sha256=ibpoURJJkyGuSgWhz8t-RuLnCmQf15TiFNr-HKTCPHA,1480 -kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc,, -kivymd/tools/packaging/pyinstaller/hook-kivymd.py,sha256=cN0arGlcA_vLA8FTaAdzKgn7s2YQRCclv7G0e4c4o-Y,1053 -kivymd/tools/patterns/MVC/Model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc,, -kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc,, -kivymd/tools/patterns/MVC/Model/database_firebase.py,sha256=5SlPAn-ROkh_ytnv2nteaVRAMC0MUSDM9u115Crfh-o,1376 -kivymd/tools/patterns/MVC/Model/database_restdb.py,sha256=Wc-zPffP-Wriyn-JGKCQrw3SGZMiAk-8LrVjParRtGM,3866 -kivymd/tools/patterns/MVC/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/patterns/MVC/data/locales/po/en.po,sha256=1b2jIsEnyQi_T_gnpe5QeO90IdaQLwWClk5pn46ZjME,425 -kivymd/tools/patterns/MVC/data/locales/po/ru.po,sha256=mQd6ol2abec-PUJsrnRWNoah0din3IAg_F4gPf5VBVw,425 -kivymd/tools/patterns/MVC/libs/__init__.py,sha256=B6Kln9GZ6UrMOxr4lOnpTxGBMaoKlcar5wpyTGyUlIk,54 -kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc,, -kivymd/tools/patterns/MVC/libs/translation.py,sha256=LiiMZUxVbAmUy71mVA-PyEkxwYrCAOcjeiDnlbCSPvQ,1411 -kivymd/tools/patterns/MVC/messages.pot,sha256=2cutqkylhtiY07tkXzE8yNqpux9eeoW3tdeoEbXdB1Y,582 -kivymd/tools/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc,, -kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc,, -kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc,, -kivymd/tools/patterns/add_view.py,sha256=4J41yOosi9KkNrMBI6h6yJ_0LoncdJzmJDy-iShaArk,6576 -kivymd/tools/patterns/create_project.py,sha256=x3g37U3Dbk-ivUJ_aGgwvjpwBkyM4zIcPF3Bcyw1ASQ,39373 -kivymd/uix/__init__.py,sha256=iYE45157qMg3owm8X0BMVuStS8kU6bFyWr04VTjIPcw,2892 -kivymd/uix/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc,, -kivymd/uix/__pycache__/boxlayout.cpython-311.pyc,, -kivymd/uix/__pycache__/carousel.cpython-311.pyc,, -kivymd/uix/__pycache__/circularlayout.cpython-311.pyc,, -kivymd/uix/__pycache__/floatlayout.cpython-311.pyc,, -kivymd/uix/__pycache__/gridlayout.cpython-311.pyc,, -kivymd/uix/__pycache__/hero.cpython-311.pyc,, -kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc,, -kivymd/uix/__pycache__/recycleview.cpython-311.pyc,, -kivymd/uix/__pycache__/relativelayout.cpython-311.pyc,, -kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc,, -kivymd/uix/__pycache__/screen.cpython-311.pyc,, -kivymd/uix/__pycache__/screenmanager.cpython-311.pyc,, -kivymd/uix/__pycache__/scrollview.cpython-311.pyc,, -kivymd/uix/__pycache__/stacklayout.cpython-311.pyc,, -kivymd/uix/__pycache__/taptargetview.cpython-311.pyc,, -kivymd/uix/__pycache__/widget.cpython-311.pyc,, -kivymd/uix/anchorlayout.py,sha256=lrw9QiThjutmOTQix71atzJKP_cauoGUykiLdLfW99Q,1025 -kivymd/uix/backdrop/__init__.py,sha256=_9OLuWRMGEDqI1-ix6u0VJbuOpHJ6FLnJuODPYw2Eko,46 -kivymd/uix/backdrop/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/backdrop/__pycache__/backdrop.cpython-311.pyc,, -kivymd/uix/backdrop/backdrop.kv,sha256=L0w8al59AMQlkUrqjJsX1o7pMC9S70zt5KwulOON18g,1407 -kivymd/uix/backdrop/backdrop.py,sha256=eiJyqjY3hT-CFUVUX97f-2-npPxsr4TfsECjTGIrhTE,16311 -kivymd/uix/banner/__init__.py,sha256=JimxFPqzTx8l1pwI4rknb8r3QiDhLcI9xb4pIfpselo,42 -kivymd/uix/banner/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/banner/__pycache__/banner.cpython-311.pyc,, -kivymd/uix/banner/banner.kv,sha256=Mb5jq9VSLr0A4DqvTpSF9tKKh-JvpiN3oM9jKh8V5vs,1679 -kivymd/uix/banner/banner.py,sha256=E99gUMVE51jKNpTG3gyQKVAiaxQ4yeIznLzcGeOO4-A,12053 -kivymd/uix/behaviors/__init__.py,sha256=htl-U1oP2Tkmgul6gvkWV54LOzrTKe_jhwpT7dd372M,979 -kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc,, -kivymd/uix/behaviors/backgroundcolor_behavior.py,sha256=a8Oa41plDW4G4tiIL-QNLc963VsW-5u7BuwvCTFfl3s,8962 -kivymd/uix/behaviors/declarative_behavior.py,sha256=MI2KelKtrkhXMIXoqu53ivHf_Zn7CQNQUtRHiwHpe9A,10236 -kivymd/uix/behaviors/elevation.py,sha256=cdQgXKUxM1-2YS1H3IM2yssc5FUQOJtptccMn7xQZvo,22211 -kivymd/uix/behaviors/focus_behavior.py,sha256=fhqtqiTMEopNMP7-_xWTVTtwiuKS9pkjnIIirjm3PcA,4240 -kivymd/uix/behaviors/hover_behavior.py,sha256=mhogwYWLTxJzqrO_Yk38v5BhYY7rFhVZ1xQfcEeXGq8,7616 -kivymd/uix/behaviors/magic_behavior.py,sha256=wwN40b_0NTG3Dopdhqt89PXYqY5mXSM4lY2xuIk1v9Q,4570 -kivymd/uix/behaviors/motion_behavior.py,sha256=15cwgX1UWlS2TJVBVOCia5FhYEOyr6PG9OPJRn_6aqU,7342 -kivymd/uix/behaviors/ripple_behavior.py,sha256=LoS_lIpYlzIGQWAX1FNh_56EmZ5NE_FsxNdQWaVvYZg,16658 -kivymd/uix/behaviors/rotate_behavior.py,sha256=Z8Ux_UwKZHoeu-cCl8hNc2EDVgC_hWni-ld8BpbL1uE,3268 -kivymd/uix/behaviors/scale_behavior.py,sha256=2ONpA7LKW5UhNI-ibBLlyQtOP_xyHDkasNxmqLO-z_c,4062 -kivymd/uix/behaviors/stencil_behavior.py,sha256=k6S2fwKMrxsFQKgI36q5-zCaQZ6LMFmv97jDPXD8e2Y,3017 -kivymd/uix/behaviors/toggle_behavior.py,sha256=wGi3INtIa_6chPcJMekye5jTaGkLMbwPtmW0aFdL_fE,8451 -kivymd/uix/behaviors/touch_behavior.py,sha256=uSP_AE8QuU_t_Q_Q-lUxuxh_Ms8TOZCewxUvSDsj04U,2475 -kivymd/uix/bottomnavigation/__init__.py,sha256=oAt66rNw5qp5ueAqLxfXs2iPpp68IWp5jVEnY3xMkwQ,85 -kivymd/uix/bottomnavigation/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/bottomnavigation/__pycache__/bottomnavigation.cpython-311.pyc,, -kivymd/uix/bottomnavigation/bottomnavigation.kv,sha256=7swDhIg8quCg7Vtm01jy1BnEtMx9qvMueFT88QBnkvU,4082 -kivymd/uix/bottomnavigation/bottomnavigation.py,sha256=BpVHD3XKnkZe2tLvNDn6Z23Kuq7l0lneY3TrRMK1pec,27138 -kivymd/uix/bottomsheet/__init__.py,sha256=VhYEno0toWnl6OmaxgYT7as1MIXYXLxhZHnTTrZ4TAY,255 -kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc,, -kivymd/uix/bottomsheet/bottomsheet.kv,sha256=83LTxxGThfDnPN1ATAw4zU0_LB-jmERiFQyC8b3iedA,1047 -kivymd/uix/bottomsheet/bottomsheet.py,sha256=zv5Y3x7e3YdqnL_RJgMunpRrSd5BP4Oro7iO-QDLC7w,36674 -kivymd/uix/boxlayout.py,sha256=cWQuo2HJNnCoeY-HwXxsxZrv0YXR-IE4GGf8ymPVswI,1694 -kivymd/uix/button/__init__.py,sha256=hflz-R7RufS_l2SBqnwYtmAV5WAnsnmD2jwr3OQeusc,385 -kivymd/uix/button/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/button/__pycache__/button.cpython-311.pyc,, -kivymd/uix/button/button.kv,sha256=Z4AKWPAoRfPUflwHeUH81NpXSGZKrsiuSbAuy5GDTTA,6614 -kivymd/uix/button/button.py,sha256=O4u_5Ph7bVeicDk_fxc1HTiCzIZUr8rTGoyTIiPDnMU,75206 -kivymd/uix/card/__init__.py,sha256=DRguLhBrd_iil2DlVN7R8Euq711j6M81Hbkyfv9f4fs,130 -kivymd/uix/card/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/card/__pycache__/card.cpython-311.pyc,, -kivymd/uix/card/card.kv,sha256=dMijf_VPWw1Vc6cM7LdCf3KCFEcHtC9QnAU2icmAeXk,192 -kivymd/uix/card/card.py,sha256=cVm6dSVT6bUsWjyh2MbXUTPbCbgpGR7ekLWQb2afIJc,33665 -kivymd/uix/carousel.py,sha256=371UKLVsrndHekRbtAgnEtUU_ZQVDdzgXFJfhpJIr1c,7044 -kivymd/uix/chip/__init__.py,sha256=gpNRYAODC-ip0mjg36rcw8SMTQh_-223GPQsPPY65OE,50 -kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/chip/__pycache__/chip.cpython-311.pyc,, -kivymd/uix/chip/chip.kv,sha256=2ZUAugzJb3yw-Mf0rw7yKA07foheqB1gS9LhK0WQrZ4,1035 -kivymd/uix/chip/chip.py,sha256=a7xTg3jyQFhsJrmjBI2eVqBwhIJSY2UdjAufll0A75U,34934 -kivymd/uix/circularlayout.py,sha256=rG9QqC_1PoEqNhHCS8OK4oLcSvqBC2RSRZh9BHc8I0w,5506 -kivymd/uix/controllers/__init__.py,sha256=WNbi76mp899CTLeSZUnVJ0b5gSeUMJ9ganvmhEcNR40,231 -kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc,, -kivymd/uix/controllers/windowcontroller.py,sha256=msVZQJwaekkIw4XUECXWAMOAsXw5NkFe38xIel1wG84,2335 -kivymd/uix/datatables/__init__.py,sha256=UQ_0tOrl5F-VSHQUpByyFw5LQzKTFAnWBNrUAnmPN2k,49 -kivymd/uix/datatables/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/datatables/__pycache__/datatables.cpython-311.pyc,, -kivymd/uix/datatables/datatables.kv,sha256=4u8JMT66faxazxGdVDAbHF3aT_ioNQRN04O_asr5Si0,6558 -kivymd/uix/datatables/datatables.py,sha256=OfoHMXPE1LYaNF03th3M8dMp_ZcgNV4wuQF0FTL5yc0,71271 -kivymd/uix/dialog/__init__.py,sha256=GcaS3dDIcvTSuJ9hYwNAsSKe89OKj1F7DEyu2j2HxCw,54 -kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc,, -kivymd/uix/dialog/dialog.kv,sha256=0afWO3x6OXEsOUHUSdxO7q3m6mOU7HlizEal4FCBCYQ,2155 -kivymd/uix/dialog/dialog.py,sha256=YjK1ozUeZ1HQpzSQvZQav0D3SWfavFJwB6g6vZlAaTs,21874 -kivymd/uix/dropdownitem/__init__.py,sha256=KyXd1v0gdOilE48z8Sp-Pqig_KJOdl0fyzWY8gPjA0U,54 -kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc,, -kivymd/uix/dropdownitem/dropdownitem.kv,sha256=w46i9i807rDqqk1iZyBTqf2wzrt4jtRv2TKxyZaWxGI,906 -kivymd/uix/dropdownitem/dropdownitem.py,sha256=uVveaPSF27cjPCe8WiVp1zjfIIqU36e79NIUPhn193U,2633 -kivymd/uix/expansionpanel/__init__.py,sha256=fOxf-XTewfdiUEsKs4O8-ZFCLxG_zC12oWWIIGtO1Xc,182 -kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc,, -kivymd/uix/expansionpanel/expansionpanel.kv,sha256=ImVy4Axm1-EqLYn52AR5gE6ypSE_jiDjQLz-FnrNZQM,355 -kivymd/uix/expansionpanel/expansionpanel.py,sha256=wPMCjQaN8HE1KwUd7-t97gI-xu-SxwZQAwrh4cRC55M,14229 -kivymd/uix/filemanager/__init__.py,sha256=TR0eAXbR-lzZUQLiVcGcVp5D1myeiLoXGpSWZitrWKI,52 -kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc,, -kivymd/uix/filemanager/filemanager.kv,sha256=PCTjXk8I4yeZSwio4YwyXf2DkXDT0Uz92d0Bk16zKq8,2863 -kivymd/uix/filemanager/filemanager.py,sha256=k_NztZeWL75BPtCCf2e-cNuKgjiRlp6FRjWg9Z6ekKc,25313 -kivymd/uix/fitimage/__init__.py,sha256=BVf16byn839UfzikgsfJj_s5xH0PjGgU9gUuetb1dsU,44 -kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc,, -kivymd/uix/fitimage/fitimage.py,sha256=o2RLSBlr9ahCeZZkmp1zyuhzPN24NKkSknWajBN1dhg,6516 -kivymd/uix/floatlayout.py,sha256=CUeL6e-k20Jg2zqWBL9sMvGzWgO7nNAsTd5So0UMgd4,1202 -kivymd/uix/gridlayout.py,sha256=HULtL-Zg0V_qN_7PZxe9Rr7jEuvGrnRA398tVZQSPkc,1671 -kivymd/uix/hero.py,sha256=P-rsRLF7OL5zHWpw6dgMRsWWWboXghyhFUw9GWpVu-I,17379 -kivymd/uix/imagelist/__init__.py,sha256=O4MQYEuq07GdwTytyXcE48Frp5Cy86zd8sqaYTPMFnk,47 -kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc,, -kivymd/uix/imagelist/imagelist.kv,sha256=lRzJikpng24-TNQl2olHbgg4CUUKnwu8XEhaOY2ts1M,921 -kivymd/uix/imagelist/imagelist.py,sha256=DkSpHgpVgN1hHlFYQddWW-BxcxcuXCg90KEq0C-q3mU,8000 -kivymd/uix/label/__init__.py,sha256=DHLIPzLH5Uq0ChimIQIUVHQ42iAilC-F2xYzWqeqiXY,48 -kivymd/uix/label/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/label/__pycache__/label.cpython-311.pyc,, -kivymd/uix/label/label.kv,sha256=pQa0LHD7haztYEiOKnKLYiK4NbbKe_gwUQWrbPPDKb0,2055 -kivymd/uix/label/label.py,sha256=h_kFBoEXrzPlf9poja-lyLOTJVcgIq9kyPGnKu3lPXI,27892 -kivymd/uix/list/__init__.py,sha256=vaqucd89ij0ssXVPdvdl9bmsiXWbsUX7uZi-qT6QzIc,788 -kivymd/uix/list/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/list/__pycache__/list.cpython-311.pyc,, -kivymd/uix/list/list.kv,sha256=7tm7YcnXRURc_CHXRTYSw9zNObeviasG7arladTBZ5U,4715 -kivymd/uix/list/list.py,sha256=ymc8r18Eex4lNKAyp1UjbyWBFFKw-yaBe9WBy3dQDcs,45486 -kivymd/uix/menu/__init__.py,sha256=2a7cHJKvQmKiqu4_YWWQMF96owFFkRiMnEPX2R_kMbA,46 -kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/menu/__pycache__/menu.cpython-311.pyc,, -kivymd/uix/menu/menu.kv,sha256=ZJ3j-XggUkcEOsEdYRlMnsGit9jZQ1VvKICBgovy2DA,14002 -kivymd/uix/menu/menu.py,sha256=7dnA5hi2CXLWhlrRsBKj59J1FWthaBs2JneIdDzioTw,40950 -kivymd/uix/navigationdrawer/__init__.py,sha256=YFHzu07n8mPUmONaMYhwkx5OzK-J5mrzi109Mfj8S8o,240 -kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc,, -kivymd/uix/navigationdrawer/navigationdrawer.kv,sha256=Sh9d6kvvLONwvFSGJyXFGJ_hzsMhBekMNVnc4Kv5J9U,3586 -kivymd/uix/navigationdrawer/navigationdrawer.py,sha256=zg1m9K_Y2oYRgd5b2lvHAq5QxG5qc2Mzqpco0jTOcJA,46331 -kivymd/uix/navigationrail/__init__.py,sha256=4chGrBkw62foF0LYSBv7fkL9E5MvwUExi7-VG_cSbtM,155 -kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc,, -kivymd/uix/navigationrail/navigationrail.kv,sha256=xDomPL_lSc_ssaPUQsOfQizMZc5Gc3ZBFbAQO2dyN0o,5588 -kivymd/uix/navigationrail/navigationrail.py,sha256=Vr8PjkkbPkCjuvYAW_3Wd-Az9IxwOUWPSOACsQ3dz5k,42888 -kivymd/uix/pickers/__init__.py,sha256=7FvCnbWhjGmwOTqCMFrzTyPOa77Yytkrger5Vz7nOqI,152 -kivymd/uix/pickers/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/pickers/colorpicker/__init__.py,sha256=7HqXXTyARgnSu9I26V08PEj53OZw34MrOGmymOFOPJs,52 -kivymd/uix/pickers/colorpicker/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/pickers/colorpicker/__pycache__/colorpicker.cpython-311.pyc,, -kivymd/uix/pickers/colorpicker/colorpicker.kv,sha256=mbHuEnvYGd97CUJLfrnjZ0qCuJZ8SR14sj9ztUOI-yQ,8272 -kivymd/uix/pickers/colorpicker/colorpicker.py,sha256=ucG1wqZWrG2WBTcUp3kE3uzfVKNMGEMCI4BqOgvEg38,22794 -kivymd/uix/pickers/datepicker/__init__.py,sha256=-_u_4EUwtwFtCh5E58y7aMi4XCK4CJi0R5cZmDptDaE,107 -kivymd/uix/pickers/datepicker/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/pickers/datepicker/__pycache__/datepicker.cpython-311.pyc,, -kivymd/uix/pickers/datepicker/datepicker.kv,sha256=yk5zBwAZZJ_LOADiGBNLVNnx73Y-D58NoqCqooP0vss,14321 -kivymd/uix/pickers/datepicker/datepicker.py,sha256=MBsMiUwYOIumJnI_Dtmhu3UOESv1CjMDWhI84w0SCvw,50563 -kivymd/uix/pickers/timepicker/__init__.py,sha256=ZWB8oTmsgA1Uy5zv2I5QmwZ2N3spznS0anLvK-aytVQ,50 -kivymd/uix/pickers/timepicker/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/pickers/timepicker/__pycache__/timepicker.cpython-311.pyc,, -kivymd/uix/pickers/timepicker/timepicker.kv,sha256=1REiI_DBcT9868oWTAK1BmPhFn0LltmR9Lwq0EHVs-g,10618 -kivymd/uix/pickers/timepicker/timepicker.py,sha256=H3qUswLdaBQ63zbF19bt0y-WiHmCGUBNQt2Qh-_sUlY,25249 -kivymd/uix/progressbar/__init__.py,sha256=YLT-xcOX3Z_O8py_ENTH9wFIletQiMJ5vUVK6nr3Qco,52 -kivymd/uix/progressbar/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/progressbar/__pycache__/progressbar.cpython-311.pyc,, -kivymd/uix/progressbar/progressbar.kv,sha256=p0LzgpX6k_hd-r_CUTbQA2K2yO7M7SIyW8nx-0B8r4Q,1423 -kivymd/uix/progressbar/progressbar.py,sha256=5EYTXRxrV3JkCSidbmXRXt9FNt9tBF3gTTvGzOvh7cI,8523 -kivymd/uix/recyclegridlayout.py,sha256=gvtUVMG04EjsCw2wOPBWgGwu_anZS7buKjFAnZqVhyQ,1804 -kivymd/uix/recycleview.py,sha256=uBxnIU6FgjS44cE6K-Wqp4xel4tuV726_Vaa6W5f5tw,1008 -kivymd/uix/refreshlayout/__init__.py,sha256=r6yH7AYvn831mRtdu6KN_p4L42JBJh2qKpNIuHyckao,66 -kivymd/uix/refreshlayout/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/refreshlayout/__pycache__/refreshlayout.cpython-311.pyc,, -kivymd/uix/refreshlayout/refreshlayout.kv,sha256=5jMCt1kBIA91ll4rWNYZ33fheUvMxph3uUBAj0BhdH0,602 -kivymd/uix/refreshlayout/refreshlayout.py,sha256=lHL1nGOpHWiPqjD7r0dkSabhR6d_Qzis7xtuhpr8RjA,9638 -kivymd/uix/relativelayout.py,sha256=hYfETginxPuQvYU37w22E184wZD_A-eTfRgFw5SqwAE,1062 -kivymd/uix/responsivelayout.py,sha256=N1GMNejHlNssk8ZpC9kMuZELuWywUs9Dms_AzHcpU1Q,5409 -kivymd/uix/screen.py,sha256=WhRKHyC8o7t8c_lgBfX4_hpIz7L2kArKYSAVM7MA0cI,2280 -kivymd/uix/screenmanager.py,sha256=YD3pJ79LdINVEH2QS1zC-FpPQcg3m4mSZakYKh3a9Wc,5091 -kivymd/uix/scrollview.py,sha256=fKCNMqezyYpNlNrYXSueRQ7ISy1Qd6PD74INrPURvdE,948 -kivymd/uix/segmentedbutton/__init__.py,sha256=WpaigD2XLpcvKEEAqWoJTZiZRy3S4J47_KU36FhNPNc,96 -kivymd/uix/segmentedbutton/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/segmentedbutton/__pycache__/segmentedbutton.cpython-311.pyc,, -kivymd/uix/segmentedbutton/segmentedbutton.kv,sha256=1cE5UXZOI46aItAYYpM0cJdgWgPXc6dcqKMFG_0ZD2Y,840 -kivymd/uix/segmentedbutton/segmentedbutton.py,sha256=JjKLG0GO2AVyk-EJQwD8EBeKaaV3Rrk0tr_pkJRRs7Q,19122 -kivymd/uix/segmentedcontrol/__init__.py,sha256=z8ZZj8D5wDxyr__hqHZjscxexIw8CRDkYX6Dl9tZxxs,99 -kivymd/uix/segmentedcontrol/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/segmentedcontrol/__pycache__/segmentedcontrol.cpython-311.pyc,, -kivymd/uix/segmentedcontrol/segmentedcontrol.kv,sha256=jhZiaohChE-DqhZC-hA3_HHxJqQ08eEGmGSF7euyA4A,959 -kivymd/uix/segmentedcontrol/segmentedcontrol.py,sha256=AJQyaQN0et40snqGp9A1ag8HWRMEJqj5PeZ5hrit_sA,11084 -kivymd/uix/selection/__init__.py,sha256=12J_d15BRpSKymQbsMwSZ51Bo_5FauKwaY-d0z_2uAk,52 -kivymd/uix/selection/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/selection/__pycache__/selection.cpython-311.pyc,, -kivymd/uix/selection/selection.kv,sha256=lpA5YyksPcf2tJmmE754eOGsTRkNhLa0IGHAjmlXD70,379 -kivymd/uix/selection/selection.py,sha256=0j-12oo2dVzs-KZDJqHTLIIHDbLcQNerZzds-NFgq8Y,21378 -kivymd/uix/selectioncontrol/__init__.py,sha256=n1yw1X7ccriTWj1GPN-V9LvFXgxuFNfEy6uRHPyhQGA,71 -kivymd/uix/selectioncontrol/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/selectioncontrol/__pycache__/selectioncontrol.cpython-311.pyc,, -kivymd/uix/selectioncontrol/selectioncontrol.kv,sha256=4_Xlvgjpfi_3OmC2BPE7eZ_P4XRRGJw5AcmlXWsf1C0,4873 -kivymd/uix/selectioncontrol/selectioncontrol.py,sha256=Nu-eGtbmgjcaI8A4Ke7nleFOXqPnWuB4q0GTe7aZ4Yc,27724 -kivymd/uix/slider/__init__.py,sha256=TQwpwsmQElirZufuKGck-QZuYLe1V1Vd2HVUwSnPx8k,42 -kivymd/uix/slider/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/slider/__pycache__/slider.cpython-311.pyc,, -kivymd/uix/slider/slider.kv,sha256=ddb5p6jonpz3R9Lqg4tfKqKVTTy2s0_pkURnwUovmtA,6144 -kivymd/uix/slider/slider.py,sha256=nmYRtmX0OOnokQFr-xbWgomK6DnkoBjQXSfe6SjNcaU,8502 -kivymd/uix/sliverappbar/__init__.py,sha256=axuqy95RR0oDLXpBtH3EauoTZN56p6EAp3JFBC-MoYI,103 -kivymd/uix/sliverappbar/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/sliverappbar/__pycache__/sliverappbar.cpython-311.pyc,, -kivymd/uix/sliverappbar/sliverappbar.kv,sha256=_Ck4u11h0HJUQa4gNwEkCBR28xHspd6KNhZ-1oHPzac,1208 -kivymd/uix/sliverappbar/sliverappbar.py,sha256=ABfFDECbD9dbefONxHxKd6qFDhS-WNGOtlZE81r5VPs,14833 -kivymd/uix/snackbar/__init__.py,sha256=wG6Czix7Tb-3f69MAZqdxy2oY_-lQF8mYHQ_rueZ2lI,124 -kivymd/uix/snackbar/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/snackbar/__pycache__/snackbar.cpython-311.pyc,, -kivymd/uix/snackbar/snackbar.kv,sha256=M0HYjCKUR6-aSrleQaqVjXzrO2tbhCTgyuYTgn0s3S8,761 -kivymd/uix/snackbar/snackbar.py,sha256=9alYRqr9yxqFlMPHbuUrXCCcron2VOZiZSA_7hZz9gA,14432 -kivymd/uix/spinner/__init__.py,sha256=QI6bPGhsNGXXrXR-fPvEkbEfTUF3V3tY1wHTx_zZAJI,44 -kivymd/uix/spinner/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/spinner/__pycache__/spinner.cpython-311.pyc,, -kivymd/uix/spinner/spinner.kv,sha256=UerB-S-STJiBnjZw6HsRqAGCNxLw0bvfu5EegQQpzDQ,521 -kivymd/uix/spinner/spinner.py,sha256=PCRVUq07-ZP0ADAWSz5vATEZE9Blx62onzKc_AdOoNs,9121 -kivymd/uix/stacklayout.py,sha256=VE-OemocOjID3yVA6cwOt1KUn64NwdVCgVA1ssD1nAM,1724 -kivymd/uix/swiper/__init__.py,sha256=yjVyswA0HfoLRx9UW7k_GR497shvH5EthBbQk8CoU_4,43 -kivymd/uix/swiper/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/swiper/__pycache__/swiper.cpython-311.pyc,, -kivymd/uix/swiper/swiper.kv,sha256=iTaioAm-1WWmrGV4mqTizz3f4Qobv8WJZT-cwhEqyD0,291 -kivymd/uix/swiper/swiper.py,sha256=4Wwnj_jFvNhRlyPFvyXyPt01ZHeJt_25KcyjeZAB-II,14656 -kivymd/uix/tab/__init__.py,sha256=ui2pD_Y163wYI19O3JdSlVHhXUs83FHQUrZFi9FcGHs,62 -kivymd/uix/tab/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/tab/__pycache__/tab.cpython-311.pyc,, -kivymd/uix/tab/tab.kv,sha256=UuHLg4fS1CwROB4wwjWLxOmFk7xU5W78qWLZxSMMvSM,3809 -kivymd/uix/tab/tab.py,sha256=WnsmGmgjPWTYbtuNkOLRZSFRciGZwHOaaAWS_zHJaNM,67730 -kivymd/uix/taptargetview.py,sha256=8oIPH-HC-kxSOsKua0NJqeacb1oxjNIExPDFz46p3-k,26995 -kivymd/uix/templates/__init__.py,sha256=N58Ktx4cjBdiBsabyRkeJKOczHNQCGhWpQV_bGEy6CY,216 -kivymd/uix/templates/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/templates/rotatewidget/__init__.py,sha256=44Zf8a5sc5FSSfYX2RTWLAikbOzgi9g3Sm_LhroTsv4,39 -kivymd/uix/templates/rotatewidget/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/templates/rotatewidget/__pycache__/rotatewidget.cpython-311.pyc,, -kivymd/uix/templates/rotatewidget/rotatewidget.py,sha256=Ea9ImstSgTxTeNKikN7GQlu_tWcgjaAkE-iMJpuYAr4,764 -kivymd/uix/templates/scalewidget/__init__.py,sha256=QeR6z6AC4N1ylUnh0aI2cBAVDuOhsqUNF0Ux9Dza2zQ,37 -kivymd/uix/templates/scalewidget/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/templates/scalewidget/__pycache__/scalewidget.cpython-311.pyc,, -kivymd/uix/templates/scalewidget/scalewidget.py,sha256=xnV2r-bw3gwvhyiwWtueNkCODC7uTg2sSJCNwlTSWuA,804 -kivymd/uix/templates/stencilwidget/__init__.py,sha256=1hoHSMc_CudX4ixsz4dlvAPQi_ppki1ht1zi7oSza_g,41 -kivymd/uix/templates/stencilwidget/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/templates/stencilwidget/__pycache__/stencilwidget.cpython-311.pyc,, -kivymd/uix/templates/stencilwidget/stencilwidget.py,sha256=VbMTYBRJXH1BGh-1jxFIXLZVGOfVj47K-1DHCzCQG4U,843 -kivymd/uix/textfield/__init__.py,sha256=TsquVODAqOW9KRaVdZEwDSuj84xNu3btukztMO1u-R8,64 -kivymd/uix/textfield/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/textfield/__pycache__/textfield.cpython-311.pyc,, -kivymd/uix/textfield/textfield.kv,sha256=1YRvhffqhGvrTT6ak7-9Q8igtweGh3heUkudK5vAsog,11995 -kivymd/uix/textfield/textfield.py,sha256=ZgKSMcO0rPjbgbhZ9sKDtCEZ4UsQS9AlUhaJkwgS9fc,66314 -kivymd/uix/toolbar/__init__.py,sha256=ERxUgGcxjesHxwJoadRRiboL22K2gdMaIu1h57GJCcM,163 -kivymd/uix/toolbar/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/toolbar/__pycache__/toolbar.cpython-311.pyc,, -kivymd/uix/toolbar/toolbar.kv,sha256=XTLAQDaSN1lMW350XzY1Wy9gpIm-GVWQzuBhngsr2-g,3569 -kivymd/uix/toolbar/toolbar.py,sha256=qOySilG3qNjHwyFEKfcqWEzbTjeLLIEc0h1JwM9QwIU,67947 -kivymd/uix/tooltip/__init__.py,sha256=TrHnzd6U1iKu-TzPaBG4jPRL7Cdaa91FqQQiS37ce9o,64 -kivymd/uix/tooltip/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/tooltip/__pycache__/tooltip.cpython-311.pyc,, -kivymd/uix/tooltip/tooltip.kv,sha256=eiA1FwuWCUm8BTdTilYPS01V2lDoVh0mW-BkeEldGPY,1171 -kivymd/uix/tooltip/tooltip.py,sha256=_-crrT-DxKx12VGfCBqe3sV_nIPTmdklEDRGhngAl4k,10861 -kivymd/uix/transition/__init__.py,sha256=QA3XDj483c_iPrbiVHdkvVZhCKPu495dr5_6hBZRLgw,113 -kivymd/uix/transition/__pycache__/__init__.cpython-311.pyc,, -kivymd/uix/transition/__pycache__/transition.cpython-311.pyc,, -kivymd/uix/transition/transition.py,sha256=xwN5NcfogHwl4xeuzA1R49Vu88LBpuwmmv2N394UWV0,11349 -kivymd/uix/widget.py,sha256=6oQLzQuKgp4Rnulq63Zlw4fPjJ0RmkttrFx7NJbCMug,1074 -kivymd/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -kivymd/utils/__pycache__/__init__.cpython-311.pyc,, -kivymd/utils/__pycache__/asynckivy.cpython-311.pyc,, -kivymd/utils/__pycache__/fpsmonitor.cpython-311.pyc,, -kivymd/utils/__pycache__/set_bars_colors.cpython-311.pyc,, -kivymd/utils/asynckivy.py,sha256=veVrps6-mxT5JFgRpwzZ18_HFzx9CeG4IZomp8cTtyQ,1544 -kivymd/utils/fpsmonitor.py,sha256=QzWJs1lr9SIk2NDVeDUC2HRSyMXNXTWB39HvLDtL0vI,1024 -kivymd/utils/set_bars_colors.py,sha256=uhCQdrRhRW-P--5D5MJR6rcauOA8wmiFoapJJczkf14,4050 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/INSTALLER b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/LICENSE b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/LICENSE similarity index 65% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/LICENSE rename to kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/LICENSE index d096ac4..d96b44f 100755 --- a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/LICENSE +++ b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/LICENSE @@ -1,18 +1,7 @@ MIT License -Copyright (c) 2022 Andrés Rodríguez and other contributors - KivyMD library up to version 0.1.2 -Copyright (c) 2022 KivyMD Team and other contributors - KivyMD library version 0.1.3 and higher - -Other libraries used in the project: - -Copyright (c) 2010-2022 Kivy Team and other contributors -Copyright (c) 2022 Brian Knapp - Androidoast library -Copyright (c) 2022 LogicalDash - stiffscroll library -Copyright (c) 2022 Kivy Garden - tabs module -Copyright (c) 2022 Nattōsai Mitō - asynckivy module -Copyright (c) 2022 tshirtman - magic_behavior module -Copyright (c) 2022 shashi278 - taptargetview module -Copyright (c) 2022 Benedikt Zwölfer - fitimage module +Copyright (c) 2024 Andrés Rodríguez and other contributors - KivyMD library up to version 0.1.2 +Copyright (c) 2024 KivyMD Team and other contributors - KivyMD library version 0.1.3 and higher Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/METADATA b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/METADATA similarity index 93% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/METADATA rename to kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/METADATA index 16bda35..2374a98 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/METADATA +++ b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: kivymd -Version: 1.2.0 +Version: 2.0.1.dev0 Summary: Set of widgets for Kivy inspired by Google's Material Design Home-page: https://github.com/kivymd/KivyMD Author: Andres Rodriguez, fork author - Ivanov Yuri @@ -40,8 +40,10 @@ Classifier: Topic :: Scientific/Engineering :: Visualization Requires-Python: >=3.7 Description-Content-Type: text/markdown; charset=UTF-8 License-File: LICENSE -Requires-Dist: kivy>=2.2.0 +Requires-Dist: kivy>=2.3.0 Requires-Dist: pillow +Requires-Dist: materialyoucolor>=2.0.7 +Requires-Dist: asynckivy<0.7,>=0.6 Provides-Extra: dev Requires-Dist: pre-commit; extra == "dev" Requires-Dist: black; extra == "dev" @@ -54,14 +56,14 @@ Requires-Dist: pytest-timeout; extra == "dev" Requires-Dist: coveralls; extra == "dev" Requires-Dist: pyinstaller[hook_testing]; extra == "dev" Provides-Extra: docs -Requires-Dist: sphinx; extra == "docs" -Requires-Dist: sphinx-autoapi==1.4.0; extra == "docs" -Requires-Dist: furo; extra == "docs" +Requires-Dist: sphinx==7.3.7; extra == "docs" +Requires-Dist: sphinx-autoapi==3.0.0; extra == "docs" +Requires-Dist: sphinx-book-theme; extra == "docs" Requires-Dist: sphinx-notfound-page; extra == "docs" Requires-Dist: sphinx-copybutton; extra == "docs" Requires-Dist: sphinx-tabs; extra == "docs" -# KivyMD [1.2.0](https://kivymd.readthedocs.io/en/latest/changelog/index.html) +# KivyMD [2.0.0](https://kivymd.readthedocs.io/en/latest/changelog/index.html) @@ -106,15 +108,16 @@ may be offered to you without asking too. ## Installation ```bash -pip install kivymd==1.2.0 +pip install kivymd==2.0.0 ``` ### Dependencies: -- [Kivy](https://github.com/kivy/kivy) >= 2.2.0 ([Installation](https://kivy.org/doc/stable/gettingstarted/installation.html)) +- [Kivy](https://github.com/kivy/kivy) >= 2.3.0 ([Installation](https://kivy.org/doc/stable/gettingstarted/installation.html)) - [Python 3.7+](https://www.python.org/) - [Pillow](https://github.com/python-pillow/Pillow/) -- [MaterialColor](https://github.com/T-Dynamos/materialyoucolor-pyhton) +- [MaterialColor](https://github.com/T-Dynamos/materialyoucolor-python) +- [asynckivy](https://github.com/asyncgui/asynckivy) ### How to install @@ -144,25 +147,16 @@ pip install . use a shallow clone (`git clone https://github.com/kivymd/KivyMD.git --depth 1`) to save time. If you need full commit history, then remove `--depth 1`. -### How to fix a shader bug on an android device - -Use `Kivy` from master branch or `Kivy` >= `2.2.0` and `KivyMD` (from master branch): - -```bash -pip install https://github.com/kivy/kivy/archive/master.zip -pip install https://github.com/kivymd/KivyMD/archive/master.zip -``` - -And use with `Buildozer`: - -```ini -requirements = kivy==master, https://github.com/kivymd/KivyMD/archive/master.zip -``` - ### How to use with [Buildozer](https://github.com/kivy/buildozer) ```ini -requirements = kivy==2.2.0, kivymd==1.2.0 +requirements = python3, + kivy, + https://github.com/kivymd/KivyMD/archive/master.zip, + materialyoucolor, + exceptiongroup, + asyncgui, + asynckivy ``` This will download latest release version of KivyMD from [PyPI](https://pypi.org/project/kivymd). @@ -171,7 +165,7 @@ If you want to use development version from [master](https://github.com/kivymd/K branch, you should specify link to zip archive: ```ini -requirements = kivy==2.1.0, https://github.com/kivymd/KivyMD/archive/master.zip +requirements = kivy, https://github.com/kivymd/KivyMD/archive/master.zip ``` Do not forget to run `buildozer android clean` or remove `.buildozer` directory @@ -356,6 +350,13 @@ and get your logo on our Readme with a link to your website. + + + + Best Route Planner - Route Optimization Software + + + #### Backers [Become a Backer](https://opencollective.com/kivymd/contribute/backer-16159) if you want to help develop this project. diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/RECORD b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/RECORD new file mode 100644 index 0000000..1557651 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/RECORD @@ -0,0 +1,332 @@ +../../../bin/kivymd.add_view,sha256=u2N52U9NKr85se5a66gdG5Old498YxKwDezJ-cwIZAY,266 +../../../bin/kivymd.create_project,sha256=6LnjVohJ7V3MZYfVCtWqtyHHaku6Io-y0pN1BFPmDAM,272 +../../../bin/kivymd.make_release,sha256=hKmHIsjNRMSeSS3A2PNqeer_kEliqi6NhzI9bmLc0Zo,269 +kivymd-2.0.1.dev0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +kivymd-2.0.1.dev0.dist-info/LICENSE,sha256=mAllwI3MAD8PljsyLcDu8ByZZYChrptzwCCA7pXK-70,1230 +kivymd-2.0.1.dev0.dist-info/METADATA,sha256=gFwEntEUBVZqXg9ZkEARN2wJJ3LRdRr49tfGGCKZt3c,15236 +kivymd-2.0.1.dev0.dist-info/RECORD,, +kivymd-2.0.1.dev0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd-2.0.1.dev0.dist-info/WHEEL,sha256=pL8R0wFFS65tNSRnaOVrsw9EOkOqxLrlUPenUYnJKNo,91 +kivymd-2.0.1.dev0.dist-info/direct_url.json,sha256=4K7_rCzsQAA6VPgFZkDLzO5m3GluAszqZihOmO2M4Lo,82 +kivymd-2.0.1.dev0.dist-info/entry_points.txt,sha256=1-yhsSzIhBNRiKNTmevRDT02q8qzg3upZcWAyrr880w,342 +kivymd-2.0.1.dev0.dist-info/top_level.txt,sha256=ABq82F4nFM8sy3xAhxiO5XXT_lAen0YqiDD29qRiPhc,7 +kivymd/__init__.py,sha256=d_a46HKOE97-WwIhBsv9yjAciPPx7yOLTeVzDynBVMI,1957 +kivymd/__pycache__/__init__.cpython-311.pyc,, +kivymd/__pycache__/_version.cpython-311.pyc,, +kivymd/__pycache__/animation.cpython-311.pyc,, +kivymd/__pycache__/app.cpython-311.pyc,, +kivymd/__pycache__/dynamic_color.cpython-311.pyc,, +kivymd/__pycache__/factory_registers.cpython-311.pyc,, +kivymd/__pycache__/font_definitions.cpython-311.pyc,, +kivymd/__pycache__/icon_definitions.cpython-311.pyc,, +kivymd/__pycache__/material_resources.cpython-311.pyc,, +kivymd/__pycache__/theming.cpython-311.pyc,, +kivymd/_version.py,sha256=6I20Wxx3c8MaIw5uF7UNh0yNERX7X5SkzUyMzzVsxno,115 +kivymd/animation.py,sha256=UMkBmLxjTlgz_tPVYrAGYxPIgVWAshAZivwlX_t983Q,6361 +kivymd/app.py,sha256=7As7g0jn_HnzRNDwPvulXGQtLd208x4Bm8dIeaRtEpE,4921 +kivymd/dynamic_color.py,sha256=jjlCogPmF5nmNHZzg9eG2YKZkoGtPUgaMb67RD5KGNo,16408 +kivymd/effects/__init__.py,sha256=ySU96kLlmPF4QB-hDa0WM_Y0Odq1MPSR568yI_hiaqI,24 +kivymd/effects/__pycache__/__init__.cpython-311.pyc,, +kivymd/effects/stiffscroll/__init__.py,sha256=tkGDtFz6s7W3iFtHRDo6NYWadL85cn7GXKAQQfpiJRk,43 +kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc,, +kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc,, +kivymd/effects/stiffscroll/stiffscroll.py,sha256=3bSj43xOzhBcBSn58iLUiaNWevlHuO8seklAyfvZsJE,7117 +kivymd/factory_registers.py,sha256=MEdyWS0DPv8XnVbLEbygs_8pB0DHoNLPxLO56Qn9GX0,7775 +kivymd/font_definitions.py,sha256=4WLZWIPY_hdCbY3a-8mPhL-0pmxMmWvBbzN9MDqRo4E,3774 +kivymd/fonts/Roboto-Black.ttf,sha256=Ws4NCDOrg_8Y6pTkp3RfkZxFiuTqvCmCGCJt9CdczU0,168060 +kivymd/fonts/Roboto-BlackItalic.ttf,sha256=iy-H-wj_S11i51PHUP4ykYE1hlAfoU3SWLGtC_ulM64,174108 +kivymd/fonts/Roboto-Bold.ttf,sha256=7GhaRhBSlv5GyHRNpKEc-BGLpsEScZQXZvelRt9qp8c,167336 +kivymd/fonts/Roboto-BoldItalic.ttf,sha256=Yd9Zf3PJHyOMvoj-PFNnAtEg0Ei3myX6D094GP0SOm8,171508 +kivymd/fonts/Roboto-Italic.ttf,sha256=meSoUGETbpngUpKe0NheNjhPulw0t3MTmo9kM5xgmUM,170504 +kivymd/fonts/Roboto-Light.ttf,sha256=xXbFBkInG82__-0E-S3I1qmB2vMAkU0KIMilpaVwFcc,167000 +kivymd/fonts/Roboto-LightItalic.ttf,sha256=pIQGImhU00_plkKlJKQ7L9Jqfb7KgC1RAKipjSDhtz0,173172 +kivymd/fonts/Roboto-Medium.ttf,sha256=nQ1VowO_0Tt5qHch9lGF6T8jXi13_jmLLcpnrFGZFfU,168644 +kivymd/fonts/Roboto-MediumItalic.ttf,sha256=0_MXyX9AA4ksuWm8_OjePcnWf7-W_a-miy41lTF7DZQ,173416 +kivymd/fonts/Roboto-Regular.ttf,sha256=ThR6tkuf322J0B9rjDygs83cWdYIqOIhj5olBLXJjhQ,168260 +kivymd/fonts/Roboto-Thin.ttf,sha256=ZySPfoxu2zzn73Ow8ApTSn9CwRFs72POIbIDW16XmgY,168488 +kivymd/fonts/Roboto-ThinItalic.ttf,sha256=KM4lGpnNV9AKmCJaj8tmtgtp2vELCUfH7E7VA8Iq_-8,172860 +kivymd/fonts/materialdesignicons-webfont.ttf,sha256=YeirpaTpgf4iz3yOi82-oAR251xiw38Bv37jM2HWhCg,1307660 +kivymd/icon_definitions.py,sha256=DAc0bD1hlaFBeIiHo5p2_HFzZHr7IUhBXC3t3SBRffQ,282946 +kivymd/images/folder.png,sha256=xY9uUYegh7hDzFI4iPEA-zyFBzq9IE007zaJGGY5JY0,2311 +kivymd/images/logo/kivymd-icon-128.png,sha256=VjWHaIJ-MSyP7ZnM25xgBfp_wG4vbQhr8B8QOTcXeaM,19826 +kivymd/images/logo/kivymd-icon-256.png,sha256=5iJVryvz0D-IvqLGTsaeJlYhZYk2R7OxskKiNgw25Ks,31943 +kivymd/images/logo/kivymd-icon-512.png,sha256=JAtfTEA7AWBPcMhFGqlwSQmQSq-lWAEJ8Y98qmDe0I0,54349 +kivymd/images/transparent.png,sha256=yM2bydAM4U0tnbs4zAuK2GnCC6I6NgAIfpw7rQhG1BQ,156 +kivymd/material_resources.py,sha256=XnkSLVe-kTAEmEl9QzJRV-qs5sgmXjKT-V5GY30KXjY,576 +kivymd/theming.py,sha256=4dUslqibyGwEd9noplpmhGbH9daoGfdaqr-XlP55a-E,33018 +kivymd/toast/__init__.py,sha256=AWk597R4COWhbrfiUSjceBpmeaVer3-f3-L4dHOCQEY,54 +kivymd/toast/__pycache__/__init__.cpython-311.pyc,, +kivymd/toast/__pycache__/androidtoast.cpython-311.pyc,, +kivymd/toast/androidtoast.py,sha256=nPo0oay5MbILuwE36H4B_WtbMtAMSNtH89bCbZF0ULU,2361 +kivymd/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/tools/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/__pycache__/argument_parser.cpython-311.pyc,, +kivymd/tools/argument_parser.py,sha256=oxgJoS5WZH_ATDlaEU0HDtm7ve4DOJ23CnOILIBygy8,3193 +kivymd/tools/hotreload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc,, +kivymd/tools/hotreload/app.py,sha256=cJxyUxz1GbQ58pgPY3GZNSl-CoawoPUPoCUF3lECltI,16803 +kivymd/tools/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/packaging/pyinstaller/__init__.py,sha256=ibpoURJJkyGuSgWhz8t-RuLnCmQf15TiFNr-HKTCPHA,1480 +kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc,, +kivymd/tools/packaging/pyinstaller/hook-kivymd.py,sha256=cN0arGlcA_vLA8FTaAdzKgn7s2YQRCclv7G0e4c4o-Y,1053 +kivymd/tools/patterns/MVC/Model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc,, +kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc,, +kivymd/tools/patterns/MVC/Model/database_firebase.py,sha256=5SlPAn-ROkh_ytnv2nteaVRAMC0MUSDM9u115Crfh-o,1376 +kivymd/tools/patterns/MVC/Model/database_restdb.py,sha256=Wc-zPffP-Wriyn-JGKCQrw3SGZMiAk-8LrVjParRtGM,3866 +kivymd/tools/patterns/MVC/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/patterns/MVC/data/locales/po/en.po,sha256=1b2jIsEnyQi_T_gnpe5QeO90IdaQLwWClk5pn46ZjME,425 +kivymd/tools/patterns/MVC/data/locales/po/ru.po,sha256=mQd6ol2abec-PUJsrnRWNoah0din3IAg_F4gPf5VBVw,425 +kivymd/tools/patterns/MVC/libs/__init__.py,sha256=B6Kln9GZ6UrMOxr4lOnpTxGBMaoKlcar5wpyTGyUlIk,54 +kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc,, +kivymd/tools/patterns/MVC/libs/translation.py,sha256=LiiMZUxVbAmUy71mVA-PyEkxwYrCAOcjeiDnlbCSPvQ,1411 +kivymd/tools/patterns/MVC/messages.pot,sha256=2cutqkylhtiY07tkXzE8yNqpux9eeoW3tdeoEbXdB1Y,582 +kivymd/tools/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc,, +kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc,, +kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc,, +kivymd/tools/patterns/add_view.py,sha256=4J41yOosi9KkNrMBI6h6yJ_0LoncdJzmJDy-iShaArk,6576 +kivymd/tools/patterns/create_project.py,sha256=x3g37U3Dbk-ivUJ_aGgwvjpwBkyM4zIcPF3Bcyw1ASQ,39373 +kivymd/uix/__init__.py,sha256=OP4CD9D1ezU3v3LGF0Yo91GIMIIJAUPMFSZNSLWdLOo,2793 +kivymd/uix/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc,, +kivymd/uix/__pycache__/boxlayout.cpython-311.pyc,, +kivymd/uix/__pycache__/circularlayout.cpython-311.pyc,, +kivymd/uix/__pycache__/floatlayout.cpython-311.pyc,, +kivymd/uix/__pycache__/gridlayout.cpython-311.pyc,, +kivymd/uix/__pycache__/hero.cpython-311.pyc,, +kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc,, +kivymd/uix/__pycache__/recycleview.cpython-311.pyc,, +kivymd/uix/__pycache__/relativelayout.cpython-311.pyc,, +kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc,, +kivymd/uix/__pycache__/screen.cpython-311.pyc,, +kivymd/uix/__pycache__/screenmanager.cpython-311.pyc,, +kivymd/uix/__pycache__/scrollview.cpython-311.pyc,, +kivymd/uix/__pycache__/stacklayout.cpython-311.pyc,, +kivymd/uix/__pycache__/widget.cpython-311.pyc,, +kivymd/uix/anchorlayout.py,sha256=K40IAwhpYiCemdh9jvOtTYF4IHnF3wdce3CjD6gXQy4,1365 +kivymd/uix/appbar/__init__.py,sha256=rL3GwJPgu7s0GcKDYri7sDtIznAYaniO2B_UxVEWU7A,264 +kivymd/uix/appbar/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/appbar/__pycache__/appbar.cpython-311.pyc,, +kivymd/uix/appbar/appbar.kv,sha256=EsSrZb-6aoYWc_kCZODw0EH6kzrTsbBESmRGv5ADzvU,2565 +kivymd/uix/appbar/appbar.py,sha256=6dquqLBAOLaBkxiwG7RQKAFF7t1OjHkBm8U83EGnSqg,38722 +kivymd/uix/badge/__init__.py,sha256=7CIBe8jXrxme7ankbSEmiPjT0EbJhPqawZHEcUa17mk,40 +kivymd/uix/badge/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/badge/__pycache__/badge.cpython-311.pyc,, +kivymd/uix/badge/badge.kv,sha256=LW70SjdLKfULFydUYceLZCLE3ulJdjUI9DLOe5zo-Ck,545 +kivymd/uix/badge/badge.py,sha256=3coq8IQq9St8t2lQOVA4gzu9ZEk3owPBCh4VdI-lnMk,1429 +kivymd/uix/behaviors/__init__.py,sha256=VWDGd99o9hPc4Ej4nuQmuVk8P3jRU4D2iQGj9h3zUyo,745 +kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/state_layer_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc,, +kivymd/uix/behaviors/backgroundcolor_behavior.py,sha256=wtIo7A8wBr562wc9MliDk3vLkQGl8MzOEnWT6E-Jiqg,5275 +kivymd/uix/behaviors/declarative_behavior.py,sha256=E6vfUjq5QoVhm7pO5BKbWZrZjiLLq0wJ-lpKDi6mwgY,9776 +kivymd/uix/behaviors/elevation.py,sha256=ybmb_IQnpLv2gZZWrEhvp5hwNxDkapdZ9IfQFD7ciFI,20274 +kivymd/uix/behaviors/focus_behavior.py,sha256=lE84JzIeMGQyoRLYPt2z2OyaoNaJ6irKMUBhjzxKwa8,2865 +kivymd/uix/behaviors/hover_behavior.py,sha256=4Dslyh8758uViHlpbJOWzOqF0I-XEdrfO-NbWbFxZ-k,7745 +kivymd/uix/behaviors/magic_behavior.py,sha256=wwN40b_0NTG3Dopdhqt89PXYqY5mXSM4lY2xuIk1v9Q,4570 +kivymd/uix/behaviors/motion_behavior.py,sha256=Jl7v9KM19gRjXQ5K-stwtj89udxn20pKRSbYjnFd1ek,13820 +kivymd/uix/behaviors/ripple_behavior.py,sha256=o2Nl94jjd7HhH0b5kwEQcby1IAZT-gcjVaYTX6Vs4yg,16973 +kivymd/uix/behaviors/rotate_behavior.py,sha256=Z8Ux_UwKZHoeu-cCl8hNc2EDVgC_hWni-ld8BpbL1uE,3268 +kivymd/uix/behaviors/scale_behavior.py,sha256=2ONpA7LKW5UhNI-ibBLlyQtOP_xyHDkasNxmqLO-z_c,4062 +kivymd/uix/behaviors/state_layer_behavior.py,sha256=vr_ZNA8ggVcqDIjNDHgsa66HqlzoO4BgNOQeF4CCrLI,22138 +kivymd/uix/behaviors/stencil_behavior.py,sha256=yJtQY5Te-sa635lhz0pRwGGfyJeG5NtuzKpw3x1i8tw,3015 +kivymd/uix/behaviors/toggle_behavior.py,sha256=9dcZhoFTDMYNEMY8vNn0_Ei9VMLzy1aHyu26RcAOxEs,8644 +kivymd/uix/behaviors/touch_behavior.py,sha256=tOxMS2XyX-8o9romBRSqJJ-G0_Kp1P7mDXyylOC1t1U,2776 +kivymd/uix/bottomsheet/__init__.py,sha256=_pvnNLykM_K6xdruglPD6BbAmq7jo2uXfLarsoehxeo,158 +kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc,, +kivymd/uix/bottomsheet/bottomsheet.kv,sha256=bemuxX5ABIiWP1v_dddvTEGaVwCJO6tOB6xSlgSj_jU,1163 +kivymd/uix/bottomsheet/bottomsheet.py,sha256=NBm4KJe4zPbdYHZ78jgxUj2YCjrJExd0Mdmq9sYys2E,12793 +kivymd/uix/boxlayout.py,sha256=KKONYwmEON79f2c6TLCxN4KNDj7E9yvuXs2oT5vEiMc,2031 +kivymd/uix/button/__init__.py,sha256=YhX34jdEnmi9kDofnQXg5v3H1NJWC_uX10f5fOmMFuo,239 +kivymd/uix/button/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/button/__pycache__/button.cpython-311.pyc,, +kivymd/uix/button/button.kv,sha256=0dJtZ_6IzOXbmHsBCDG64-OawofWV1okG1-eWP5nwQk,13278 +kivymd/uix/button/button.py,sha256=D7Rg3a4nT6zEJIZ6QONTigHfukAyQX8Ly1CuZ6tVINU,32731 +kivymd/uix/card/__init__.py,sha256=hjAO06DlaWnFP_wYQC5ZFMR4lobKDY0aztACZCvWgd8,113 +kivymd/uix/card/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/card/__pycache__/card.cpython-311.pyc,, +kivymd/uix/card/card.kv,sha256=DZMWfl8xWTrWaZ35miD23vBNtl5g_86QY3tv3mMyGdo,2926 +kivymd/uix/card/card.py,sha256=vdewoU57GGQDC5JjPsd3Z8Xy5aCKRtX_sEpYbpU7kig,27567 +kivymd/uix/chip/__init__.py,sha256=1uvEh6w800aZE4KV-LA6xch01o8Netw-h8N3Wy4Jb6E,135 +kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/chip/__pycache__/chip.cpython-311.pyc,, +kivymd/uix/chip/chip.kv,sha256=WUigEnF_XgGmwpv-5OUxaMY8LRZeXWxD4Ew36tk0JHI,3445 +kivymd/uix/chip/chip.py,sha256=n5-qQWzqXr6-eTGavpU7apsgX7WdsSnAP2MhKQ_6DyA,35420 +kivymd/uix/circularlayout.py,sha256=S5Z4R2Z7ENwSoDB-UqWjOl0lCoemTessK_C4KT3jru8,5407 +kivymd/uix/controllers/__init__.py,sha256=WNbi76mp899CTLeSZUnVJ0b5gSeUMJ9ganvmhEcNR40,231 +kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc,, +kivymd/uix/controllers/windowcontroller.py,sha256=msVZQJwaekkIw4XUECXWAMOAsXw5NkFe38xIel1wG84,2335 +kivymd/uix/dialog/__init__.py,sha256=6dLZqaNu832pAEUyZBrEU6BdQ46SSOx9LI8jOMsnHD4,182 +kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc,, +kivymd/uix/dialog/dialog.kv,sha256=cLK7ZK50QwBmT73D3WgjnGbGGQ0BLrkQ8VHYmwFLFVA,2958 +kivymd/uix/dialog/dialog.py,sha256=iAr3ur0C0afToFtVXYSVpJrswIn6LX5_0IHZXaiobQI,18598 +kivymd/uix/divider/__init__.py,sha256=p52N9PonSJQ90tycWEJRDRpk8-D5R-ClBX0NN3xycl0,44 +kivymd/uix/divider/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/divider/__pycache__/divider.cpython-311.pyc,, +kivymd/uix/divider/divider.kv,sha256=hn-zA8BMGFadxbyojHmC07pvge-TLSxF0VCv2sMPizE,250 +kivymd/uix/divider/divider.py,sha256=GRPGVGjSQEaIefqehWO5untZom69GD-OgIAaGd7srhY,3702 +kivymd/uix/dropdownitem/__init__.py,sha256=e4eaF7uU5hU119DKcnTkj2hC-DtQoJ5gpx4n-EilUvI,74 +kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc,, +kivymd/uix/dropdownitem/dropdownitem.kv,sha256=7ZljjTLoW__Fixl4jPTJG96upstMIfRxijwFLmbsWvc,1180 +kivymd/uix/dropdownitem/dropdownitem.py,sha256=6uneYSSjErpJSYaFnjGMNsOodt8c0VIs8OlZyKzRZkg,4773 +kivymd/uix/expansionpanel/__init__.py,sha256=OFJC5zK9iAI9doEVtptYDVPRuCQ2WTqd8LjScXQetEA,123 +kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc,, +kivymd/uix/expansionpanel/expansionpanel.kv,sha256=vK3HR_n4ihGzD-lRSV5Y_RKRdk5a151YjUr7QlClK78,279 +kivymd/uix/expansionpanel/expansionpanel.py,sha256=9KwYGUFkpZGdLrnHZ2YsVovDzDE9vwqRlHnffRT8dzo,14722 +kivymd/uix/filemanager/__init__.py,sha256=TR0eAXbR-lzZUQLiVcGcVp5D1myeiLoXGpSWZitrWKI,52 +kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc,, +kivymd/uix/filemanager/filemanager.kv,sha256=chfHadHr34MRk_UAuqPv9MOWLFhV_Ne84XfqL-NQF0I,2550 +kivymd/uix/filemanager/filemanager.py,sha256=Bsd_iFa2Yk_1JsW6rgobOOV2jOZDORrV5d5Y8IO9FWY,25902 +kivymd/uix/fitimage/__init__.py,sha256=BVf16byn839UfzikgsfJj_s5xH0PjGgU9gUuetb1dsU,44 +kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc,, +kivymd/uix/fitimage/fitimage.py,sha256=r364DXB21psGT2Mw8MIDZtXYgTbujb0ya6b5t5PD1jA,3250 +kivymd/uix/floatlayout.py,sha256=QfF_RcIiG7ITlKfxvsmcW0gy97fXdk5BmVVyvAqibpg,1541 +kivymd/uix/gridlayout.py,sha256=HJCj1dEvIXwJj0tOK9lWNgovFYMMUAmtf5-SZO9__f8,2013 +kivymd/uix/hero.py,sha256=Pkdo1qCbwQnErS8zExJBOO23pM2TM56UaKgaftGwCq8,18420 +kivymd/uix/imagelist/__init__.py,sha256=VgCXsVvUFA9yfBpB3cEwLWqQR0_s6um2SMohe0wTcv4,111 +kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc,, +kivymd/uix/imagelist/imagelist.kv,sha256=ukH2JEHvszq165W2Joylu7HoVl3pKYqMd7xhk_YWR54,1052 +kivymd/uix/imagelist/imagelist.py,sha256=hfJphayTAaVMQ-2BQsq5I3u8Tvyzm4ka_yNfNmAlRBg,7010 +kivymd/uix/label/__init__.py,sha256=DHLIPzLH5Uq0ChimIQIUVHQ42iAilC-F2xYzWqeqiXY,48 +kivymd/uix/label/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/label/__pycache__/label.cpython-311.pyc,, +kivymd/uix/label/label.kv,sha256=wCK0divTBiNdEqsDlxLAWStH69MYIDiLqiVZw9wg9fA,1323 +kivymd/uix/label/label.py,sha256=cQVTn_ArbRQsoPXMq-tgDP99ebU05oF4fILP-TQZPoc,26088 +kivymd/uix/list/__init__.py,sha256=JQbupFYB2E24FxZaz4y94ImASKQfS1eGrZPdfEpJ4-E,364 +kivymd/uix/list/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/list/__pycache__/list.cpython-311.pyc,, +kivymd/uix/list/list.kv,sha256=T7A3DeE6Vcsba2UacXMPPck2OBo2Kxzp7OOWPt1GjoI,4563 +kivymd/uix/list/list.py,sha256=koECDdLVSW1gluCNYT-VEST8N3fV6Y-jkAenKQ8fWXs,16560 +kivymd/uix/menu/__init__.py,sha256=2a7cHJKvQmKiqu4_YWWQMF96owFFkRiMnEPX2R_kMbA,46 +kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/menu/__pycache__/menu.cpython-311.pyc,, +kivymd/uix/menu/menu.kv,sha256=f35OBRCv2GiFoIoQsmJiD5OO6HJBMtWvtGFG8l7Njks,13637 +kivymd/uix/menu/menu.py,sha256=s5ykbqIKmZokiYRCbNsPImOrPxulVxuQnmOxEjl-sr8,40145 +kivymd/uix/navigationbar/__init__.py,sha256=a30ldn9-lWqS5o8UjCD2T2bUF95jRiC-yKF_r3KqXOs,139 +kivymd/uix/navigationbar/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/navigationbar/__pycache__/navigationbar.cpython-311.pyc,, +kivymd/uix/navigationbar/navigationbar.kv,sha256=-yaGGm2VOpgyAhvTtRNQD5rVKRuga9ZaADtbPgj-9SA,4035 +kivymd/uix/navigationbar/navigationbar.py,sha256=NCULciX76Vbe6DkQnWXhcDmRb8zvoaMGpdt9h07CgSQ,17122 +kivymd/uix/navigationdrawer/__init__.py,sha256=JNRnAbxuu0x2Xb8oO7lwBjKwKnYn2grJo_RZBcvBEIA,351 +kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc,, +kivymd/uix/navigationdrawer/navigationdrawer.kv,sha256=R6xE6aRpthfbeEfUm62pvnWRBA7uE-Za_mNa--H9JpA,2031 +kivymd/uix/navigationdrawer/navigationdrawer.py,sha256=gxkX3v9U5LCQXZLRPjcXJLoz_bUd-fTbP-M2H2qQCGM,38521 +kivymd/uix/navigationrail/__init__.py,sha256=1fQMqMVg-A3g6ZOFOrX-adJd8k9R7Xe5kijzq_U3Ksw,216 +kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc,, +kivymd/uix/navigationrail/navigationrail.kv,sha256=fMPYmHmNdS3WnSl2zpaxSuQMbLwg01YRU_3MbTh5eMs,2935 +kivymd/uix/navigationrail/navigationrail.py,sha256=MDMM8pdO5oGvH1gVGG4T2sLsz9lIWnrfR1C4qQe6Zsw,22302 +kivymd/uix/pickers/__init__.py,sha256=mhnmC4YAXu71eD90YcUe_l9kuMXUjHKALTFG6GdvtZM,242 +kivymd/uix/pickers/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/pickers/datepicker/__init__.py,sha256=gXQyrdPWJP9UxOwZ8VWuXZn8FB6S2AYnhl0FmAhI8Pc,116 +kivymd/uix/pickers/datepicker/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/pickers/datepicker/__pycache__/datepicker.cpython-311.pyc,, +kivymd/uix/pickers/datepicker/datepicker.kv,sha256=ZyWURj3ZzJ1Vb0-Fr4nI33sJQSLS2gAsjanoVHYBD5I,11736 +kivymd/uix/pickers/datepicker/datepicker.py,sha256=bYMdgC533VJdkR9vFVHM8mkyUyOrnUwbi7YvywR4hIs,60382 +kivymd/uix/pickers/timepicker/__init__.py,sha256=SBtSeGRb0VrrQgzFUGZxl0tQRwmUjKw5jpLhg371tNc,126 +kivymd/uix/pickers/timepicker/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/pickers/timepicker/__pycache__/timepicker.cpython-311.pyc,, +kivymd/uix/pickers/timepicker/timepicker.kv,sha256=xXlxSukPBj9L05B2hP-IdxEAvI3_O0hmuMQttlyCWGc,11334 +kivymd/uix/pickers/timepicker/timepicker.py,sha256=k6kbkVFug5fY_IN98j9YGWtewSsztqIVYa8zbQo51wY,38753 +kivymd/uix/progressindicator/__init__.py,sha256=dA8bwUMDtdx1CglUx3R73Xz6j9uUiiZT6qVphrx9me8,112 +kivymd/uix/progressindicator/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/progressindicator/__pycache__/progressindicator.cpython-311.pyc,, +kivymd/uix/progressindicator/progressindicator.kv,sha256=3XXvaGnEXAYpAFgQGE8gR3VGnYNYHapx827RBFtViDE,2221 +kivymd/uix/progressindicator/progressindicator.py,sha256=nuzNdqp1yGaQ6R80OQlYgXiYl42IPIRC2lRT9s1bwjw,18195 +kivymd/uix/recyclegridlayout.py,sha256=I399c4gsmyHAedTU1Biwd7QRYG60QJ-gx33WVct7CCc,2140 +kivymd/uix/recycleview.py,sha256=FVhr4SI0wjbQy08q68nDjh-Mqsdg6nfjwONZfHTBctY,1348 +kivymd/uix/refreshlayout/__init__.py,sha256=r6yH7AYvn831mRtdu6KN_p4L42JBJh2qKpNIuHyckao,66 +kivymd/uix/refreshlayout/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/refreshlayout/__pycache__/refreshlayout.cpython-311.pyc,, +kivymd/uix/refreshlayout/refreshlayout.kv,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/uix/refreshlayout/refreshlayout.py,sha256=lHL1nGOpHWiPqjD7r0dkSabhR6d_Qzis7xtuhpr8RjA,9638 +kivymd/uix/relativelayout.py,sha256=9ewM64QYa1PI_-yBWo5d6mY5PfWudJ5gYu94q9OYEm8,1434 +kivymd/uix/responsivelayout.py,sha256=N1GMNejHlNssk8ZpC9kMuZELuWywUs9Dms_AzHcpU1Q,5409 +kivymd/uix/screen.py,sha256=MgpjK_06QR66Zr4qdxfyiW3ACcaRHclBu-vGsep9Xuo,2625 +kivymd/uix/screenmanager.py,sha256=gSccPZXnmadWd6ueyl9jXXZK4vpUNgEaw0iHVBd262s,5549 +kivymd/uix/scrollview.py,sha256=jeE7XEi8AIigV_BAL-uUOzACu1hEwrTg0FrpabexNok,10744 +kivymd/uix/segmentedbutton/__init__.py,sha256=4xtmjrtfPcihaUtek7R5GXm6ltBYdyY6vz7UokAM1hY,147 +kivymd/uix/segmentedbutton/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/segmentedbutton/__pycache__/segmentedbutton.cpython-311.pyc,, +kivymd/uix/segmentedbutton/segmentedbutton.kv,sha256=JjfYB1naUJjHn8_quYhjnA8rgHH552eeoCLJb6JegRs,3468 +kivymd/uix/segmentedbutton/segmentedbutton.py,sha256=WaZ5DBY-7bmKdoclIl6W7q_ZN7ZgmKnPcJ75TbKiwng,22680 +kivymd/uix/selectioncontrol/__init__.py,sha256=n1yw1X7ccriTWj1GPN-V9LvFXgxuFNfEy6uRHPyhQGA,71 +kivymd/uix/selectioncontrol/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/selectioncontrol/__pycache__/selectioncontrol.cpython-311.pyc,, +kivymd/uix/selectioncontrol/selectioncontrol.kv,sha256=RylxUp5CUsYur5Md_kzX76tcy93rwbfcrOr_eMy9HuQ,5311 +kivymd/uix/selectioncontrol/selectioncontrol.py,sha256=mIgPK-LLcm4We5LfJ8vv2Ue6uuLQ-biiy0EkN5ZXJQQ,24706 +kivymd/uix/slider/__init__.py,sha256=f2N0xMmmO7e9aNdxn0vDqKRgpMIV8EScrsRl71OG1yU,78 +kivymd/uix/slider/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/slider/__pycache__/slider.cpython-311.pyc,, +kivymd/uix/slider/slider.kv,sha256=ydvIp5T2Htrh7Q2YMb2joStz8FVKENTnREmh6FcdVuk,7066 +kivymd/uix/slider/slider.py,sha256=DuuUi_jEpU8c5cyNmjZ5ZeKV4wU-sqNuyicWDOW8f28,17486 +kivymd/uix/sliverappbar/__init__.py,sha256=axuqy95RR0oDLXpBtH3EauoTZN56p6EAp3JFBC-MoYI,103 +kivymd/uix/sliverappbar/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/sliverappbar/__pycache__/sliverappbar.cpython-311.pyc,, +kivymd/uix/sliverappbar/sliverappbar.kv,sha256=jcGxg6SQqadnGHJVJ6S1U6MmwDwALuJ1dGV6Ra651YU,1370 +kivymd/uix/sliverappbar/sliverappbar.py,sha256=Usg3jZdwnaUwO-f2YycHVl9qJIkB29QLtURi0W2_OuA,11439 +kivymd/uix/snackbar/__init__.py,sha256=wP0ppgJbwiGlR3HEMdTo5Umbkq5xeCMkmmJI8ohv8lU,223 +kivymd/uix/snackbar/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/snackbar/__pycache__/snackbar.cpython-311.pyc,, +kivymd/uix/snackbar/snackbar.kv,sha256=JSszxvKOLOGvX3KR5DRekgPVRx8yqEq9BXwgRhbeqno,1836 +kivymd/uix/snackbar/snackbar.py,sha256=Li_UxO9IkrAf29Rkq1vFyoIr9CzVRm-HsFb46Z1ciTg,11746 +kivymd/uix/stacklayout.py,sha256=UDmj4W66Js16Y_RaHRA3WzXz1lBVwvhhtZkIIhQYfco,2067 +kivymd/uix/swiper/__init__.py,sha256=yjVyswA0HfoLRx9UW7k_GR497shvH5EthBbQk8CoU_4,43 +kivymd/uix/swiper/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/swiper/__pycache__/swiper.cpython-311.pyc,, +kivymd/uix/swiper/swiper.kv,sha256=iTaioAm-1WWmrGV4mqTizz3f4Qobv8WJZT-cwhEqyD0,291 +kivymd/uix/swiper/swiper.py,sha256=lG0_lK1TIfIIz5jkrSnQS67ecA9_Ty6DbwcTXN9olck,12618 +kivymd/uix/tab/__init__.py,sha256=Cr-a9CGP8XGLa7QkvU08OpIS1mXu2-o_8V2CONFH1fE,192 +kivymd/uix/tab/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/tab/__pycache__/tab.cpython-311.pyc,, +kivymd/uix/tab/tab.kv,sha256=ZBRG7PYPNPuI8pwfw7RNHI5wYgDP_oNPnZLzR4B_pMc,2255 +kivymd/uix/tab/tab.py,sha256=GTbl_ONS94t4-Lyb3tg5UXG6plx_t3QjDDZCxZtYyRQ,41727 +kivymd/uix/textfield/__init__.py,sha256=q0cpSrgMsws4Csqjz1xv-OCiiFkSstO9P1Vxi6H3sTo,195 +kivymd/uix/textfield/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/textfield/__pycache__/textfield.cpython-311.pyc,, +kivymd/uix/textfield/textfield.kv,sha256=Yu3KxUoBhim0ZI-7if-dY4HI0ZqhPA7mUHyLW7M4obo,13507 +kivymd/uix/textfield/textfield.py,sha256=G0freQCtBynqyvvfYrkqFg3tqfFyAOHla119eFworC0,60112 +kivymd/uix/tooltip/__init__.py,sha256=QPH-5XUDaiDQm6TO5gKyE7lUveO7F4Y4ZiWOfZkxD08,182 +kivymd/uix/tooltip/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/tooltip/__pycache__/tooltip.cpython-311.pyc,, +kivymd/uix/tooltip/tooltip.kv,sha256=gdM-7qQFuTcS-OXzsd6MgFZEalzgx_4wq5azAy1MxoM,2012 +kivymd/uix/tooltip/tooltip.py,sha256=I7UbwBjgaXQQJAsbYsSRZA3kskhZaOilUxav4akYfAM,14636 +kivymd/uix/transition/__init__.py,sha256=Akw-XkRM_JWV17J_SkneutkxlsKZZKqAEkCA4Rd8XYQ,141 +kivymd/uix/transition/__pycache__/__init__.cpython-311.pyc,, +kivymd/uix/transition/__pycache__/transition.cpython-311.pyc,, +kivymd/uix/transition/transition.py,sha256=6uWH24w6ZUK4abdQrc1ZuQqbOem9j_coS0zH16KvR-Q,17974 +kivymd/uix/widget.py,sha256=tR6SyGcoofexLHh_P9YUI7qcYrbHEzOkPwWQhpMoRJ4,1457 +kivymd/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +kivymd/utils/__pycache__/__init__.cpython-311.pyc,, +kivymd/utils/__pycache__/fpsmonitor.cpython-311.pyc,, +kivymd/utils/__pycache__/set_bars_colors.cpython-311.pyc,, +kivymd/utils/fpsmonitor.py,sha256=F1g2HqSr1QH2_SIoQReesMSMmyRj5YJxolBGlK1Tgs8,1514 +kivymd/utils/set_bars_colors.py,sha256=uhCQdrRhRW-P--5D5MJR6rcauOA8wmiFoapJJczkf14,4050 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/REQUESTED b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/REQUESTED similarity index 100% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/REQUESTED rename to kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/REQUESTED diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/WHEEL b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/WHEEL similarity index 65% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/WHEEL rename to kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/WHEEL index 0fde4dd..3d32758 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/WHEEL +++ b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/WHEEL @@ -1,5 +1,5 @@ Wheel-Version: 1.0 -Generator: setuptools (74.1.2) +Generator: setuptools (74.1.3) Root-Is-Purelib: true Tag: py3-none-any diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/direct_url.json b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/direct_url.json new file mode 100644 index 0000000..c614191 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/direct_url.json @@ -0,0 +1 @@ +{"archive_info": {}, "url": "https://github.com/kivymd/KivyMD/archive/master.zip"} \ No newline at end of file diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/entry_points.txt b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/entry_points.txt similarity index 100% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/entry_points.txt rename to kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/entry_points.txt diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/top_level.txt b/kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/top_level.txt similarity index 100% rename from kivy_venv/lib/python3.11/site-packages/kivymd-1.2.0.dist-info/top_level.txt rename to kivy_venv/lib/python3.11/site-packages/kivymd-2.0.1.dev0.dist-info/top_level.txt diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/__init__.py index 58b78df..40f670c 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/__init__.py @@ -26,12 +26,10 @@ import os import kivy from kivy.logger import Logger -__version__ = "1.2.0" -"""KivyMD version.""" +from kivymd._version import __version__, release -release = False if "READTHEDOCS" not in os.environ: - kivy.require("2.2.0") + kivy.require("2.3.0") try: from kivymd._version import __date__, __hash__, __short_hash__ @@ -59,13 +57,8 @@ _log_message = ( + f' (installed at "{__file__}")' ) Logger.info(_log_message) -Logger.warning( - "KivyMD: " - "Version 1.2.0 is deprecated and is no longer supported. " - "Use KivyMD version 2.0.0 from the master branch " - "(pip install https://github.com/kivymd/KivyMD/archive/master.zip)" -) import kivymd.factory_registers # NOQA import kivymd.font_definitions # NOQA +import kivymd.animation # NOQA from kivymd.tools.packaging.pyinstaller import hooks_path # NOQA diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/__init__.cpython-311.pyc index bbf0286..9d416f8 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/_version.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/_version.cpython-311.pyc index 36daae7..0bfc5a5 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/_version.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/_version.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/animation.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/animation.cpython-311.pyc new file mode 100644 index 0000000..e46ab29 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/animation.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/app.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/app.cpython-311.pyc index 3a9dfff..3fa8738 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/app.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/app.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/color_definitions.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/color_definitions.cpython-311.pyc deleted file mode 100644 index 9f472ad..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/color_definitions.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/dynamic_color.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/dynamic_color.cpython-311.pyc new file mode 100644 index 0000000..9e01241 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/dynamic_color.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/factory_registers.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/factory_registers.cpython-311.pyc index d622eb4..2b39ebc 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/factory_registers.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/factory_registers.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/font_definitions.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/font_definitions.cpython-311.pyc index 4e8f142..fdf5560 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/font_definitions.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/font_definitions.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/icon_definitions.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/icon_definitions.cpython-311.pyc index d3fa221..b3f6ece 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/icon_definitions.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/icon_definitions.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/material_resources.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/material_resources.cpython-311.pyc index 58d8ecd..d5954b3 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/material_resources.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/material_resources.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming.cpython-311.pyc index 289067c..ec4c9da 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming_dynamic_text.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming_dynamic_text.cpython-311.pyc deleted file mode 100644 index 451e86a..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/__pycache__/theming_dynamic_text.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/_version.py b/kivy_venv/lib/python3.11/site-packages/kivymd/_version.py index 5ab8670..c075297 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/_version.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/_version.py @@ -1,5 +1,5 @@ -# THIS FILE IS GENERATED FROM KIVYMD SETUP.PY -__version__ = '1.2.0' -__hash__ = 'Unknown' -__short_hash__ = 'Unknown' -__date__ = '2024-09-15' +release = False +__version__ = "2.0.1.dev0" +__hash__ = "Unknown" +__short_hash__ = "Unknown" +__date__ = "2024-09-15" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/animation.py b/kivy_venv/lib/python3.11/site-packages/kivymd/animation.py new file mode 100644 index 0000000..4987b57 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/animation.py @@ -0,0 +1,224 @@ +""" +Animation +========= + +.. versionadded:: 2.0.0 + +Adds new transitions to the :class:`~kivy.animation.AnimationTransition` class: +- "easing_standard" +- "easing_decelerated" +- "easing_accelerated" +- "easing_linear" + + +.. code-block:: python + + + from kivy.lang import Builder + from kivy.animation import Animation + from kivy.uix.boxlayout import BoxLayout + from kivy.clock import Clock + from kivy.metrics import dp + from kivy.properties import ListProperty + + from kivymd.app import MDApp + + + class AnimBox(BoxLayout): + obj_pos = ListProperty([0, 0]) + + + UI = ''' + : + transition:"in_out_bounce" + size_hint_y:None + height:dp(100) + obj_pos:[dp(40), self.pos[-1] + dp(40)] + canvas: + Color: + rgba:app.theme_cls.primaryContainerColor + Rectangle: + size:[self.size[0], dp(5)] + pos:self.pos[0], self.pos[-1] + dp(50) + Color: + rgba:app.theme_cls.primaryColor + Rectangle: + size:[dp(30)] * 2 + pos:root.obj_pos + MDLabel: + adaptive_height:True + text:root.transition + padding:[dp(10), 0] + halign:"center" + + MDGridLayout: + orientation:"lr-tb" + cols:1 + md_bg_color:app.theme_cls.backgroundColor + spacing:dp(10) + ''' + + + class MotionApp(MDApp): + + def build(self): + return Builder.load_string(UI) + + def on_start(self): + for transition in [ + "easing_linear", + "easing_accelerated", + "easing_decelerated", + "easing_standard", + "in_out_cubic" + ]: # Add more here for comparison + print(transition) + widget = AnimBox() + widget.transition = transition + self.root.add_widget(widget) + Clock.schedule_once(self.run_animation, 1) + + _inverse = True + def run_animation(self, dt): + x = (self.root.children[0].width - dp(30)) if self._inverse else 0 + for widget in self.root.children: + Animation( + obj_pos=[x, widget.obj_pos[-1]], t=widget.transition, d=3 + ).start(widget) + self._inverse = not self._inverse + Clock.schedule_once(self.run_animation, 3.1) + + MotionApp().run() + +.. image:: https://github.com/kivymd/KivyMD/assets/68729523/21c847b0-284a-4796-b704-e4a2531fbb1b + :align: center +""" + +import math +import sys +import kivy.animation + +float_epsilon = 8.3446500e-7 + +if sys.version_info < (3, 11): + cbrt = lambda number: (abs(number) ** (1/3)) * (-1 if number < 0 else 1) +else: + cbrt = math.cbrt + +class CubicBezier: + """Ported from Android source code""" + + p0 = 0 + p1 = 0 + p2 = 0 + p3 = 0 + + def __init__(self, *args): + self.p0, self.p1, self.p2, self.p3 = args + + def evaluate_cubic(self, p1, p2, t): + a = 1.0 / 3.0 + (p1 - p2) + b = p2 - 2.0 * p1 + c = p1 + return 3.0 * ((a * t + b) * t + c) * t + + def clamp_range(self, r): + if r < 0.0: + if -float_epsilon <= r < 0.0: + return 0.0 + else: + return math.nan + elif r > 1.0: + if 1.0 <= r <= 1.0 + float_epsilon: + return 1.0 + else: + return math.nan + else: + return r + + def close_to(self, x, y): + return abs(x - y) < float_epsilon + + def find_first_cubic_root(self, p0, p1, p2, p3): + a = 3.0 * (p0 - 2.0 * p1 + p2) + b = 3.0 * (p1 - p0) + c = p0 + d = -p0 + 3.0 * (p1 - p2) + p3 + if self.close_to(d, 0.0): + if self.close_to(a, 0.0): + if self.close_to(b, 0.0): + return math.nan + return self.clamp_range(-c / b) + else: + q = math.sqrt(b * b - 4.0 * a * c) + a2 = 2.0 * a + root = self.clamp_range((q - b) / a2) + if not math.isnan(root): + return root + return self.clamp_range((-b - q) / a2) + a /= d + b /= d + c /= d + o3 = (3.0 * b - a * a) / 9.0 + q2 = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0 + discriminant = q2 * q2 + o3 * o3 * o3 + a3 = a / 3.0 + + if discriminant < 0.0: + mp33 = -(o3 * o3 * o3) + r = math.sqrt(mp33) + t = -q2 / r + cos_phi = max(-1.0, min(t, 1.0)) + phi = math.acos(cos_phi) + t1 = 2.0 * cbrt(r) + root = self.clamp_range(t1 * math.cos(phi / 3.0) - a3) + if not math.isnan(root): + return root + root = self.clamp_range( + t1 * math.cos((phi + 2.0 * math.pi) / 3.0) - a3 + ) + if not math.isnan(root): + return root + return self.clamp_range( + t1 * math.cos((phi + 4.0 * math.pi) / 3.0) - a3 + ) + + elif self.close_to(discriminant, 0.0): + u1 = -cbrt(q2) + root = self.clamp_range(2.0 * u1 - a3) + if not math.isnan(root): + return root + return self.clamp_range(-u1 - a3) + + sd = math.sqrt(discriminant) + u1 = cbrt(-q2 + sd) + v1 = cbrt(q2 + sd) + return self.clamp_range(u1 - v1 - a3) + + def t(self, value: float): + return self.evaluate_cubic( + self.p1, + self.p3, + self.find_first_cubic_root( + -value, + self.p0 - value, + self.p2 - value, + 1.0 - value, + ), + ) + + +class MDAnimationTransition(kivy.animation.AnimationTransition): + """KivyMD's equivalent of kivy's `AnimationTransition`""" + + easing_standard = CubicBezier(0.4, 0.0, 0.2, 1.0).t + easing_decelerated = CubicBezier(0.0, 0.0, 0.2, 1.0).t + easing_accelerated = CubicBezier(0.4, 0.0, 1.0, 1.0).t + easing_linear = CubicBezier(0.0, 0.0, 1.0, 1.0).t + +# TODO: add `easing_emphasized` here +# it's defination is +# path(M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1) + +# Monkey patch kivy's animation module +kivy.animation.AnimationTransition = MDAnimationTransition diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/app.py b/kivy_venv/lib/python3.11/site-packages/kivymd/app.py index bdad688..40a31a1 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/app.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/app.py @@ -3,14 +3,15 @@ Themes/Material App =================== This module contains :class:`MDApp` class that is inherited from -:class:`~kivy.app.App`. :class:`MDApp` has some properties needed for ``KivyMD`` -library (like :attr:`~MDApp.theme_cls`). You can turn on the monitor displaying -the current ``FPS`` value in your application: +:class:`~kivy.app.App`. :class:`MDApp` has some properties needed for `KivyMD` +library (like :attr:`~MDApp.theme_cls`). You can turn on the monitor +displaying the current `FP` value in your application: .. code-block:: python KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor MDLabel: text: "Hello, World!" @@ -32,10 +33,23 @@ the current ``FPS`` value in your application: MainApp().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fps-monitor.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fps-monitor-dark.png :width: 350 px :align: center +.. note:: + + Note that if you override the built-in on_start method, you will + definitely need to call the super method: + + .. code-block:: python + + class MainApp(MDApp): + def build(self): + [...] + + def on_start(self): + [...] """ __all__ = ("MDApp",) @@ -55,7 +69,12 @@ class FpsMonitoring: """Implements a monitor to display the current FPS in the toolbar.""" def fps_monitor_start(self, anchor: str = "top") -> None: - """Adds a monitor to the main application window.""" + """ + Adds a monitor to the main application window. + + :type anchor: str; + :param anchor: anchor FPS panel ('top' or 'bottom'); + """ def add_monitor(*args): from kivy.core.window import Window @@ -114,6 +133,14 @@ class MDApp(App, FpsMonitoring): super().__init__(**kwargs) self.theme_cls = ThemeManager() + def _run_prepare(self): + self.theme_cls.bind( + theme_style=self.theme_cls.update_theme_colors, + primary_palette=self.theme_cls.set_colors + ) + self.theme_cls.set_colors() + super()._run_prepare() + def load_all_kv_files(self, path_to_directory: str) -> None: """ Recursively loads KV files from the selected directory. @@ -128,8 +155,8 @@ class MDApp(App, FpsMonitoring): if "kivymd" in path_to_directory: Logger.critical( "KivyMD: " - "Do not use the word 'kivymd' in the name of the directory " - "from where you download KV files" + "Do not use the word 'kivymd' in the name of the " + "directory from where you download KV files" ) if ( "venv" in path_to_dir diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/color_definitions.py b/kivy_venv/lib/python3.11/site-packages/kivymd/color_definitions.py deleted file mode 100644 index e4a7de4..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/color_definitions.py +++ /dev/null @@ -1,954 +0,0 @@ -""" -Themes/Color Definitions -======================== - -.. seealso:: - - `Material Design spec, The color system `_ - - `Material Design spec, The color tool `_ - -Material colors palette to use in :class:`kivymd.theming.ThemeManager`. -:data:`~colors` is a dict-in-dict where the first key is a value from -:data:`~palette` and the second key is a value from :data:`~hue`. Color is a hex -value, a string of 6 characters (0-9, A-F) written in uppercase. - -For example, ``colors["Red"]["900"]`` is ``"B71C1C"``. -""" - -colors = { - "Red": { - "50": "FFEBEE", - "100": "FFCDD2", - "200": "EF9A9A", - "300": "E57373", - "400": "EF5350", - "500": "F44336", - "600": "E53935", - "700": "D32F2F", - "800": "C62828", - "900": "B71C1C", - "A100": "FF8A80", - "A200": "FF5252", - "A400": "FF1744", - "A700": "D50000", - }, - "Pink": { - "50": "FCE4EC", - "100": "F8BBD0", - "200": "F48FB1", - "300": "F06292", - "400": "EC407A", - "500": "E91E63", - "600": "D81B60", - "700": "C2185B", - "800": "AD1457", - "900": "880E4F", - "A100": "FF80AB", - "A200": "FF4081", - "A400": "F50057", - "A700": "C51162", - }, - "Purple": { - "50": "F3E5F5", - "100": "E1BEE7", - "200": "CE93D8", - "300": "BA68C8", - "400": "AB47BC", - "500": "9C27B0", - "600": "8E24AA", - "700": "7B1FA2", - "800": "6A1B9A", - "900": "4A148C", - "A100": "EA80FC", - "A200": "E040FB", - "A400": "D500F9", - "A700": "AA00FF", - }, - "DeepPurple": { - "50": "EDE7F6", - "100": "D1C4E9", - "200": "B39DDB", - "300": "9575CD", - "400": "7E57C2", - "500": "673AB7", - "600": "5E35B1", - "700": "512DA8", - "800": "4527A0", - "900": "311B92", - "A100": "B388FF", - "A200": "7C4DFF", - "A400": "651FFF", - "A700": "6200EA", - }, - "Indigo": { - "50": "E8EAF6", - "100": "C5CAE9", - "200": "9FA8DA", - "300": "7986CB", - "400": "5C6BC0", - "500": "3F51B5", - "600": "3949AB", - "700": "303F9F", - "800": "283593", - "900": "1A237E", - "A100": "8C9EFF", - "A200": "536DFE", - "A400": "3D5AFE", - "A700": "304FFE", - }, - "Blue": { - "50": "E3F2FD", - "100": "BBDEFB", - "200": "90CAF9", - "300": "64B5F6", - "400": "42A5F5", - "500": "2196F3", - "600": "1E88E5", - "700": "1976D2", - "800": "1565C0", - "900": "0D47A1", - "A100": "82B1FF", - "A200": "448AFF", - "A400": "2979FF", - "A700": "2962FF", - }, - "LightBlue": { - "50": "E1F5FE", - "100": "B3E5FC", - "200": "81D4FA", - "300": "4FC3F7", - "400": "29B6F6", - "500": "03A9F4", - "600": "039BE5", - "700": "0288D1", - "800": "0277BD", - "900": "01579B", - "A100": "80D8FF", - "A200": "40C4FF", - "A400": "00B0FF", - "A700": "0091EA", - }, - "Cyan": { - "50": "E0F7FA", - "100": "B2EBF2", - "200": "80DEEA", - "300": "4DD0E1", - "400": "26C6DA", - "500": "00BCD4", - "600": "00ACC1", - "700": "0097A7", - "800": "00838F", - "900": "006064", - "A100": "84FFFF", - "A200": "18FFFF", - "A400": "00E5FF", - "A700": "00B8D4", - }, - "Teal": { - "50": "E0F2F1", - "100": "B2DFDB", - "200": "80CBC4", - "300": "4DB6AC", - "400": "26A69A", - "500": "009688", - "600": "00897B", - "700": "00796B", - "800": "00695C", - "900": "004D40", - "A100": "A7FFEB", - "A200": "64FFDA", - "A400": "1DE9B6", - "A700": "00BFA5", - }, - "Green": { - "50": "E8F5E9", - "100": "C8E6C9", - "200": "A5D6A7", - "300": "81C784", - "400": "66BB6A", - "500": "4CAF50", - "600": "43A047", - "700": "388E3C", - "800": "2E7D32", - "900": "1B5E20", - "A100": "B9F6CA", - "A200": "69F0AE", - "A400": "00E676", - "A700": "00C853", - }, - "LightGreen": { - "50": "F1F8E9", - "100": "DCEDC8", - "200": "C5E1A5", - "300": "AED581", - "400": "9CCC65", - "500": "8BC34A", - "600": "7CB342", - "700": "689F38", - "800": "558B2F", - "900": "33691E", - "A100": "CCFF90", - "A200": "B2FF59", - "A400": "76FF03", - "A700": "64DD17", - }, - "Lime": { - "50": "F9FBE7", - "100": "F0F4C3", - "200": "E6EE9C", - "300": "DCE775", - "400": "D4E157", - "500": "CDDC39", - "600": "C0CA33", - "700": "AFB42B", - "800": "9E9D24", - "900": "827717", - "A100": "F4FF81", - "A200": "EEFF41", - "A400": "C6FF00", - "A700": "AEEA00", - }, - "Yellow": { - "50": "FFFDE7", - "100": "FFF9C4", - "200": "FFF59D", - "300": "FFF176", - "400": "FFEE58", - "500": "FFEB3B", - "600": "FDD835", - "700": "FBC02D", - "800": "F9A825", - "900": "F57F17", - "A100": "FFFF8D", - "A200": "FFFF00", - "A400": "FFEA00", - "A700": "FFD600", - }, - "Amber": { - "50": "FFF8E1", - "100": "FFECB3", - "200": "FFE082", - "300": "FFD54F", - "400": "FFCA28", - "500": "FFC107", - "600": "FFB300", - "700": "FFA000", - "800": "FF8F00", - "900": "FF6F00", - "A100": "FFE57F", - "A200": "FFD740", - "A400": "FFC400", - "A700": "FFAB00", - }, - "Orange": { - "50": "FFF3E0", - "100": "FFE0B2", - "200": "FFCC80", - "300": "FFB74D", - "400": "FFA726", - "500": "FF9800", - "600": "FB8C00", - "700": "F57C00", - "800": "EF6C00", - "900": "E65100", - "A100": "FFD180", - "A200": "FFAB40", - "A400": "FF9100", - "A700": "FF6D00", - }, - "DeepOrange": { - "50": "FBE9E7", - "100": "FFCCBC", - "200": "FFAB91", - "300": "FF8A65", - "400": "FF7043", - "500": "FF5722", - "600": "F4511E", - "700": "E64A19", - "800": "D84315", - "900": "BF360C", - "A100": "FF9E80", - "A200": "FF6E40", - "A400": "FF3D00", - "A700": "DD2C00", - }, - "Brown": { - "50": "EFEBE9", - "100": "D7CCC8", - "200": "BCAAA4", - "300": "A1887F", - "400": "8D6E63", - "500": "795548", - "600": "6D4C41", - "700": "5D4037", - "800": "4E342E", - "900": "3E2723", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Gray": { - "50": "FAFAFA", - "100": "F5F5F5", - "200": "EEEEEE", - "300": "E0E0E0", - "400": "BDBDBD", - "500": "9E9E9E", - "600": "757575", - "700": "616161", - "800": "424242", - "900": "212121", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "BlueGray": { - "50": "ECEFF1", - "100": "CFD8DC", - "200": "B0BEC5", - "300": "90A4AE", - "400": "78909C", - "500": "607D8B", - "600": "546E7A", - "700": "455A64", - "800": "37474F", - "900": "263238", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Light": { - "StatusBar": "E0E0E0", - "AppBar": "F5F5F5", - "Background": "FAFAFA", - "CardsDialogs": "FFFFFF", - "FlatButtonDown": "cccccc", - }, - "Dark": { - "StatusBar": "000000", - "AppBar": "1f1f1f", - "Background": "121212", - "CardsDialogs": "212121", - "FlatButtonDown": "999999", - }, -} -""" -Color palette. Taken from `2014 Material Design color palettes -`_. - -To demonstrate the shades of the palette, you can run the following code: - -.. code-block:: python - - from kivy.lang import Builder - from kivy.properties import ListProperty, StringProperty - - from kivymd.color_definitions import colors - from kivymd.uix.tab import MDTabsBase - from kivymd.uix.boxlayout import MDBoxLayout - - demo = ''' - - orientation: 'vertical' - - MDTopAppBar: - title: app.title - - MDTabs: - id: android_tabs - on_tab_switch: app.on_tab_switch(*args) - size_hint_y: None - height: "48dp" - tab_indicator_anim: False - - RecycleView: - id: rv - key_viewclass: "viewclass" - key_size: "height" - - RecycleBoxLayout: - default_size: None, dp(48) - default_size_hint: 1, None - size_hint_y: None - height: self.minimum_height - orientation: "vertical" - - - - size_hint_y: None - height: "42dp" - - MDLabel: - text: root.text - halign: "center" - - - - ''' - - from kivy.factory import Factory - - from kivymd.app import MDApp - - - class Tab(MDBoxLayout, MDTabsBase): - pass - - - class ItemColor(MDBoxLayout): - text = StringProperty() - color = ListProperty() - - - class Palette(MDApp): - title = "Colors definitions" - - def build(self): - Builder.load_string(demo) - self.screen = Factory.Root() - - for name_tab in colors.keys(): - tab = Tab(title=name_tab) - self.screen.ids.android_tabs.add_widget(tab) - return self.screen - - def on_tab_switch( - self, instance_tabs, instance_tab, instance_tabs_label, tab_text - ): - self.screen.ids.rv.data = [] - if not tab_text: - tab_text = 'Red' - for value_color in colors[tab_text]: - self.screen.ids.rv.data.append( - { - "viewclass": "ItemColor", - "md_bg_color": colors[tab_text][value_color], - "title": value_color, - } - ) - - def on_start(self): - self.on_tab_switch( - None, - None, - None, - self.screen.ids.android_tabs.ids.layout.children[-1].text, - ) - - - Palette().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/palette.gif - :align: center -""" - -palette = [ - "Red", - "Pink", - "Purple", - "DeepPurple", - "Indigo", - "Blue", - "LightBlue", - "Cyan", - "Teal", - "Green", - "LightGreen", - "Lime", - "Yellow", - "Amber", - "Orange", - "DeepOrange", - "Brown", - "Gray", - "BlueGray", -] -"""Valid values for color palette selecting.""" - -hue = [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "700", - "800", - "900", - "A100", - "A200", - "A400", - "A700", -] -"""Valid values for color hue selecting.""" - - -light_colors = { - "Red": ["50", "100", "200", "300", "A100"], - "Pink": ["50", "100", "200", "A100"], - "Purple": ["50", "100", "200", "A100"], - "DeepPurple": ["50", "100", "200", "A100"], - "Indigo": ["50", "100", "200", "A100"], - "Blue": ["50", "100", "200", "300", "400", "A100"], - "LightBlue": [ - "50", - "100", - "200", - "300", - "400", - "500", - "A100", - "A200", - "A400", - ], - "Cyan": [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "A100", - "A200", - "A400", - "A700", - ], - "Teal": ["50", "100", "200", "300", "400", "A100", "A200", "A400", "A700"], - "Green": [ - "50", - "100", - "200", - "300", - "400", - "500", - "A100", - "A200", - "A400", - "A700", - ], - "LightGreen": [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "A100", - "A200", - "A400", - "A700", - ], - "Lime": [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "700", - "800", - "A100", - "A200", - "A400", - "A700", - ], - "Yellow": [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "700", - "800", - "900", - "A100", - "A200", - "A400", - "A700", - ], - "Amber": [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "700", - "800", - "900", - "A100", - "A200", - "A400", - "A700", - ], - "Orange": [ - "50", - "100", - "200", - "300", - "400", - "500", - "600", - "700", - "A100", - "A200", - "A400", - "A700", - ], - "DeepOrange": ["50", "100", "200", "300", "400", "A100", "A200"], - "Brown": ["50", "100", "200"], - "Gray": ["50", "100", "200", "300", "400", "500"], - "BlueGray": ["50", "100", "200", "300"], - "Dark": [], - "Light": ["White", "MainBackground", "DialogBackground"], -} -"""Which colors are light. Other are dark.""" - -text_colors = { - "Red": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "Pink": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "FFFFFF", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "Purple": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "FFFFFF", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "DeepPurple": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "FFFFFF", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "Indigo": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "FFFFFF", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "Blue": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "LightBlue": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "FFFFFF", - }, - "Cyan": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "000000", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Teal": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Green": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "LightGreen": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "000000", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Lime": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "000000", - "700": "000000", - "800": "000000", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Yellow": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "000000", - "700": "000000", - "800": "000000", - "900": "000000", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Amber": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "000000", - "700": "000000", - "800": "000000", - "900": "000000", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "Orange": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "000000", - "700": "000000", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "000000", - "A700": "000000", - }, - "DeepOrange": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "000000", - "A200": "000000", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "Brown": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "FFFFFF", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "FFFFFF", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "Gray": { - "50": "FFFFFF", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "000000", - "500": "000000", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "FFFFFF", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, - "BlueGray": { - "50": "000000", - "100": "000000", - "200": "000000", - "300": "000000", - "400": "FFFFFF", - "500": "FFFFFF", - "600": "FFFFFF", - "700": "FFFFFF", - "800": "FFFFFF", - "900": "FFFFFF", - "A100": "FFFFFF", - "A200": "FFFFFF", - "A400": "FFFFFF", - "A700": "FFFFFF", - }, -} -""" -Text colors generated from :data:`~light_colors`. "000000" for light and -"FFFFFF" for dark. - -How to generate text_colors dict - -.. code-block:: python - - text_colors = {} - for p in palette: - text_colors[p] = {} - for h in hue: - if h in light_colors[p]: - text_colors[p][h] = "000000" - else: - text_colors[p][h] = "FFFFFF" -""" - -theme_colors = [ - "Primary", - "Secondary", - "Background", - "Surface", - "Error", - "On_Primary", - "On_Secondary", - "On_Background", - "On_Surface", - "On_Error", -] -"""Valid theme colors.""" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/dynamic_color.py b/kivy_venv/lib/python3.11/site-packages/kivymd/dynamic_color.py new file mode 100644 index 0000000..bbe8b26 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/dynamic_color.py @@ -0,0 +1,632 @@ +""" +Components/Dynamic color +======================== + +.. seealso:: + + `Material Design spec, Dynamic color + `_ + +.. rubric:: Dynamic color can create accessible UI color schemes based on + content or user settings + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color.png + :align: center + +Dynamic color experiences are built with M3 color schemes. Beginning with +Android 12, users can generate individualized schemes through wallpaper +selection and other customization settings. With M3 as a foundation, +user-generated colors can coexist with app colors, putting a range of +customizable visual experiences in the hands of users. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color-preview.png + :align: center + +1. Baseline scheme +2. Colors extracted from a wallpaper +3. Colors extracted from content + +Example of dynamic color from the list of standard color schemes +---------------------------------------------------------------- + +.. code-block:: python + + from kivy.clock import Clock + from kivy.lang import Builder + from kivy.properties import StringProperty, ColorProperty + from kivy.uix.boxlayout import BoxLayout + from kivy.utils import hex_colormap + + from kivymd.uix.menu import MDDropdownMenu + from kivymd.app import MDApp + + + KV = ''' + + orientation: "vertical" + + MDLabel: + text: root.text + color: "grey" + adaptive_height: True + + MDCard: + theme_bg_color: "Custom" + md_bg_color: root.bg_color + + + MDScreen: + md_bg_color: app.theme_cls.backgroundColor + + MDIconButton: + on_release: app.open_menu(self) + pos_hint: {"top": .98} + x: "12dp" + icon: "menu" + + MDRecycleView: + id: card_list + viewclass: "ColorCard" + bar_width: 0 + size_hint_y: None + height: root.height - dp(68) + + RecycleGridLayout: + cols: 3 + spacing: "16dp" + padding: "16dp" + default_size: None, dp(56) + default_size_hint: 1, None + size_hint_y: None + height: self.minimum_height + ''' + + + class ColorCard(BoxLayout): + text = StringProperty() + bg_color = ColorProperty() + + + class Example(MDApp): + menu: MDDropdownMenu = None + + def build(self): + self.theme_cls.dynamic_color = True + return Builder.load_string(KV) + + def get_instance_from_menu(self, name_item): + index = 0 + rv = self.menu.ids.md_menu + opts = rv.layout_manager.view_opts + datas = rv.data[0] + + for data in rv.data: + if data["text"] == name_item: + index = rv.data.index(data) + break + + instance = rv.view_adapter.get_view( + index, datas, opts[index]["viewclass"] + ) + + return instance + + def open_menu(self, menu_button): + menu_items = [] + for item, method in { + "Set palette": lambda: self.set_palette(), + "Switch theme style": lambda: self.theme_switch(), + }.items(): + menu_items.append({"text": item, "on_release": method}) + self.menu = MDDropdownMenu( + caller=menu_button, + items=menu_items, + ) + self.menu.open() + + def set_palette(self): + instance_from_menu = self.get_instance_from_menu("Set palette") + available_palettes = [ + name_color.capitalize() for name_color in hex_colormap.keys() + ] + + menu_items = [] + for name_palette in available_palettes: + menu_items.append( + { + "text": name_palette, + "on_release": lambda x=name_palette: self.switch_palette(x), + } + ) + MDDropdownMenu( + caller=instance_from_menu, + items=menu_items, + ).open() + + def switch_palette(self, selected_palette): + self.theme_cls.primary_palette = selected_palette + Clock.schedule_once(self.generate_cards, 0.5) + + def theme_switch(self) -> None: + self.theme_cls.switch_theme() + Clock.schedule_once(self.generate_cards, 0.5) + + def generate_cards(self, *args): + self.root.ids.card_list.data = [] + for color in self.theme_cls.schemes_name_colors: + value = f"{color}Color" + self.root.ids.card_list.data.append( + { + "bg_color": getattr(self.theme_cls, value), + "text": value, + } + ) + + def on_start(self): + Clock.schedule_once(self.generate_cards) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color.gif + :align: center + +Example of a dynamic color from an image +---------------------------------------- + +.. seealso:: + + :attr:`kivymd.theming.ThemeManager.path_to_wallpaper` + +.. code-block:: python + + import os + + from kivy.clock import Clock + from kivy.core.window import Window + from kivy.core.window.window_sdl2 import WindowSDL + from kivy.lang import Builder + from kivy.properties import StringProperty, ColorProperty + + from kivymd.uix.boxlayout import MDBoxLayout + from kivymd.app import MDApp + + + KV = ''' + + orientation: "vertical" + + MDLabel: + text: root.text + color: "grey" + adaptive_height: True + + MDCard: + theme_bg_color: "Custom" + md_bg_color: root.bg_color + + + MDScreen: + md_bg_color: app.theme_cls.backgroundColor + + MDRecycleView: + id: card_list + viewclass: "ColorCard" + bar_width: 0 + + RecycleGridLayout: + cols: 3 + spacing: "16dp" + padding: "16dp" + default_size: None, dp(56) + default_size_hint: 1, None + size_hint_y: None + height: self.minimum_height + ''' + + + class ColorCard(MDBoxLayout): + text = StringProperty() + bg_color = ColorProperty() + + + class Example(MDApp): + def __init__(self, **kwargs): + super().__init__(**kwargs) + Window.bind(on_dropfile=self.on_drop_file) + + def on_drop_file(self, sdl: WindowSDL, path_to_file: str) -> None: + ext = os.path.splitext(path_to_file)[1] + if isinstance(path_to_file, bytes): + path_to_file = path_to_file.decode() + if isinstance(ext, bytes): + ext = ext.decode() + if ext in [".png", ".jpg"]: + self.theme_cls.path_to_wallpaper = path_to_file + Clock.schedule_once(self.generate_cards, 0.5) + + def build(self): + self.theme_cls.dynamic_color = True + self.theme_cls.theme_style = "Dark" + return Builder.load_string(KV) + + def theme_switch(self) -> None: + self.theme_cls.switch_theme() + Clock.schedule_once(self.generate_cards, 0.5) + + def generate_cards(self, *args): + self.root.ids.card_list.data = [] + for color in self.theme_cls.schemes_name_colors: + value = f"{color}Color" + self.root.ids.card_list.data.append( + { + "bg_color": getattr(self.theme_cls, value), + "text": value, + } + ) + + def on_start(self): + Clock.schedule_once(self.generate_cards) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dynamic-color-path-to_wallpapper.gif + :align: center +""" + +from kivy.properties import ColorProperty + + +class DynamicColor: + """ + Dynamic color class. + + .. versionadded:: 2.0.0 + """ + + # Primary. + primaryColor = ColorProperty() + """ + Primary color. + + :attr:`primaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + primaryContainerColor = ColorProperty() + """ + Primary container color. + + :attr:`primaryContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # On Primary. + onPrimaryColor = ColorProperty() + """ + On primary color. + + :attr:`onPrimaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + onPrimaryContainerColor = ColorProperty() + """ + On primary container color. + + :attr:`onPrimaryContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Secondary. + secondaryColor = ColorProperty() + """ + Secondary color. + + :attr:`secondaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + secondaryContainerColor = ColorProperty() + """ + Secondary container color. + + :attr:`secondaryContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # On Secondary. + onSecondaryColor = ColorProperty() + """ + On secondary color. + + :attr:`onSecondaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + onSecondaryContainerColor = ColorProperty() + """ + On secondary container color. + + :attr:`onSecondaryContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Tertiary. + tertiaryColor = ColorProperty() + """ + Tertiary color. + + :attr:`tertiaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + tertiaryContainerColor = ColorProperty() + """ + Tertiary container color. + + :attr:`tertiaryContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # On Tertiary. + onTertiaryColor = ColorProperty() + """ + On tertiary color. + + :attr:`onTertiaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + onTertiaryContainerColor = ColorProperty() + """ + On tertiary container color. + + :attr:`onTertiaryContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Surface. + surfaceColor = ColorProperty() + """ + Surface color. + + :attr:`surfaceColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceDimColor = ColorProperty() + """ + Surface dim color. + + :attr:`surfaceDimColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceBrightColor = ColorProperty() + """ + Surface bright color. + + :attr:`surfaceBrightColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceContainerLowestColor = ColorProperty() + """ + Surface container lowest color. + + :attr:`surfaceContainerLowestColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceContainerLowColor = ColorProperty() + """ + Surface container low color. + + :attr:`surfaceContainerLowColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceContainerColor = ColorProperty() + """ + Surface container color. + + :attr:`surfaceContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceContainerHighColor = ColorProperty() + """ + Surface container high color. + + :attr:`surfaceContainerHighColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceContainerHighestColor = ColorProperty() + """ + Surface container highest color. + + :attr:`surfaceContainerHighestColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceVariantColor = ColorProperty() + """ + Surface variant color. + + :attr:`surfaceVariantColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + surfaceTintColor = ColorProperty() + """ + Surface tint color. + + :attr:`surfaceTintColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # On Surface. + onSurfaceColor = ColorProperty() + """ + On surface color. + + :attr:`onSurfaceColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + onSurfaceLightColor = ColorProperty() + """ + On surface light color. + + :attr:`onSurfaceLightColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + onSurfaceVariantColor = ColorProperty() + """ + On surface variant color. + + :attr:`onSurfaceVariantColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Inverse. + inverseSurfaceColor = ColorProperty() + """ + Inverse surface color. + + :attr:`inverseSurfaceColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + inverseOnSurfaceColor = ColorProperty() + """ + Inverse on surface color. + + :attr:`inverseOnSurfaceColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + inversePrimaryColor = ColorProperty() + """ + Inverse primary color. + + :attr:`inversePrimaryColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Background. + backgroundColor = ColorProperty() + """ + Background color. + + :attr:`backgroundColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # On Background. + onBackgroundColor = ColorProperty() + """ + On background color. + + :attr:`onBackgroundColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Error. + errorColor = ColorProperty() + """ + Error color. + + :attr:`errorColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + errorContainerColor = ColorProperty() + """ + Error container color. + + :attr:`errorContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # On Error. + onErrorColor = ColorProperty() + """ + On error color. + + :attr:`onErrorColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + onErrorContainerColor = ColorProperty() + """ + On error container color. + + :attr:`onErrorContainerColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Outline. + outlineColor = ColorProperty() + """ + Outline color. + + :attr:`outlineColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + outlineVariantColor = ColorProperty() + """ + Outline variant color. + + :attr:`outlineVariantColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Shadow/scrim. + shadowColor = ColorProperty() + """ + Shadow color. + + :attr:`shadowColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + scrimColor = ColorProperty() + """ + Scrim color. + + :attr:`scrimColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Disabled. + disabledTextColor = ColorProperty() + """ + Disabled text color. + + :attr:`disabledTextColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # Transparent. + transparentColor = ColorProperty([0, 0, 0, 0]) + """ + Transparent color. + + :attr:`transparentColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `[0, 0, 0, 0]`. + """ + + # Ripple. + rippleColor = ColorProperty("#BDBDBD") + """ + Ripple color. + + :attr:`rippleColor` is an :class:`~kivy.properties.ColorProperty` + and defaults to `'#BDBDBD'`. + """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/__pycache__/__init__.cpython-311.pyc index c8885d5..008b0bd 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__init__.py deleted file mode 100644 index d2905b0..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .fadingedge import FadingEdgeEffect diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 06c12bd..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__pycache__/fadingedge.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__pycache__/fadingedge.cpython-311.pyc deleted file mode 100644 index d77e538..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/__pycache__/fadingedge.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/fadingedge.py b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/fadingedge.py deleted file mode 100644 index 106d3c8..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/fadingedge/fadingedge.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -Effects/FadingEdgeEffect -======================== - -.. versionadded:: 1.0.0 - -The `FadingEdgeEffect` class implements a fade effect for `KivyMD` widgets: - -.. code-block:: python - - from kivy.lang import Builder - from kivy.uix.scrollview import ScrollView - - from kivymd.app import MDApp - from kivymd.effects.fadingedge.fadingedge import FadingEdgeEffect - from kivymd.uix.list import OneLineListItem - - KV = ''' - MDScreen: - - FadeScrollView: - fade_height: self.height / 2 - fade_color: root.md_bg_color - - MDList: - id: container - ''' - - - class FadeScrollView(FadingEdgeEffect, ScrollView): - pass - - - class Test(MDApp): - def build(self): - return Builder.load_string(KV) - - def on_start(self): - for i in range(20): - self.root.ids.container.add_widget( - OneLineListItem(text=f"Single-line item {i}") - ) - - - Test().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fading-edge-effect-white.gif - :align: center - -.. note:: Use the same color value for the fade_color parameter as for the - parent widget. -""" - -from typing import Union - -from kivy.clock import Clock -from kivy.graphics.context_instructions import Color -from kivy.graphics.vertex_instructions import Rectangle -from kivy.metrics import dp -from kivy.properties import BooleanProperty, ColorProperty, NumericProperty - -from kivymd.theming import ThemableBehavior - -__all_ = ("FadingEdgeEffect",) - - -class FadingEdgeEffect(ThemableBehavior): - """ - The class implements the fade effect. - - .. versionadded:: 1.0.0 - """ - - fade_color = ColorProperty(None) - """ - Fade color. - - :attr:`fade_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - fade_height = NumericProperty(0) - """ - Fade height. - - :attr:`fade_height` is an :class:`~kivy.properties.ColorProperty` - and defaults to `0`. - """ - - edge_top = BooleanProperty(True) - """ - Display fade edge top. - - :attr:`edge_top` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. - """ - - edge_bottom = BooleanProperty(True) - """ - Display fade edge bottom. - - :attr:`edge_bottom` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. - """ - - _height_segment = 10 - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Clock.schedule_once(self.set_fade) - - # TODO: Perhaps it would be better if we used a Shader for the fade effect. - # But, I think the canvas instructions shouldn't affect performance - def set_fade(self, interval: Union[int, float]) -> None: - """Draws a bottom and top fade border on the canvas.""" - - fade_color = ( - self.theme_cls.primary_color - if not self.fade_color - else self.fade_color - ) - height_segment = ( - self.fade_height if self.fade_height else dp(100) - ) // self._height_segment - alpha = 1.1 - - with self.canvas: - for i in range(self._height_segment): - alpha -= 0.1 - - Color(rgba=(fade_color[:-1] + [round(alpha, 1)])) - rectangle_top = ( - Rectangle( - pos=(self.x, self.height - (i * height_segment)), - size=(self.width, height_segment), - ) - if self.edge_top - else None - ) - rectangle_bottom = ( - Rectangle( - pos=(self.x, i * height_segment), - size=(self.width, height_segment), - ) - if self.edge_bottom - else None - ) - # How I hate lambda functions because of their length :( - # But I don’t want to call the arguments by short, - # incomprehensible names 'a', 'b', 'c'. - self.bind( - pos=lambda instance_fadind_edge_effect, window_size, rectangle_top=rectangle_top, rectangle_bottom=rectangle_bottom, index=i: self.update_canvas( - instance_fadind_edge_effect, - window_size, - rectangle_top, - rectangle_bottom, - index, - ), - size=lambda instance_fadind_edge_effect, window_size, rectangle_top=rectangle_top, rectangle_bottom=rectangle_bottom, index=i: self.update_canvas( - instance_fadind_edge_effect, - window_size, - rectangle_top, - rectangle_bottom, - index, - ), - ) - self.update_canvas( - self, self.size, rectangle_top, rectangle_bottom, i - ) - - def update_canvas( - self, - instance_fadind_edge_effect, - size: list[int, int], - rectangle_top: Rectangle, - rectangle_bottom: Rectangle, - index: int, - ) -> None: - """ - Updates the position and size of the fade border on the canvas. - Called when the application screen is resized. - """ - - height_segment = ( - self.fade_height if self.fade_height else dp(100) - ) // self._height_segment - - if rectangle_top: - rectangle_top.pos = ( - instance_fadind_edge_effect.x, - size[1] - - (index * height_segment - instance_fadind_edge_effect.y), - ) - rectangle_top.size = (size[0], height_segment) - if rectangle_bottom: - rectangle_bottom.pos = ( - instance_fadind_edge_effect.x, - index * height_segment + instance_fadind_edge_effect.y, - ) - rectangle_bottom.size = (size[0], height_segment) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__init__.py deleted file mode 100644 index 2fbddae..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .roulettescroll import RouletteScrollEffect diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index a4379aa..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__pycache__/roulettescroll.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__pycache__/roulettescroll.cpython-311.pyc deleted file mode 100644 index 360857b..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/__pycache__/roulettescroll.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/roulettescroll.py b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/roulettescroll.py deleted file mode 100644 index 528f5ac..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/roulettescroll/roulettescroll.py +++ /dev/null @@ -1,251 +0,0 @@ -""" -Effects/RouletteScrollEffect -============================ - -This is a subclass of :class:`kivy.effects.ScrollEffect` that simulates the -motion of a roulette, or a notched wheel (think Wheel of Fortune). It is -primarily designed for emulating the effect of the iOS and android date pickers. - -Usage ------ - -Here's an example of using :class:`RouletteScrollEffect` for a -:class:`kivy.uix.scrollview.ScrollView`: - -.. code-block:: python - - from kivy.uix.gridlayout import GridLayout - from kivy.uix.button import Button - from kivy.uix.scrollview import ScrollView - - # Preparing a `GridLayout` inside a `ScrollView`. - layout = GridLayout(cols=1, padding=10, size_hint=(None, None), width=500) - layout.bind(minimum_height=layout.setter('height')) - - for i in range(30): - btn = Button(text=str(i), size=(480, 40), size_hint=(None, None)) - layout.add_widget(btn) - - root = ScrollView( - size_hint=(None, None), - size=(500, 320), - pos_hint={'center_x': .5, 'center_y': .5}, - do_scroll_x=False, - ) - root.add_widget(layout) - - # Preparation complete. Now add the new scroll effect. - root.effect_y = RouletteScrollEffect(anchor=20, interval=40) - runTouchApp(root) - -Here the :class:`ScrollView` scrolls through a series of buttons with height -40. We then attached a :class:`RouletteScrollEffect` with interval 40, -corresponding to the button heights. This allows the scrolling to stop at -the same offset no matter where it stops. The :attr:`RouletteScrollEffect.anchor` -adjusts this offset. - -Customizations --------------- - -Other settings that can be played with include: - -:attr:`RouletteScrollEffect.pull_duration`, -:attr:`RouletteScrollEffect.coasting_alpha`, -:attr:`RouletteScrollEffect.pull_back_velocity`, and -:attr:`RouletteScrollEffect.terminal_velocity`. - -See their module documentations for details. - -:class:`RouletteScrollEffect` has one event ``on_coasted_to_stop`` that -is fired when the roulette stops, "making a selection". It can be listened to -for handling or cleaning up choice making. -""" - -from math import ceil, exp, floor - -from kivy.animation import Animation -from kivy.effects.scroll import ScrollEffect -from kivy.properties import AliasProperty, NumericProperty, ObjectProperty - -__all_ = ("RouletteScrollEffect",) - - -class RouletteScrollEffect(ScrollEffect): - """ - This is a subclass of :class:`kivy.effects.ScrollEffect` that simulates the - motion of a roulette, or a notched wheel (think Wheel of Fortune). It is - primarily designed for emulating the effect of the iOS and android date pickers. - - .. versionadded:: 0.104.2 - """ - - __events__ = ("on_coasted_to_stop",) - - drag_threshold = NumericProperty(0) - """ - Overrides :attr:`ScrollEffect.drag_threshold` to abolish drag threshold. - - .. note:: - If using this with a :class:`Roulette` or other :class:`Tickline` - subclasses, what matters is :attr:`Tickline.drag_threshold`, which - is passed to this attribute in the end. - - :attr:`drag_threshold` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0`. - """ - - min = NumericProperty(-float("inf")) - max = NumericProperty(float("inf")) - - interval = NumericProperty(50) - """ - The interval of the values of the "roulette". - - :attr:`interval` is an :class:`~kivy.properties.NumericProperty` - and defaults to `50`. - """ - - anchor = NumericProperty(0) - """ - One of the valid stopping values. - - :attr:`anchor` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0`. - """ - - pull_duration = NumericProperty(0.2) - """ - When movement slows around a stopping value, an animation is used - to pull it toward the nearest value. :attr:`pull_duration` is the duration - used for such an animation. - - :attr:`pull_duration` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - coasting_alpha = NumericProperty(0.5) - """ - When within :attr:`coasting_alpha` * :attr:`interval` of the - next notch and velocity is below :attr:`terminal_velocity`, - coasting begins and will end on the next notch. - - :attr:`coasting_alpha` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0.5`. - """ - - pull_back_velocity = NumericProperty("50sp") - """ - The velocity below which the scroll value will be drawn to the - *nearest* notch instead of the *next* notch in the direction travelled. - - :attr:`pull_back_velocity` is an :class:`~kivy.properties.NumericProperty` - and defaults to `50sp`. - """ - - _anim = ObjectProperty(None) - - def get_term_vel(self): - return ( - exp(self.friction) - * self.interval - * self.coasting_alpha - / self.pull_duration - ) - - def set_term_vel(self, val): - self.pull_duration = ( - exp(self.friction) * self.interval * self.coasting_alpha / val - ) - - terminal_velocity = AliasProperty( - get_term_vel, - set_term_vel, - bind=["interval", "coasting_alpha", "pull_duration", "friction"], - cache=True, - ) - """ - If velocity falls between :attr:`pull_back_velocity` and - :attr:`terminal velocity` then the movement will start to coast - to the next coming stopping value. - - :attr:`terminal_velocity` is computed from a set formula given - :attr:`interval`, :attr:`coasting_alpha`, :attr:`pull_duration`, - and :attr:`friction`. Setting :attr:`terminal_velocity` has the - effect of setting :attr:`pull_duration`. - """ - - def start(self, val, t=None): - if self._anim: - self._anim.stop(self) - return ScrollEffect.start(self, val, t=t) - - def on_notch(self, *args): - return (self.scroll - self.anchor) % self.interval == 0 - - def nearest_notch(self, *args): - interval = float(self.interval) - anchor = self.anchor - n = round((self.scroll - anchor) / interval) - return anchor + n * interval - - def next_notch(self, *args): - interval = float(self.interval) - anchor = self.anchor - round_ = ceil if self.velocity > 0 else floor - n = round_((self.scroll - anchor) / interval) - return anchor + n * interval - - def near_notch(self, d=0.01): - nearest = self.nearest_notch() - if abs((nearest - self.scroll) / self.interval) % 1 < d: - return nearest - else: - return None - - def near_next_notch(self, d=None): - d = d or self.coasting_alpha - next_ = self.next_notch() - if abs((next_ - self.scroll) / self.interval) % 1 < d: - return next_ - else: - return None - - def update_velocity(self, dt): - if self.is_manual: - return - velocity = self.velocity - t_velocity = self.terminal_velocity - next_ = self.near_next_notch() - pull_back_velocity = self.pull_back_velocity - if pull_back_velocity < abs(velocity) < t_velocity and next_: - duration = abs((next_ - self.scroll) / self.velocity) - anim = Animation( - scroll=next_, - duration=duration, - ) - self._anim = anim - anim.on_complete = self._coasted_to_stop - anim.start(self) - return - if abs(velocity) < pull_back_velocity and not self.on_notch(): - anim = Animation( - scroll=self.nearest_notch(), - duration=self.pull_duration, - t="in_out_circ", - ) - self._anim = anim - anim.on_complete = self._coasted_to_stop - anim.start(self) - else: - self.velocity -= self.velocity * self.friction - self.apply_distance(self.velocity * dt) - self.trigger_velocity_update() - - def on_coasted_to_stop(self, *args): - """ - This event fires when the roulette has stopped, `making a selection`. - """ - - def _coasted_to_stop(self, *args): - self.velocity = 0 - self.dispatch("on_coasted_to_stop") diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc index 8ed4555..1c6c278 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc index 149b3c0..4c67d31 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/effects/stiffscroll/__pycache__/stiffscroll.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/factory_registers.py b/kivy_venv/lib/python3.11/site-packages/kivymd/factory_registers.py index 4497bfe..50fcd00 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/factory_registers.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/factory_registers.py @@ -7,11 +7,11 @@ from kivy.factory import Factory register = Factory.register register("MDSegmentedButton", module="kivymd.uix.segmentedbutton") register("MDSegmentedButtonItem", module="kivymd.uix.segmentedbutton") +register("MDSegmentButtonIcon", module="kivymd.uix.segmentedbutton") +register("MDSegmentButtonLabel", module="kivymd.uix.segmentedbutton") register("MDScrollView", module="kivymd.uix.scrollview") register("MDRecycleView", module="kivymd.uix.recycleview") register("MDResponsiveLayout", module="kivymd.uix.responsivelayout") -register("MDSegmentedControl", module="kivymd.uix.segmentedcontrol") -register("MDSegmentedControlItem", module="kivymd.uix.segmentedcontrol") register("MDSliverAppbar", module="kivymd.uix.sliverappbar") register("MDSliverAppbarContent", module="kivymd.uix.sliverappbar") register("MDSliverAppbarHeader", module="kivymd.uix.sliverappbar") @@ -19,8 +19,9 @@ register("MDNavigationRailItem", module="kivymd.uix.navigationrail") register("MDNavigationRail", module="kivymd.uix.navigationrail") register("MDNavigationRailFabButton", module="kivymd.uix.navigationrail") register("MDNavigationRailMenuButton", module="kivymd.uix.navigationrail") +register("MDNavigationRailItemIcon", module="kivymd.uix.navigationrail") +register("MDNavigationRailItemLabel", module="kivymd.uix.navigationrail") register("MDSwiper", module="kivymd.uix.swiper") -register("MDCarousel", module="kivymd.uix.carousel") register("MDWidget", module="kivymd.uix.widget") register("MDFloatLayout", module="kivymd.uix.floatlayout") register("MDAnchorLayout", module="kivymd.uix.anchorlayout") @@ -32,80 +33,102 @@ register("MDRelativeLayout", module="kivymd.uix.relativelayout") register("MDGridLayout", module="kivymd.uix.gridlayout") register("MDStackLayout", module="kivymd.uix.stacklayout") register("MDExpansionPanel", module="kivymd.uix.expansionpanel") -register("MDExpansionPanelOneLine", module="kivymd.uix.expansionpanel") -register("MDExpansionPanelTwoLine", module="kivymd.uix.expansionpanel") -register("MDExpansionPanelThreeLine", module="kivymd.uix.expansionpanel") +register("MDExpansionPanelHeader", module="kivymd.uix.expansionpanel") +register("MDExpansionPanelContent", module="kivymd.uix.expansionpanel") register("FitImage", module="kivymd.uix.fitimage") register("MDBackdrop", module="kivymd.uix.backdrop") -register("MDBanner", module="kivymd.uix.banner") register("MDTooltip", module="kivymd.uix.tooltip") +register("MDTooltipPlain", module="kivymd.uix.tooltip") +register("MDTooltipRich", module="kivymd.uix.tooltip") +register("MDTooltipRichActionButton", module="kivymd.uix.tooltip") +register("MDTooltipRichSubhead", module="kivymd.uix.tooltip") +register("MDTooltipRichSupportingText", module="kivymd.uix.tooltip") register("MDBottomSheet", module="kivymd.uix.bottomsheet") -register("MDBottomNavigation", module="kivymd.uix.bottomnavigation") -register("MDBottomNavigationItem", module="kivymd.uix.bottomnavigation") +register("MDBottomSheetDragHandle", module="kivymd.uix.bottomsheet") +register("MDBottomSheetDragHandleButton", module="kivymd.uix.bottomsheet") +register("MDBottomSheetDragHandleTitle", module="kivymd.uix.bottomsheet") +register("MDNavigationBar", module="kivymd.uix.navigationbar") +register("MDNavigationItem", module="kivymd.uix.navigationbar") +register("MDNavigationItemLabel", module="kivymd.uix.navigationbar") +register("MDNavigationItemIcon", module="kivymd.uix.navigationbar") register("MDToggleButton", module="kivymd.uix.behaviors.toggle_behavior") -register("MDFloatingActionButtonSpeedDial", module="kivymd.uix.button") +register("MDButton", module="kivymd.uix.button") +register("MDButtonText", module="kivymd.uix.button") +register("MDButtonIcon", module="kivymd.uix.button") +register("MDFabButton", module="kivymd.uix.button") register("MDIconButton", module="kivymd.uix.button") -register("MDRoundImageButton", module="kivymd.uix.button") -register("MDFlatButton", module="kivymd.uix.button") -register("MDRaisedButton", module="kivymd.uix.button") -register("MDFloatingActionButton", module="kivymd.uix.button") -register("MDRectangleFlatButton", module="kivymd.uix.button") -register("MDTextButton", module="kivymd.uix.button") -register("MDCustomRoundIconButton", module="kivymd.uix.button") -register("MDRoundFlatButton", module="kivymd.uix.button") -register("MDFillRoundFlatButton", module="kivymd.uix.button") -register("MDRectangleFlatIconButton", module="kivymd.uix.button") -register("MDRoundFlatIconButton", module="kivymd.uix.button") -register("MDFillRoundFlatIconButton", module="kivymd.uix.button") +register("MDExtendedFabButton", module="kivymd.uix.button") +register("MDExtendedFabButtonIcon", module="kivymd.uix.button") +register("MDExtendedFabButtonText", module="kivymd.uix.button") register("MDCard", module="kivymd.uix.card") -register("MDSeparator", module="kivymd.uix.card") -register("MDSelectionList", module="kivymd.uix.selection") +register("MDDivider", module="kivymd.uix.divider") register("MDChip", module="kivymd.uix.chip") +register("MDChipLeadingAvatar", module="kivymd.uix.chip") +register("MDChipLeadingIcon", module="kivymd.uix.chip") +register("MDChipTrailingIcon", module="kivymd.uix.chip") +register("MDChipText", module="kivymd.uix.chip") register("MDSmartTile", module="kivymd.uix.imagelist") +register("MDSmartTileOverlayContainer", module="kivymd.uix.imagelist") +register("MDSmartTileImage", module="kivymd.uix.imagelist") register("MDLabel", module="kivymd.uix.label") register("MDIcon", module="kivymd.uix.label") +register("MDBadge", module="kivymd.uix.badge") register("MDList", module="kivymd.uix.list") -register("ILeftBody", module="kivymd.uix.list") -register("ILeftBodyTouch", module="kivymd.uix.list") -register("IRightBody", module="kivymd.uix.list") -register("IRightBodyTouch", module="kivymd.uix.list") -register("OneLineListItem", module="kivymd.uix.list") -register("TwoLineListItem", module="kivymd.uix.list") -register("ThreeLineListItem", module="kivymd.uix.list") -register("OneLineAvatarListItem", module="kivymd.uix.list") -register("TwoLineAvatarListItem", module="kivymd.uix.list") -register("ThreeLineAvatarListItem", module="kivymd.uix.list") -register("OneLineIconListItem", module="kivymd.uix.list") -register("TwoLineIconListItem", module="kivymd.uix.list") -register("ThreeLineIconListItem", module="kivymd.uix.list") -register("OneLineRightIconListItem", module="kivymd.uix.list") -register("TwoLineRightIconListItem", module="kivymd.uix.list") -register("ThreeLineRightIconListItem", module="kivymd.uix.list") -register("OneLineAvatarIconListItem", module="kivymd.uix.list") -register("TwoLineAvatarIconListItem", module="kivymd.uix.list") -register("ThreeLineAvatarIconListItem", module="kivymd.uix.list") +register("MDListItem", module="kivymd.uix.list") +register("MDListItemHeadlineText", module="kivymd.uix.list") +register("MDListItemSupportingText", module="kivymd.uix.list") +register("MDListItemTrailingSupportingText", module="kivymd.uix.list") +register("MDListItemLeadingIcon", module="kivymd.uix.list") +register("MDListItemTrailingIcon", module="kivymd.uix.list") +register("MDListItemTrailingCheckbox", module="kivymd.uix.list") +register("MDListItemTertiaryText", module="kivymd.uix.list") register("HoverBehavior", module="kivymd.uix.behaviors.hover_behavior") register("FocusBehavior", module="kivymd.uix.behaviors.focus_behavior") register("MagicBehavior", module="kivymd.uix.behaviors.magic_behavior") register("MDNavigationDrawer", module="kivymd.uix.navigationdrawer") register("MDNavigationLayout", module="kivymd.uix.navigationdrawer") register("MDNavigationDrawerMenu", module="kivymd.uix.navigationdrawer") -register("MDNavigationDrawerHeader", module="kivymd.uix.navigationdrawer") register("MDNavigationDrawerItem", module="kivymd.uix.navigationdrawer") +register( + "MDNavigationDrawerItemLeadingIcon", module="kivymd.uix.navigationdrawer" +) +register( + "MDNavigationDrawerItemTrailingText", module="kivymd.uix.navigationdrawer" +) +register("MDNavigationDrawerHeader", module="kivymd.uix.navigationdrawer") +register("MDNavigationDrawerItemText", module="kivymd.uix.navigationdrawer") register("MDNavigationDrawerLabel", module="kivymd.uix.navigationdrawer") register("MDNavigationDrawerDivider", module="kivymd.uix.navigationdrawer") -register("MDProgressBar", module="kivymd.uix.progressbar") register("MDScrollViewRefreshLayout", module="kivymd.uix.refreshlayout") register("MDCheckbox", module="kivymd.uix.selectioncontrol") register("MDSwitch", module="kivymd.uix.selectioncontrol") register("MDSlider", module="kivymd.uix.slider") -register("MDSpinner", module="kivymd.uix.spinner") -register("MDTabs", module="kivymd.uix.tab") +register("MDCircularProgressIndicator", module="kivymd.uix.progressindicator") +register("MDLinearProgressIndicator", module="kivymd.uix.progressindicator") +register("MDTabsPrimary", module="kivymd.uix.tab") +register("MDTabsSecondary", module="kivymd.uix.tab") +register("MDTabsItem", module="kivymd.uix.tab") +register("MDTabsItemSecondary", module="kivymd.uix.tab") +register("MDTabsBadge", module="kivymd.uix.tab") +register("MDTabsItemIcon", module="kivymd.uix.tab") +register("MDTabsItemText", module="kivymd.uix.tab") +register("MDTabsCarousel", module="kivymd.uix.tab") register("MDTextField", module="kivymd.uix.textfield") -register("MDTextFieldRect", module="kivymd.uix.textfield") -register("MDTopAppBar", module="kivymd.uix.toolbar") -register("MDBottomAppBar", module="kivymd.uix.toolbar") +register("MDTextFieldHelperText", module="kivymd.uix.textfield") +register("MDTextFieldMaxLengthText", module="kivymd.uix.textfield") +register("MDTextFieldHintText", module="kivymd.uix.textfield") +register("MDTextFieldLeadingIcon", module="kivymd.uix.textfield") +register("MDTextFieldTrailingIcon", module="kivymd.uix.textfield") +register("MDTopAppBarTrailingButtonContainer", module="kivymd.uix.appbar") +register("MDTopAppBarLeadingButtonContainer", module="kivymd.uix.appbar") +register("MDFabBottomAppBarButton", module="kivymd.uix.appbar") +register("MDActionBottomAppBarButton", module="kivymd.uix.appbar") +register("MDTopAppBarTitle", module="kivymd.uix.appbar") +register("MDTopAppBar", module="kivymd.uix.appbar") +register("MDBottomAppBar", module="kivymd.uix.appbar") +register("MDActionTopAppBarButton", module="kivymd.uix.appbar") register("MDDropDownItem", module="kivymd.uix.dropdownitem") +register("MDDropDownItemText", module="kivymd.uix.dropdownitem") register("MDCircularLayout", module="kivymd.uix.circularlayout") register("MDHeroFrom", module="kivymd.uix.hero") register("MDHeroTo", module="kivymd.uix.hero") diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/font_definitions.py b/kivy_venv/lib/python3.11/site-packages/kivymd/font_definitions.py index e7cc8e2..c3637e4 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/font_definitions.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/font_definitions.py @@ -1,5 +1,5 @@ """ -Themes/Font Definitions +Themes/Font definitions ======================= .. seealso:: @@ -8,6 +8,7 @@ Themes/Font Definitions """ from kivy.core.text import LabelBase +from kivy.metrics import sp from kivymd import fonts_path @@ -48,22 +49,102 @@ fonts = [ for font in fonts: LabelBase.register(**font) -theme_font_styles = [ - "H1", - "H2", - "H3", - "H4", - "H5", - "H6", - "Subtitle1", - "Subtitle2", - "Body1", - "Body2", - "Button", - "Caption", - "Overline", - "Icon", -] +# TODO: Add `weight` properties. +theme_font_styles = { + "Icon": { + "large": { + "line-height": 1, + "font-name": "Icons", + "font-size": sp(24), + }, + }, + "Display": { + "large": { + "line-height": 1.64, + "font-name": "Roboto", + "font-size": sp(57), + }, + "medium": { + "line-height": 1.52, + "font-name": "Roboto", + "font-size": sp(45), + }, + "small": { + "line-height": 1.44, + "font-name": "Roboto", + "font-size": sp(36), + }, + }, + "Headline": { + "large": { + "line-height": 1.40, + "font-name": "Roboto", + "font-size": sp(32), + }, + "medium": { + "line-height": 1.36, + "font-name": "Roboto", + "font-size": sp(28), + }, + "small": { + "line-height": 1.32, + "font-name": "Roboto", + "font-size": sp(24), + }, + }, + "Title": { + "large": { + "line-height": 1.28, + "font-name": "Roboto", + "font-size": sp(22), + }, + "medium": { + "line-height": 1.24, + "font-name": "Roboto", + "font-size": sp(16), + }, + "small": { + "line-height": 1.20, + "font-name": "Roboto", + "font-size": sp(14), + }, + }, + "Body": { + "large": { + "line-height": 1.24, + "font-name": "Roboto", + "font-size": sp(16), + }, + "medium": { + "line-height": 1.20, + "font-name": "Roboto", + "font-size": sp(14), + }, + "small": { + "line-height": 1.16, + "font-name": "Roboto", + "font-size": sp(12), + }, + }, + "Label": { + "large": { + "line-height": 1.20, + "font-name": "Roboto", + "font-size": sp(14), + }, + "medium": { + "line-height": 1.16, + "font-name": "Roboto", + "font-size": sp(12), + }, + "small": { + "line-height": 1.16, + "font-name": "Roboto", + "font-size": sp(11), + }, + }, +} """ -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-styles-2.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/label-font-style-preview.png + :align: center """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Black.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Black.ttf index 689fe5c..0112e7d 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Black.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Black.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BlackItalic.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BlackItalic.ttf index 0b4e0ee..b2c6aca 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BlackItalic.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BlackItalic.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Bold.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Bold.ttf index d3f01ad..43da14d 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Bold.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Bold.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BoldItalic.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BoldItalic.ttf index 41cc1e7..bcfdab4 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BoldItalic.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-BoldItalic.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Italic.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Italic.ttf index 6a1cee5..1b5eaa3 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Italic.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Italic.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Light.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Light.ttf index 219063a..e7307e7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Light.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Light.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-LightItalic.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-LightItalic.ttf index 0e81e87..2d277af 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-LightItalic.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-LightItalic.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Medium.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Medium.ttf index 1a7f3b0..ac0f908 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Medium.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Medium.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-MediumItalic.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-MediumItalic.ttf index 0030295..fc36a47 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-MediumItalic.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-MediumItalic.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Regular.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Regular.ttf index 2c97eea..ddf4bfa 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Regular.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Regular.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Thin.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Thin.ttf index b74a4fd..2e0dee6 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Thin.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-Thin.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-ThinItalic.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-ThinItalic.ttf index dd0ddb8..084f9c0 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-ThinItalic.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/Roboto-ThinItalic.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/materialdesignicons-webfont.ttf b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/materialdesignicons-webfont.ttf index b00c684..bba7dcf 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/materialdesignicons-webfont.ttf and b/kivy_venv/lib/python3.11/site-packages/kivymd/fonts/materialdesignicons-webfont.ttf differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/icon_definitions.py b/kivy_venv/lib/python3.11/site-packages/kivymd/icon_definitions.py index 53cb540..a45366a 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/icon_definitions.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/icon_definitions.py @@ -2,17 +2,17 @@ Themes/Icon Definitions ======================= -.. seealso:: +.. seealso::Updateeeee - `Material Design Icons `_ + `Material Design Icons `_ -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/material-icons.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/material-m3-icons.png :align: center List of icons from materialdesignicons.com. These expanded material design icons are maintained by Austin Andrews (Templarian on Github). -LAST UPDATED: Version 7.2.96 +Version 7.4.47 To preview the icons and their names, you can use the following application: ---------------------------------------------------------------------------- @@ -21,25 +21,28 @@ To preview the icons and their names, you can use the following application: from kivy.lang import Builder from kivy.properties import StringProperty - from kivy.uix.screenmanager import Screen from kivymd.icon_definitions import md_icons + from kivymd.uix.screen import MDScreen from kivymd.app import MDApp - from kivymd.uix.list import OneLineIconListItem - + from kivymd.uix.list import MDListItem Builder.load_string( ''' #:import images_path kivymd.images_path - + - IconLeftWidget: + MDListItemLeadingIcon: icon: root.icon + MDListItemSupportingText: + text: root.text + + md_bg_color: self.theme_cls.backgroundColor MDBoxLayout: orientation: 'vertical' @@ -51,6 +54,7 @@ To preview the icons and their names, you can use the following application: MDIconButton: icon: 'magnify' + pos_hint: {'center_y': .5} MDTextField: id: search_field @@ -63,7 +67,7 @@ To preview the icons and their names, you can use the following application: key_size: 'height' RecycleBoxLayout: - padding: dp(10) + padding: dp(10), dp(10), 0, dp(10) default_size: None, dp(48) default_size_hint: 1, None size_hint_y: None @@ -73,19 +77,19 @@ To preview the icons and their names, you can use the following application: ) - class CustomOneLineIconListItem(OneLineIconListItem): + class IconItem(MDListItem): icon = StringProperty() + text = StringProperty() - class PreviousMDIcons(Screen): - + class PreviousMDIcons(MDScreen): def set_list_md_icons(self, text="", search=False): '''Builds a list of icons for the screen MDIcons.''' def add_icon_item(name_icon): self.ids.rv.data.append( { - "viewclass": "CustomOneLineIconListItem", + "viewclass": "IconItem", "icon": name_icon, "text": name_icon, "callback": lambda x: x, @@ -115,7 +119,7 @@ To preview the icons and their names, you can use the following application: MainApp().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icons-previous.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/m3-icons-previous.gif :align: center """ @@ -149,9 +153,12 @@ md_icons = { "account-badge": "\U000F1B0A", "account-badge-outline": "\U000F1B0B", "account-box": "\U000F0006", + "account-box-edit-outline": "\U000F1CC8", + "account-box-minus-outline": "\U000F1CC9", "account-box-multiple": "\U000F0934", "account-box-multiple-outline": "\U000F100A", "account-box-outline": "\U000F0007", + "account-box-plus-outline": "\U000F1CCA", "account-cancel": "\U000F12DF", "account-cancel-outline": "\U000F12E0", "account-card": "\U000F1BA4", @@ -181,6 +188,10 @@ md_icons = { "account-edit-outline": "\U000F0FFB", "account-eye": "\U000F0420", "account-eye-outline": "\U000F127B", + "account-file": "\U000F1CA7", + "account-file-outline": "\U000F1CA8", + "account-file-text": "\U000F1CA9", + "account-file-text-outline": "\U000F1CAA", "account-filter": "\U000F0936", "account-filter-outline": "\U000F0F9D", "account-group": "\U000F0849", @@ -669,6 +680,8 @@ md_icons = { "arrow-left-thin-circle-outline": "\U000F159A", "arrow-left-top": "\U000F17A7", "arrow-left-top-bold": "\U000F17A8", + "arrow-oscillating": "\U000F1C91", + "arrow-oscillating-off": "\U000F1C92", "arrow-projectile": "\U000F1840", "arrow-projectile-multiple": "\U000F183F", "arrow-right": "\U000F0054", @@ -840,6 +853,8 @@ md_icons = { "bag-personal-off": "\U000F0E11", "bag-personal-off-outline": "\U000F0E12", "bag-personal-outline": "\U000F0E13", + "bag-personal-plus": "\U000F1CA4", + "bag-personal-plus-outline": "\U000F1CA5", "bag-personal-tag": "\U000F1B0C", "bag-personal-tag-outline": "\U000F1B0D", "bag-suitcase": "\U000F158B", @@ -1145,10 +1160,12 @@ md_icons = { "book-off-outline": "\U000F1695", "book-open": "\U000F00BD", "book-open-blank-variant": "\U000F00BE", + "book-open-blank-variant-outline": "\U000F1CCB", "book-open-outline": "\U000F0B63", "book-open-page-variant": "\U000F05DA", "book-open-page-variant-outline": "\U000F15D6", "book-open-variant": "\U000F14F7", + "book-open-variant-outline": "\U000F1CCC", "book-outline": "\U000F0B64", "book-play": "\U000F0E82", "book-play-outline": "\U000F0E83", @@ -1339,9 +1356,11 @@ md_icons = { "bus-multiple": "\U000F0F3F", "bus-school": "\U000F079F", "bus-side": "\U000F07A0", + "bus-sign": "\U000F1CC1", "bus-stop": "\U000F1012", "bus-stop-covered": "\U000F1013", "bus-stop-uncovered": "\U000F1014", + "bus-wrench": "\U000F1CC2", "butterfly": "\U000F1589", "butterfly-outline": "\U000F158A", "button-cursor": "\U000F1B4F", @@ -1521,6 +1540,7 @@ md_icons = { "car-defrost-rear": "\U000F0D62", "car-door": "\U000F0B6B", "car-door-lock": "\U000F109D", + "car-door-lock-open": "\U000F1C81", "car-electric": "\U000F0B6C", "car-electric-outline": "\U000F15B5", "car-emergency": "\U000F160F", @@ -1639,6 +1659,7 @@ md_icons = { "cash-100": "\U000F0115", "cash-check": "\U000F14EE", "cash-clock": "\U000F1A91", + "cash-edit": "\U000F1CAB", "cash-fast": "\U000F185C", "cash-lock": "\U000F14EA", "cash-lock-open": "\U000F14EB", @@ -1702,6 +1723,7 @@ md_icons = { "chair-school": "\U000F0125", "chandelier": "\U000F1793", "charity": "\U000F0C4F", + "charity-search": "\U000F1C82", "chart-arc": "\U000F0126", "chart-areaspline": "\U000F0127", "chart-areaspline-variant": "\U000F0E91", @@ -1710,6 +1732,8 @@ md_icons = { "chart-bell-curve": "\U000F0C50", "chart-bell-curve-cumulative": "\U000F0FA7", "chart-box": "\U000F154D", + "chart-box-multiple": "\U000F1CCD", + "chart-box-multiple-outline": "\U000F1CCE", "chart-box-outline": "\U000F154E", "chart-box-plus-outline": "\U000F154F", "chart-bubble": "\U000F05E3", @@ -2026,6 +2050,8 @@ md_icons = { "cloud-cog-outline": "\U000F1BF1", "cloud-download": "\U000F0162", "cloud-download-outline": "\U000F0B7D", + "cloud-key": "\U000F1CA1", + "cloud-key-outline": "\U000F1CA2", "cloud-lock": "\U000F11F1", "cloud-lock-open": "\U000F1BF2", "cloud-lock-open-outline": "\U000F1BF3", @@ -2063,6 +2089,10 @@ md_icons = { "coach-lamp-variant": "\U000F1A37", "coat-rack": "\U000F109E", "code-array": "\U000F0168", + "code-block-braces": "\U000F1C83", + "code-block-brackets": "\U000F1C84", + "code-block-parentheses": "\U000F1C85", + "code-block-tags": "\U000F1C86", "code-braces": "\U000F0169", "code-braces-box": "\U000F10D6", "code-brackets": "\U000F016A", @@ -2501,6 +2531,7 @@ md_icons = { "diamond": "\U000F0B8A", "diamond-outline": "\U000F0B8B", "diamond-stone": "\U000F01C8", + "diaper-outline": "\U000F1CCF", "dice-1": "\U000F01CA", "dice-1-outline": "\U000F114A", "dice-2": "\U000F01CB", @@ -2584,6 +2615,7 @@ md_icons = { "donkey": "\U000F07C2", "door": "\U000F081A", "door-closed": "\U000F081B", + "door-closed-cancel": "\U000F1C93", "door-closed-lock": "\U000F10AF", "door-open": "\U000F081C", "door-sliding": "\U000F181E", @@ -2611,6 +2643,7 @@ md_icons = { "download-lock": "\U000F1320", "download-lock-outline": "\U000F1321", "download-multiple": "\U000F09E9", + "download-multiple-outline": "\U000F1CD0", "download-network": "\U000F06F4", "download-network-outline": "\U000F0C66", "download-off": "\U000F10B0", @@ -2643,7 +2676,10 @@ md_icons = { "earbuds-off-outline": "\U000F1851", "earbuds-outline": "\U000F1852", "earth": "\U000F01E7", + "earth-arrow-down": "\U000F1C87", + "earth-arrow-left": "\U000F1C88", "earth-arrow-right": "\U000F1311", + "earth-arrow-up": "\U000F1C89", "earth-box": "\U000F06CD", "earth-box-minus": "\U000F1407", "earth-box-off": "\U000F06CE", @@ -2747,11 +2783,17 @@ md_icons = { "emoticon-kiss-outline": "\U000F0C73", "emoticon-lol": "\U000F1214", "emoticon-lol-outline": "\U000F1215", + "emoticon-minus": "\U000F1CB2", + "emoticon-minus-outline": "\U000F1CB3", "emoticon-neutral": "\U000F0C74", "emoticon-neutral-outline": "\U000F01F6", "emoticon-outline": "\U000F01F2", + "emoticon-plus": "\U000F1CB4", + "emoticon-plus-outline": "\U000F1CB5", "emoticon-poop": "\U000F01F7", "emoticon-poop-outline": "\U000F0C75", + "emoticon-remove": "\U000F1CB6", + "emoticon-remove-outline": "\U000F1CB7", "emoticon-sad": "\U000F0C76", "emoticon-sad-outline": "\U000F01F8", "emoticon-sick": "\U000F157C", @@ -2781,6 +2823,7 @@ md_icons = { "ethernet": "\U000F0200", "ethernet-cable": "\U000F0201", "ethernet-cable-off": "\U000F0202", + "ethernet-off": "\U000F1CD1", "ev-plug-ccs1": "\U000F1519", "ev-plug-ccs2": "\U000F151A", "ev-plug-chademo": "\U000F151B", @@ -2811,6 +2854,7 @@ md_icons = { "eye-check-outline": "\U000F0D05", "eye-circle": "\U000F0B94", "eye-circle-outline": "\U000F0B95", + "eye-closed": "\U000F1CA3", "eye-lock": "\U000F1C06", "eye-lock-open": "\U000F1C07", "eye-lock-open-outline": "\U000F1C08", @@ -3090,6 +3134,7 @@ md_icons = { "fire-hydrant-alert": "\U000F1138", "fire-hydrant-off": "\U000F1139", "fire-off": "\U000F1722", + "fire-station": "\U000F1CC3", "fire-truck": "\U000F08AB", "firebase": "\U000F0967", "firefox": "\U000F0239", @@ -3531,6 +3576,8 @@ md_icons = { "gas-burner": "\U000F1A1B", "gas-cylinder": "\U000F0647", "gas-station": "\U000F0298", + "gas-station-in-use": "\U000F1CC4", + "gas-station-in-use-outline": "\U000F1CC5", "gas-station-off": "\U000F1409", "gas-station-off-outline": "\U000F140A", "gas-station-outline": "\U000F0EB8", @@ -3559,6 +3606,9 @@ md_icons = { "gender-male-female-variant": "\U000F113F", "gender-non-binary": "\U000F1140", "gender-transgender": "\U000F029F", + "generator-mobile": "\U000F1C8A", + "generator-portable": "\U000F1C8B", + "generator-stationary": "\U000F1C8C", "gentoo": "\U000F08E8", "gesture": "\U000F07CB", "gesture-double-tap": "\U000F073C", @@ -3794,6 +3844,7 @@ md_icons = { "heart-pulse": "\U000F05F6", "heart-remove": "\U000F1430", "heart-remove-outline": "\U000F1433", + "heart-search": "\U000F1C8D", "heart-settings": "\U000F1665", "heart-settings-outline": "\U000F1666", "heat-pump": "\U000F1A43", @@ -3918,7 +3969,10 @@ md_icons = { "hospital-building": "\U000F02E1", "hospital-marker": "\U000F02E2", "hot-tub": "\U000F0828", + "hours-12": "\U000F1C94", "hours-24": "\U000F1478", + "hub": "\U000F1C95", + "hub-outline": "\U000F1C96", "hubspot": "\U000F0D17", "hulu": "\U000F0829", "human": "\U000F02E6", @@ -3933,6 +3987,7 @@ md_icons = { "human-female-boy": "\U000F0A59", "human-female-dance": "\U000F15C9", "human-female-female": "\U000F0A5A", + "human-female-female-child": "\U000F1C8E", "human-female-girl": "\U000F0A5B", "human-greeting": "\U000F17C4", "human-greeting-proximity": "\U000F159D", @@ -3950,6 +4005,7 @@ md_icons = { "human-male-height": "\U000F0EFB", "human-male-height-variant": "\U000F0EFC", "human-male-male": "\U000F0A5E", + "human-male-male-child": "\U000F1C8F", "human-non-binary": "\U000F1848", "human-pregnant": "\U000F05CF", "human-queue": "\U000F1571", @@ -4063,6 +4119,59 @@ md_icons = { "integrated-circuit-chip": "\U000F1913", "invert-colors": "\U000F0301", "invert-colors-off": "\U000F0E4A", + "invoice": "\U000F1CD2", + "invoice-arrow-left": "\U000F1CD3", + "invoice-arrow-left-outline": "\U000F1CD4", + "invoice-arrow-right": "\U000F1CD5", + "invoice-arrow-right-outline": "\U000F1CD6", + "invoice-check": "\U000F1CD7", + "invoice-check-outline": "\U000F1CD8", + "invoice-clock": "\U000F1CD9", + "invoice-clock-outline": "\U000F1CDA", + "invoice-edit": "\U000F1CDB", + "invoice-edit-outline": "\U000F1CDC", + "invoice-export-outline": "\U000F1CDD", + "invoice-fast": "\U000F1CDE", + "invoice-fast-outline": "\U000F1CDF", + "invoice-import": "\U000F1CE0", + "invoice-import-outline": "\U000F1CE1", + "invoice-list": "\U000F1CE2", + "invoice-list-outline": "\U000F1CE3", + "invoice-minus": "\U000F1CE4", + "invoice-minus-outline": "\U000F1CE5", + "invoice-multiple": "\U000F1CE6", + "invoice-multiple-outline": "\U000F1CE7", + "invoice-outline": "\U000F1CE8", + "invoice-plus": "\U000F1CE9", + "invoice-plus-outline": "\U000F1CEA", + "invoice-remove": "\U000F1CEB", + "invoice-remove-outline": "\U000F1CEC", + "invoice-send": "\U000F1CED", + "invoice-send-outline": "\U000F1CEE", + "invoice-text": "\U000F1CEF", + "invoice-text-arrow-left": "\U000F1CF0", + "invoice-text-arrow-left-outline": "\U000F1CF1", + "invoice-text-arrow-right": "\U000F1CF2", + "invoice-text-arrow-right-outline": "\U000F1CF3", + "invoice-text-check": "\U000F1CF4", + "invoice-text-check-outline": "\U000F1CF5", + "invoice-text-clock": "\U000F1CF6", + "invoice-text-clock-outline": "\U000F1CF7", + "invoice-text-edit": "\U000F1CF8", + "invoice-text-edit-outline": "\U000F1CF9", + "invoice-text-fast": "\U000F1CFA", + "invoice-text-fast-outline": "\U000F1CFB", + "invoice-text-minus": "\U000F1CFC", + "invoice-text-minus-outline": "\U000F1CFD", + "invoice-text-multiple": "\U000F1CFE", + "invoice-text-multiple-outline": "\U000F1CFF", + "invoice-text-outline": "\U000F1D00", + "invoice-text-plus": "\U000F1D01", + "invoice-text-plus-outline": "\U000F1D02", + "invoice-text-remove": "\U000F1D03", + "invoice-text-remove-outline": "\U000F1D04", + "invoice-text-send": "\U000F1D05", + "invoice-text-send-outline": "\U000F1D06", "iobroker": "\U000F12E8", "ip": "\U000F0A5F", "ip-network": "\U000F0A60", @@ -4073,6 +4182,7 @@ md_icons = { "iron-board": "\U000F1838", "iron-outline": "\U000F1825", "island": "\U000F104F", + "island-variant": "\U000F1CC6", "iv-bag": "\U000F10B9", "jabber": "\U000F0DD5", "jeepney": "\U000F0302", @@ -4313,6 +4423,9 @@ md_icons = { "link-box-outline": "\U000F0D1B", "link-box-variant": "\U000F0D1C", "link-box-variant-outline": "\U000F0D1D", + "link-circle": "\U000F1CAC", + "link-circle-outline": "\U000F1CAD", + "link-edit": "\U000F1CAE", "link-lock": "\U000F10BA", "link-off": "\U000F0338", "link-plus": "\U000F0C94", @@ -4487,9 +4600,11 @@ md_icons = { "medication-outline": "\U000F1B15", "meditation": "\U000F117B", "memory": "\U000F035B", + "memory-arrow-down": "\U000F1CA6", "menorah": "\U000F17D4", "menorah-fire": "\U000F17D5", "menu": "\U000F035C", + "menu-close": "\U000F1C90", "menu-down": "\U000F035D", "menu-down-outline": "\U000F06B6", "menu-left": "\U000F035E", @@ -4694,10 +4809,16 @@ md_icons = { "motorbike-off": "\U000F1B16", "mouse": "\U000F037D", "mouse-bluetooth": "\U000F098B", + "mouse-left-click": "\U000F1D07", + "mouse-left-click-outline": "\U000F1D08", "mouse-move-down": "\U000F1550", "mouse-move-up": "\U000F1551", "mouse-move-vertical": "\U000F1552", "mouse-off": "\U000F037E", + "mouse-outline": "\U000F1D09", + "mouse-right-click": "\U000F1D0A", + "mouse-right-click-outline": "\U000F1D0B", + "mouse-scroll-wheel": "\U000F1D0C", "mouse-variant": "\U000F037F", "mouse-variant-off": "\U000F0380", "move-resize": "\U000F0655", @@ -5139,7 +5260,13 @@ md_icons = { "parking": "\U000F03E3", "party-popper": "\U000F1056", "passport": "\U000F07E3", + "passport-alert": "\U000F1CB8", "passport-biometric": "\U000F0DE1", + "passport-cancel": "\U000F1CB9", + "passport-check": "\U000F1CBA", + "passport-minus": "\U000F1CBB", + "passport-plus": "\U000F1CBC", + "passport-remove": "\U000F1CBD", "pasta": "\U000F1160", "patio-heater": "\U000F0F80", "patreon": "\U000F0882", @@ -5349,6 +5476,7 @@ md_icons = { "plus-network-outline": "\U000F0CBA", "plus-outline": "\U000F0705", "plus-thick": "\U000F11EC", + "pocket": "\U000F1CBE", "podcast": "\U000F0994", "podium": "\U000F0D25", "podium-bronze": "\U000F0D26", @@ -5478,6 +5606,7 @@ md_icons = { "progress-question": "\U000F1522", "progress-star": "\U000F1788", "progress-star-four-points": "\U000F1C3D", + "progress-tag": "\U000F1D0D", "progress-upload": "\U000F0998", "progress-wrench": "\U000F0CBD", "projector": "\U000F042E", @@ -5531,6 +5660,7 @@ md_icons = { "quality-high": "\U000F0435", "quality-low": "\U000F0A0C", "quality-medium": "\U000F0A0D", + "queue-first-in-last-out": "\U000F1CAF", "quora": "\U000F0D29", "rabbit": "\U000F0907", "rabbit-variant": "\U000F1A61", @@ -5779,6 +5909,7 @@ md_icons = { "rounded-corner": "\U000F0607", "router": "\U000F11E2", "router-network": "\U000F1087", + "router-network-wireless": "\U000F1C97", "router-wireless": "\U000F0469", "router-wireless-off": "\U000F15A3", "router-wireless-settings": "\U000F0A69", @@ -5923,10 +6054,14 @@ md_icons = { "serial-port": "\U000F065C", "server": "\U000F048B", "server-minus": "\U000F048C", + "server-minus-outline": "\U000F1C98", "server-network": "\U000F048D", "server-network-off": "\U000F048E", + "server-network-outline": "\U000F1C99", "server-off": "\U000F048F", + "server-outline": "\U000F1C9A", "server-plus": "\U000F0490", + "server-plus-outline": "\U000F1C9B", "server-remove": "\U000F0491", "server-security": "\U000F0492", "set-all": "\U000F0778", @@ -6466,6 +6601,7 @@ md_icons = { "swap-horizontal-bold": "\U000F0BCD", "swap-horizontal-circle": "\U000F0FE1", "swap-horizontal-circle-outline": "\U000F0FE2", + "swap-horizontal-hidden": "\U000F1D0E", "swap-horizontal-variant": "\U000F08C1", "swap-vertical": "\U000F04E2", "swap-vertical-bold": "\U000F0BCE", @@ -6563,6 +6699,8 @@ md_icons = { "tag-arrow-up-outline": "\U000F1732", "tag-check": "\U000F1A7A", "tag-check-outline": "\U000F1A7B", + "tag-edit": "\U000F1C9C", + "tag-edit-outline": "\U000F1C9D", "tag-faces": "\U000F04FA", "tag-heart": "\U000F068B", "tag-heart-outline": "\U000F0BCF", @@ -6838,6 +6976,7 @@ md_icons = { "traffic-light": "\U000F052B", "traffic-light-outline": "\U000F182A", "train": "\U000F052C", + "train-bus": "\U000F1CC7", "train-car": "\U000F0BD8", "train-car-autorack": "\U000F1B2D", "train-car-box": "\U000F1B2E", @@ -6931,6 +7070,8 @@ md_icons = { "truck-flatbed": "\U000F1891", "truck-minus": "\U000F19AE", "truck-minus-outline": "\U000F19BD", + "truck-off-road": "\U000F1C9E", + "truck-off-road-off": "\U000F1C9F", "truck-outline": "\U000F129D", "truck-plus": "\U000F19AD", "truck-plus-outline": "\U000F19BC", @@ -6975,6 +7116,7 @@ md_icons = { "umbrella-closed-outline": "\U000F13E2", "umbrella-closed-variant": "\U000F13E1", "umbrella-outline": "\U000F054B", + "underwear-outline": "\U000F1D0F", "undo": "\U000F054C", "undo-variant": "\U000F054D", "unfold-less-horizontal": "\U000F054E", @@ -6990,15 +7132,21 @@ md_icons = { "unreal": "\U000F09B1", "update": "\U000F06B0", "upload": "\U000F0552", + "upload-box": "\U000F1D10", + "upload-box-outline": "\U000F1D11", + "upload-circle": "\U000F1D12", + "upload-circle-outline": "\U000F1D13", "upload-lock": "\U000F1373", "upload-lock-outline": "\U000F1374", "upload-multiple": "\U000F083D", + "upload-multiple-outline": "\U000F1D14", "upload-network": "\U000F06F6", "upload-network-outline": "\U000F0CD8", "upload-off": "\U000F10C6", "upload-off-outline": "\U000F10C7", "upload-outline": "\U000F0E07", "usb": "\U000F0553", + "usb-c-port": "\U000F1CBF", "usb-flash-drive": "\U000F129E", "usb-flash-drive-outline": "\U000F129F", "usb-port": "\U000F11F0", @@ -7083,6 +7231,7 @@ md_icons = { "video-plus": "\U000F09B3", "video-plus-outline": "\U000F01D3", "video-stabilization": "\U000F091B", + "video-standard-definition": "\U000F1CA0", "video-switch": "\U000F0569", "video-switch-outline": "\U000F0790", "video-vintage": "\U000F0A1C", @@ -7233,6 +7382,9 @@ md_icons = { "watering-can-outline": "\U000F1482", "watermark": "\U000F0612", "wave": "\U000F0F2E", + "wave-arrow-down": "\U000F1CB0", + "wave-arrow-up": "\U000F1CB1", + "wave-undercurrent": "\U000F1CC0", "waveform": "\U000F147D", "waves": "\U000F078D", "waves-arrow-left": "\U000F1859", @@ -7251,6 +7403,9 @@ md_icons = { "weather-hurricane-outline": "\U000F1C78", "weather-lightning": "\U000F0593", "weather-lightning-rainy": "\U000F067E", + "weather-moonset": "\U000F1D15", + "weather-moonset-down": "\U000F1D16", + "weather-moonset-up": "\U000F1D17", "weather-night": "\U000F0594", "weather-night-partly-cloudy": "\U000F0F31", "weather-partly-cloudy": "\U000F0595", @@ -7424,23 +7579,27 @@ md_icons = { if __name__ == "__main__": from kivy.lang import Builder from kivy.properties import StringProperty - from kivy.uix.screenmanager import Screen + from kivymd.uix.screen import MDScreen from kivymd.app import MDApp - from kivymd.uix.list import OneLineIconListItem + from kivymd.uix.list import MDListItem Builder.load_string( """ #:import images_path kivymd.images_path - + - IconLeftWidget: + MDListItemLeadingIcon: icon: root.icon + MDListItemSupportingText: + text: root.text + + md_bg_color: self.theme_cls.backgroundColor MDBoxLayout: orientation: 'vertical' @@ -7452,6 +7611,7 @@ if __name__ == "__main__": MDIconButton: icon: 'magnify' + pos_hint: {'center_y': .5} MDTextField: id: search_field @@ -7464,7 +7624,7 @@ if __name__ == "__main__": key_size: 'height' RecycleBoxLayout: - padding: dp(10) + padding: dp(10), dp(10), 0, dp(10) default_size: None, dp(48) default_size_hint: 1, None size_hint_y: None @@ -7473,17 +7633,18 @@ if __name__ == "__main__": """ ) - class CustomOneLineIconListItem(OneLineIconListItem): + class IconItem(MDListItem): icon = StringProperty() + text = StringProperty() - class PreviousMDIcons(Screen): + class PreviousMDIcons(MDScreen): def set_list_md_icons(self, text="", search=False): """Builds a list of icons for the screen MDIcons.""" def add_icon_item(name_icon): self.ids.rv.data.append( { - "viewclass": "CustomOneLineIconListItem", + "viewclass": "IconItem", "icon": name_icon, "text": name_icon, "callback": lambda x: x, diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/images/alpha_layer.png b/kivy_venv/lib/python3.11/site-packages/kivymd/images/alpha_layer.png deleted file mode 100644 index 70cc2eb..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/images/alpha_layer.png and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/images/black.png b/kivy_venv/lib/python3.11/site-packages/kivymd/images/black.png deleted file mode 100644 index 0380795..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/images/black.png and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/images/blue.png b/kivy_venv/lib/python3.11/site-packages/kivymd/images/blue.png deleted file mode 100644 index b47c1e7..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/images/blue.png and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/images/green.png b/kivy_venv/lib/python3.11/site-packages/kivymd/images/green.png deleted file mode 100644 index 797f279..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/images/green.png and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/images/red.png b/kivy_venv/lib/python3.11/site-packages/kivymd/images/red.png deleted file mode 100644 index eac94b1..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/images/red.png and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/images/yellow.png b/kivy_venv/lib/python3.11/site-packages/kivymd/images/yellow.png deleted file mode 100644 index 6062231..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/images/yellow.png and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/material_resources.py b/kivy_venv/lib/python3.11/site-packages/kivymd/material_resources.py index 2eb6626..f2aeb31 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/material_resources.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/material_resources.py @@ -21,44 +21,3 @@ elif Window.width >= dp(600) and Window.height >= dp(600): DEVICE_TYPE = "tablet" else: DEVICE_TYPE = "mobile" - -if DEVICE_TYPE == "mobile": - MAX_NAV_DRAWER_WIDTH = dp(300) - HORIZ_MARGINS = dp(16) - STANDARD_INCREMENT = dp(56) - PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT - LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - dp(8) -else: - MAX_NAV_DRAWER_WIDTH = dp(400) - HORIZ_MARGINS = dp(24) - STANDARD_INCREMENT = dp(64) - PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT - LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - -# Elevation. -SEGMENT_CONTROL_SEGMENT_SWITCH_ELEVATION = 1 -FILE_MANAGER_TOP_APP_BAR_ELEVATION = 1 -FLOATING_ACTION_BUTTON_M2_ELEVATION = 1 -FLOATING_ACTION_BUTTON_M3_ELEVATION = 0.5 -CARD_STYLE_ELEVATED_M3_ELEVATION = 0.5 -CARD_STYLE_OUTLINED_FILLED_M3_ELEVATION = 0 -DATA_TABLE_ELEVATION = 4 -DROP_DOWN_MENU_ELEVATION = 2 -TOP_APP_BAR_ELEVATION = 2 -SNACK_BAR_ELEVATION = 2 - -# Shadow softness. -RAISED_BUTTON_SOFTNESS = 4 -FLOATING_ACTION_BUTTON_M3_SOFTNESS = 0 -DATA_TABLE_SOFTNESS = 12 -DROP_DOWN_MENU_SOFTNESS = 6 - -# Shadow offset. -RAISED_BUTTON_OFFSET = (0, -2) -FLOATING_ACTION_BUTTON_M2_OFFSET = (0, -1) -FLOATING_ACTION_BUTTON_M3_OFFSET = (0, -2) -DATA_TABLE_OFFSET = (0, -2) -DROP_DOWN_MENU_OFFSET = (0, -2) -SNACK_BAR_OFFSET = (0, -2) - -TOUCH_TARGET_HEIGHT = dp(48) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/theming.py b/kivy_venv/lib/python3.11/site-packages/kivymd/theming.py index 0c89bcb..5b4692f 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/theming.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/theming.py @@ -4,7 +4,7 @@ Themes/Theming .. seealso:: - `Material Design spec, Material theming `_ + `Material Design spec, Dynamic color `_ Material App ------------ @@ -21,231 +21,51 @@ Control material properties The main application class inherited from the :class:`~kivymd.app.MDApp` class has the :attr:`~kivymd.app.MDApp.theme_cls` attribute, with which you control the material properties of your application. - -Changing the theme colors -------------------------- - -The standard theme_cls is designed to provide the standard themes and colors as -defined by Material Design. - -We do not recommend that you change this. - -However, if you do need to change the standard colors, for instance to meet branding -guidelines, you can do this by overloading the `color_definitions.py` object. - -Create a custom color defintion object. This should have the same format as -the `colors `_ -object in `color_definitions.py` and contain definitions for at least the -primary color, the accent color and the Light and Dark backgrounds. - -.. note:: Your custom colors *must* use the names of the - `existing colors as defined in the palette `_ - e.g. You can have `Blue` but you cannot have `NavyBlue`. - -Add the custom theme to the :class:`~kivymd.app.MDApp` as shown in the -following snippet. - -.. tabs:: - - .. tab:: Imperative python style with KV - - .. code-block:: python - - from kivy.lang import Builder - from kivy.properties import ObjectProperty - - from kivymd.app import MDApp - from kivymd.uix.floatlayout import MDFloatLayout - from kivymd.uix.tab import MDTabsBase - from kivymd.icon_definitions import md_icons - - colors = { - "Teal": { - "200": "#212121", - "500": "#212121", - "700": "#212121", - }, - "Red": { - "200": "#C25554", - "500": "#C25554", - "700": "#C25554", - }, - "Light": { - "StatusBar": "E0E0E0", - "AppBar": "#202020", - "Background": "#2E3032", - "CardsDialogs": "#FFFFFF", - "FlatButtonDown": "#CCCCCC", - }, - } - - - KV = ''' - MDBoxLayout: - orientation: "vertical" - - MDTopAppBar: - title: "Custom theme" - - MDTabs: - id: tabs - - - - - MDIconButton: - id: icon - icon: root.icon - icon_size: "48sp" - theme_icon_color: "Custom" - icon_color: "white" - pos_hint: {"center_x": .5, "center_y": .5} - ''' - - - class Tab(MDFloatLayout, MDTabsBase): - '''Class implementing content for a tab.''' - - icon = ObjectProperty() - - - class Example(MDApp): - icons = list(md_icons.keys())[15:30] - - def build(self): - self.theme_cls.colors = colors - self.theme_cls.primary_palette = "Teal" - self.theme_cls.accent_palette = "Red" - return Builder.load_string(KV) - - def on_start(self): - for name_tab in self.icons: - tab = Tab(title="This is " + name_tab, icon=name_tab) - self.root.ids.tabs.add_widget(tab) - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivy.properties import ObjectProperty - - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.button import MDIconButton - from kivymd.uix.floatlayout import MDFloatLayout - from kivymd.uix.tab import MDTabsBase, MDTabs - from kivymd.icon_definitions import md_icons - from kivymd.uix.toolbar import MDTopAppBar - - colors = { - "Teal": { - "200": "#212121", - "500": "#212121", - "700": "#212121", - }, - "Red": { - "200": "#C25554", - "500": "#C25554", - "700": "#C25554", - }, - "Light": { - "StatusBar": "E0E0E0", - "AppBar": "#202020", - "Background": "#2E3032", - "CardsDialogs": "#FFFFFF", - "FlatButtonDown": "#CCCCCC", - }, - } - - - class Tab(MDFloatLayout, MDTabsBase): - '''Class implementing content for a tab.''' - - icon = ObjectProperty() - - - class Example(MDApp): - icons = list(md_icons.keys())[15:30] - - def build(self): - self.theme_cls.colors = colors - self.theme_cls.primary_palette = "Teal" - self.theme_cls.accent_palette = "Red" - - return ( - MDBoxLayout( - MDTopAppBar(title="Custom theme"), - MDTabs(id="tabs"), - orientation="vertical", - ) - ) - - def on_start(self): - for name_tab in self.icons: - self.root.ids.tabs.add_widget( - Tab( - MDIconButton( - icon=name_tab, - icon_size="48sp", - theme_icon_color="Custom", - icon_color="white", - pos_hint={"center_x": .5, "center_y": .5}, - ), - title="This is " + name_tab, - icon=name_tab, - ) - ) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/custom-color.png - :align: center - -This will change the theme colors to your custom definition. In all other -respects, the theming stays as documented. - -.. warning:: Please note that the key ``'Red'`` is a required key for the - dictionary :attr:`kivymd.color_definition.colors`. """ -from kivy.animation import Animation +import os.path +from timeit import default_timer + from kivy.app import App -from kivy.clock import Clock +from kivy.logger import Logger from kivy.core.window import Window from kivy.event import EventDispatcher -from kivy.metrics import dp from kivy.properties import ( AliasProperty, BooleanProperty, - ColorProperty, DictProperty, NumericProperty, ObjectProperty, OptionProperty, StringProperty, ) -from kivy.utils import get_color_from_hex +from kivy import platform +from kivy.utils import get_color_from_hex, rgba, hex_colormap -from kivymd.color_definitions import colors, hue, palette +from kivymd.dynamic_color import DynamicColor from kivymd.font_definitions import theme_font_styles -from kivymd.material_resources import DEVICE_IOS, DEVICE_TYPE +from kivymd.material_resources import DEVICE_IOS + +from materialyoucolor.utils.color_utils import argb_from_rgba_01 +from materialyoucolor.dynamiccolor.material_dynamic_colors import ( + MaterialDynamicColors, +) +from materialyoucolor.utils.platform_utils import SCHEMES, get_dynamic_scheme +from materialyoucolor.hct import Hct +from materialyoucolor.dislike.dislike_analyzer import DislikeAnalyzer -class ThemeManager(EventDispatcher): - primary_palette = OptionProperty("Blue", options=palette) +class ThemeManager(EventDispatcher, DynamicColor): + primary_palette = OptionProperty( + None, + options=[name_color.capitalize() for name_color in hex_colormap.keys()], + ) """ The name of the color scheme that the application will use. All major `material` components will have the color of the specified color theme. - Available options are: `'Red'`, `'Pink'`, `'Purple'`, `'DeepPurple'`, - `'Indigo'`, `'Blue'`, `'LightBlue'`, `'Cyan'`, `'Teal'`, `'Green'`, - `'LightGreen'`, `'Lime'`, `'Yellow'`, `'Amber'`, `'Orange'`, `'DeepOrange'`, - `'Brown'`, `'Gray'`, `'BlueGray'`. + See :attr:`kivy.utils.hex_colormap` keys for available values. To change the color scheme of an application: @@ -261,18 +81,24 @@ class ThemeManager(EventDispatcher): KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor - MDRectangleFlatButton: - text: "Hello, World" + MDButton: + style: "elevated" pos_hint: {"center_x": .5, "center_y": .5} + + MDButtonIcon: + icon: "plus" + + MDButtonText: + text: "Button" ''' class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Red" # "Purple", "Red" - + self.theme_cls.primary_palette = "Olive" # "Purple", "Red" return Builder.load_string(KV) @@ -283,350 +109,166 @@ class ThemeManager(EventDispatcher): .. code-block:: python from kivymd.app import MDApp - from kivymd.uix.button import MDRectangleFlatButton + from kivymd.uix.button import MDButton, MDButtonIcon, MDButtonText from kivymd.uix.screen import MDScreen class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" # "Purple", "Red" + self.theme_cls.primary_palette = "Olive" # "Purple", "Red" return ( MDScreen( - MDRectangleFlatButton( - text="Hello, World", + MDButton( + MDButtonIcon( + icon="plus", + ), + MDButtonText( + text="Button", + ), + style="elevated", pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) + ), + md_bg_color=self.theme_cls.backgroundColor, ) ) Example().run() - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/primary-palette.png + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/primary-palette-m3.png :align: center :attr:`primary_palette` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'Blue'`. + and defaults to `None`. """ - primary_hue = OptionProperty("500", options=hue) + dynamic_color_quality = NumericProperty(1 if platform == "android" else 10) """ - The color hue of the application. + The quality of the generated color scheme from the system wallpaper. + It is equal to or higher than `1`, with `1` representing the maximum quality. - Available options are: `'50'`, `'100'`, `'200'`, `'300'`, `'400'`, `'500'`, - `'600'`, `'700'`, `'800'`, `'900'`, `'A100'`, `'A200'`, `'A400'`, `'A700'`. + .. warning:: - To change the hue color scheme of an application: + Remember that by increasing the quality value, you also increase the + generation time of the color scheme. - .. tabs:: - - .. tab:: Imperative python style with KV - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.screen import MDScreen - from kivymd.uix.button import MDRectangleFlatButton - - - class MainApp(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.primary_hue = "200" # "500" - screen = MDScreen() - screen.add_widget( - MDRectangleFlatButton( - text="Hello, World", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) - ) - return screen - - - MainApp().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.button import MDRectangleFlatButton - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_hue = "200" # "500" - - return ( - MDScreen( - MDRectangleFlatButton( - text="Hello, World", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) - ) - ) - - - Example().run() - - With a value of ``self.theme_cls.primary_hue = "200"`` and ``self.theme_cls.primary_hue = "500"``: - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/primary_hue.png - :align: center - - :attr:`primary_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'500'`. + :attr:`dynamic_color_quality` is an :class:`~kivy.properties.NumericProperty` + and defaults to `10` if platform is not Android else `1`. """ - primary_light_hue = OptionProperty("200", options=hue) + dynamic_color = BooleanProperty(False) """ - Hue value for :attr:`primary_light`. + Enables or disables dynamic color. - :attr:`primary_light_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'200'`. - """ - - primary_dark_hue = OptionProperty("700", options=hue) - """ - Hue value for :attr:`primary_dark`. - - :attr:`primary_light_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'700'`. - """ - - def _get_primary_color(self) -> list: - return get_color_from_hex( - self.colors[self.primary_palette][self.primary_hue] - ) - - primary_color = AliasProperty( - _get_primary_color, bind=("primary_palette", "primary_hue") - ) - """ - The color of the current application theme. - - :attr:`primary_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value of the current application theme, property is readonly. - """ - - def _get_primary_light(self) -> list: - return get_color_from_hex( - self.colors[self.primary_palette][self.primary_light_hue] - ) - - primary_light = AliasProperty( - _get_primary_light, bind=("primary_palette", "primary_light_hue") - ) - """ - Colors of the current application color theme (in lighter color). - - .. tabs:: - - .. tab:: Declarative style with KV - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - - - KV = ''' - MDScreen: - - MDRaisedButton: - text: "primary_light" - pos_hint: {"center_x": 0.5, "center_y": 0.7} - md_bg_color: app.theme_cls.primary_light - - MDRaisedButton: - text: "primary_color" - pos_hint: {"center_x": 0.5, "center_y": 0.5} - - MDRaisedButton: - text: "primary_dark" - pos_hint: {"center_x": 0.5, "center_y": 0.3} - md_bg_color: app.theme_cls.primary_dark - ''' - - - class MainApp(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - - MainApp().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.button import MDRaisedButton - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" - - return ( - MDScreen( - MDRaisedButton( - text="Primary light", - pos_hint={"center_x": 0.5, "center_y": 0.7}, - md_bg_color=self.theme_cls.primary_light, - ), - MDRaisedButton( - text="Primary color", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ), - MDRaisedButton( - text="Primary dark", - pos_hint={"center_x": 0.5, "center_y": 0.3}, - md_bg_color=self.theme_cls.primary_dark, - ), - ) - ) - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/primary-colors-light-dark.png - :align: center - - :attr:`primary_light` is an :class:`~kivy.properties.AliasProperty` that - returns the value of the current application theme (in lighter color), - property is readonly. - """ - - def _get_primary_dark(self) -> list: - return get_color_from_hex( - self.colors[self.primary_palette][self.primary_dark_hue] - ) - - primary_dark = AliasProperty( - _get_primary_dark, bind=("primary_palette", "primary_dark_hue") - ) - """ - Colors of the current application color theme (in darker color). - - :attr:`primary_dark` is an :class:`~kivy.properties.AliasProperty` that - returns the value of the current application theme (in darker color), - property is readonly. - """ - - accent_palette = OptionProperty("Amber", options=palette) - """ - The application color palette used for items such as the tab indicator - in the :class:`~kivymd.uix.tab.MDTabsBar` class and so on. - See :attr:`kivymd.uix.tab.MDTabsBar.indicator_color` attribute. - - :attr:`accent_palette` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'Amber'`. - """ - - accent_hue = OptionProperty("500", options=hue) - """ - Similar to :attr:`primary_hue`, but returns a value for :attr:`accent_palette`. - - :attr:`accent_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'500'`. - """ - - accent_light_hue = OptionProperty("200", options=hue) - """ - Hue value for :attr:`accent_light`. - - :attr:`accent_light_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'200'`. - """ - - accent_dark_hue = OptionProperty("700", options=hue) - """ - Hue value for :attr:`accent_dark`. - - :attr:`accent_dark_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'700'`. - """ - - def _get_accent_color(self) -> list: - return get_color_from_hex( - self.colors[self.accent_palette][self.accent_hue] - ) - - accent_color = AliasProperty( - _get_accent_color, bind=["accent_palette", "accent_hue"] - ) - """ - Similar to :attr:`primary_color`, but returns a value for :attr:`accent_color`. - - :attr:`accent_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`accent_color`, property is - readonly. - """ - - def _get_accent_light(self) -> list: - return get_color_from_hex( - self.colors[self.accent_palette][self.accent_light_hue] - ) - - accent_light = AliasProperty( - _get_accent_light, bind=["accent_palette", "accent_light_hue"] - ) - """ - Similar to :attr:`primary_light`, but returns a value for :attr:`accent_light`. - - :attr:`accent_light` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`accent_light`, property is - readonly. - """ - - def _get_accent_dark(self) -> list: - return get_color_from_hex( - self.colors[self.accent_palette][self.accent_dark_hue] - ) - - accent_dark = AliasProperty( - _get_accent_dark, bind=["accent_palette", "accent_dark_hue"] - ) - """ - Similar to :attr:`primary_dark`, but returns a value for :attr:`accent_dark`. - - :attr:`accent_dark` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`accent_dark`, property is - readonly. - """ - - material_style = OptionProperty("M3", options=["M2", "M3"]) - """ - Material design style. - Available options are: 'M2', 'M3'. - - .. versionadded:: 1.0.0 - - .. versionchanged:: 1.2.0 - By default now `'M3'`. + .. versionadded:: 2.0.0 .. seealso:: + + `Material Design spec, Dynamic color `_ - `Material Design 2 `_ and - `Material Design 3 `_ + To build the color scheme of your application from user wallpapers, you + must enable the `READ_EXTERNAL_STORAGE + `_ + permission if your android version is below 8.1: + + .. code-block:: python + + from kivy import platform + from kivy.lang import Builder + from kivy.clock import Clock + + from kivymd.app import MDApp + + KV = ''' + MDScreen: + md_bg_color: app.theme_cls.surfaceColor + + MDButton: + style: "elevated" + pos_hint: {"center_x": .5, "center_y": .5} + + MDButtonIcon: + icon: "plus" + + MDButtonText: + text: "Elevated" + ''' - :attr:`material_style` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'M3'`. + class Example(MDApp): + def build(self): + return Builder.load_string(KV) + + def on_resume(self, *args): + '''Updating the color scheme when the application resumes.''' + + self.theme_cls.set_colors() + + def set_dynamic_color(self, *args) -> None: + ''' + When sets the `dynamic_color` value, the self method will be + `called.theme_cls.set_colors()` which will generate a color + scheme from a custom wallpaper if `dynamic_color` is `True`. + ''' + + self.theme_cls.dynamic_color = True + + def on_start(self) -> None: + ''' + It is fired at the start of the application and requests the + necessary permissions. + ''' + + def callback(permission, results): + if all([res for res in results]): + Clock.schedule_once(self.set_dynamic_color) + + if platform == "android": + from android.permissions import Permission, request_permissions + + permissions = [Permission.READ_EXTERNAL_STORAGE] + request_permissions(permissions, callback) + + + Example().run() + + :attr:`dynamic_color` is an :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + dynamic_scheme_name = OptionProperty("TONAL_SPOT", options=SCHEMES.keys()) + """ + Name of the dynamic scheme. Availabe schemes `TONAL_SPOT`, `SPRITZ` + `VIBRANT`, `EXPRESSIVE`, `FRUIT_SALAD`, `RAINBOW`, `MONOCHROME`, `FIDELITY` + and `CONTENT`. + + :attr:`dynamic_scheme_name` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'TONAL_SPOT'`. """ - theme_style_switch_animation = BooleanProperty(False) + dynamic_scheme_contrast = NumericProperty(0.0) + """ + The contrast of the generated color scheme. + + :attr:`dynamic_scheme_contrast` is an :class:`~kivy.properties.NumericProperty` + and defaults to `0.0`. + """ + + path_to_wallpaper = StringProperty() + """ + The path to the image to set the color scheme. You can use this option + if you want to use dynamic color on platforms other than the Android + platform. + + .. versionadded:: 2.0.0 + + :attr:`path_to_wallpaper` is an :class:`~kivy.properties.StringProperty` + and defaults to `''`. + """ + + theme_style_switch_animation = BooleanProperty(True) """ Animate app colors when switching app color scheme ('Dark/light'). @@ -644,26 +286,29 @@ class ThemeManager(EventDispatcher): KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor MDCard: orientation: "vertical" padding: 0, 0, 0 , "36dp" size_hint: .5, .5 + style: "elevated" pos_hint: {"center_x": .5, "center_y": .5} - elevation: 2 - shadow_offset: 0, -2 MDLabel: text: "Theme style - {}".format(app.theme_cls.theme_style) halign: "center" valign: "center" bold: True - font_style: "H5" + font_style: "Display" + role: "small" - MDRaisedButton: - text: "Set theme" + MDButton: on_release: app.switch_theme_style() pos_hint: {"center_x": .5} + + MDButtonText: + text: "Set theme" ''' @@ -689,8 +334,10 @@ class ThemeManager(EventDispatcher): .. code-block:: python + from kivy.clock import Clock + from kivymd.app import MDApp - from kivymd.uix.button import MDRaisedButton + from kivymd.uix.button import MDButton, MDButtonText from kivymd.uix.card import MDCard from kivymd.uix.label import MDLabel from kivymd.uix.screen import MDScreen @@ -706,14 +353,18 @@ class ThemeManager(EventDispatcher): MDCard( MDLabel( id="label", - text="Theme style - {}".format(self.theme_cls.theme_style), + text="Theme style - {}".format( + self.theme_cls.theme_style), halign="center", valign="center", bold=True, - font_style="H5", + font_style="Display", + role="small", ), - MDRaisedButton( - text="Set theme", + MDButton( + MDButtonText( + text="Set theme", + ), on_release=self.switch_theme_style, pos_hint={"center_x": 0.5}, ), @@ -722,12 +373,17 @@ class ThemeManager(EventDispatcher): padding=(0, 0, 0, "36dp"), size_hint=(0.5, 0.5), pos_hint={"center_x": 0.5, "center_y": 0.5}, - elevation=2, - shadow_offset=(0, -2), + style="elevated", ) ) ) + def on_start(self): + def on_start(*args): + self.root.md_bg_color = self.theme_cls.backgroundColor + + Clock.schedule_once(on_start) + def switch_theme_style(self, *args): self.theme_cls.primary_palette = ( "Orange" if self.theme_cls.primary_palette == "Red" else "Red" @@ -735,7 +391,7 @@ class ThemeManager(EventDispatcher): self.theme_cls.theme_style = ( "Dark" if self.theme_cls.theme_style == "Light" else "Light" ) - self.root.ids.card.ids.label.text = ( + self.root.get_ids().label.text = ( "Theme style - {}".format(self.theme_cls.theme_style) ) @@ -746,7 +402,7 @@ class ThemeManager(EventDispatcher): :align: center :attr:`theme_style_switch_animation` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. + and defaults to `True`. """ theme_style_switch_animation_duration = NumericProperty(0.2) @@ -774,58 +430,37 @@ class ThemeManager(EventDispatcher): """ App theme style. - .. tabs:: + .. code-block:: python - .. tab:: Imperative python style + from kivy.clock import Clock - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.screen import MDScreen - from kivymd.uix.button import MDRectangleFlatButton + from kivymd.app import MDApp + from kivymd.uix.screen import MDScreen + from kivymd.uix.button import MDButton, MDButtonText - class MainApp(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" # "Light" - screen = MDScreen() - screen.add_widget( - MDRectangleFlatButton( - text="Hello, World", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) - ) - return screen + class Example(MDApp): + def build(self): + self.theme_cls.primary_palette = "Orange" + self.theme_cls.theme_style = "Light" # "Dark" + return MDScreen( + MDButton( + MDButtonText( + text="Hello, World", + ), + style="outlined", + pos_hint={"center_x": 0.5, "center_y": 0.5}, + ) + ) + + def on_start(self): + def on_start(*args): + self.root.md_bg_color = self.theme_cls.backgroundColor + + Clock.schedule_once(on_start) - MainApp().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.button import MDRectangleFlatButton - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" # "Light" - - return ( - MDScreen( - MDRectangleFlatButton( - text="Hello, World", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ), - ) - ) - - - Example().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/theme-style.png :align: center @@ -840,370 +475,6 @@ class ThemeManager(EventDispatcher): else: return self.theme_style - def _get_bg_darkest(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - return get_color_from_hex(self.colors["Light"]["StatusBar"]) - elif theme_style == "Dark": - return get_color_from_hex(self.colors["Dark"]["StatusBar"]) - - bg_darkest = AliasProperty(_get_bg_darkest, bind=["theme_style"]) - """ - Similar to :attr:`bg_dark`, - but the color values are a tone lower (darker) than :attr:`bg_dark`. - - .. tabs:: - - .. tab:: Declarative style with KV - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - - KV = ''' - MDBoxLayout: - - MDWidget: - md_bg_color: app.theme_cls.bg_light - - MDBoxLayout: - md_bg_color: app.theme_cls.bg_normal - - MDBoxLayout: - md_bg_color: app.theme_cls.bg_dark - - MDBoxLayout: - md_bg_color: app.theme_cls.bg_darkest - ''' - - - class MainApp(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" # "Light" - return Builder.load_string(KV) - - - MainApp().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.widget import MDWidget - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" # "Light" - - return ( - MDBoxLayout( - MDWidget( - md_bg_color=self.theme_cls.bg_light, - ), - MDWidget( - md_bg_color=self.theme_cls.bg_normal, - ), - MDWidget( - md_bg_color=self.theme_cls.bg_dark, - ), - MDWidget( - md_bg_color=self.theme_cls.bg_darkest, - ), - ) - ) - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bg-normal-dark-darkest.png - :align: center - - :attr:`bg_darkest` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`bg_darkest`, - property is readonly. - """ - - def _get_op_bg_darkest(self) -> list: - return self._get_bg_darkest(True) - - opposite_bg_darkest = AliasProperty( - _get_op_bg_darkest, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`bg_darkest`. - - :attr:`opposite_bg_darkest` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`opposite_bg_darkest`, - property is readonly. - """ - - def _get_bg_dark(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - return get_color_from_hex(self.colors["Light"]["AppBar"]) - elif theme_style == "Dark": - return get_color_from_hex(self.colors["Dark"]["AppBar"]) - - bg_dark = AliasProperty(_get_bg_dark, bind=["theme_style"]) - """ - Similar to :attr:`bg_normal`, - but the color values are one tone lower (darker) than :attr:`bg_normal`. - - :attr:`bg_dark` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`bg_dark`, - property is readonly. - """ - - def _get_op_bg_dark(self) -> list: - return self._get_bg_dark(True) - - opposite_bg_dark = AliasProperty(_get_op_bg_dark, bind=["theme_style"]) - """ - The opposite value of color in the :attr:`bg_dark`. - - :attr:`opposite_bg_dark` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`opposite_bg_dark`, - property is readonly. - """ - - def _get_bg_normal(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - return get_color_from_hex(self.colors["Light"]["Background"]) - elif theme_style == "Dark": - return get_color_from_hex(self.colors["Dark"]["Background"]) - - bg_normal = AliasProperty(_get_bg_normal, bind=["theme_style"]) - """ - Similar to :attr:`bg_light`, - but the color values are one tone lower (darker) than :attr:`bg_light`. - - :attr:`bg_normal` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`bg_normal`, - property is readonly. - """ - - def _get_op_bg_normal(self) -> list: - return self._get_bg_normal(True) - - opposite_bg_normal = AliasProperty(_get_op_bg_normal, bind=["theme_style"]) - """ - The opposite value of color in the :attr:`bg_normal`. - - :attr:`opposite_bg_normal` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`opposite_bg_normal`, - property is readonly. - """ - - def _get_bg_light(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - return get_color_from_hex(self.colors["Light"]["CardsDialogs"]) - elif theme_style == "Dark": - return get_color_from_hex(self.colors["Dark"]["CardsDialogs"]) - - bg_light = AliasProperty(_get_bg_light, bind=["theme_style"]) - """" - Depending on the style of the theme (`'Dark'` or `'Light`') - that the application uses, :attr:`bg_light` contains the color value - in ``rgba`` format for the widgets background. - - :attr:`bg_light` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`bg_light`, - property is readonly. - """ - - def _get_op_bg_light(self) -> list: - return self._get_bg_light(True) - - opposite_bg_light = AliasProperty(_get_op_bg_light, bind=["theme_style"]) - """ - The opposite value of color in the :attr:`bg_light`. - - :attr:`opposite_bg_light` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`opposite_bg_light`, - property is readonly. - """ - - def _get_divider_color(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - color = get_color_from_hex("000000") - elif theme_style == "Dark": - color = get_color_from_hex("FFFFFF") - color[3] = 0.12 - return color - - divider_color = AliasProperty(_get_divider_color, bind=["theme_style"]) - """ - Color for dividing lines such as :class:`~kivymd.uix.card.MDSeparator`. - - :attr:`divider_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`divider_color`, - property is readonly. - """ - - def _get_op_divider_color(self) -> list: - return self._get_divider_color(True) - - opposite_divider_color = AliasProperty( - _get_op_divider_color, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`divider_color`. - - :attr:`opposite_divider_color` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`opposite_divider_color`, - property is readonly. - """ - - def _get_disabled_primary_color(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - lum = sum(self.primary_color[0:3]) / 3.0 - if theme_style == "Light": - a = 0.38 - elif theme_style == "Dark": - a = 0.50 - return [lum, lum, lum, a] - - disabled_primary_color = AliasProperty( - _get_disabled_primary_color, bind=["theme_style"] - ) - """ - The greyscale disabled version of the current application theme color - in ``rgba`` format. - - .. versionadded:: 1.0.0 - - :attr:`disabled_primary_color` - is an :class:`~kivy.properties.AliasProperty` that returns the value - in ``rgba`` format for :attr:`disabled_primary_color`, - property is readonly. - """ - - def _get_op_disabled_primary_color(self) -> list: - return self._get_disabled_primary_color(True) - - opposite_disabled_primary_color = AliasProperty( - _get_op_disabled_primary_color, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`disabled_primary_color`. - - .. versionadded:: 1.0.0 - - :attr:`opposite_disabled_primary_color` is an - :class:`~kivy.properties.AliasProperty` that returns the value - in ``rgba`` format for :attr:`opposite_disabled_primary_color`, - property is readonly. - """ - - def _get_text_color(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - color = get_color_from_hex("000000") - color[3] = 0.87 - elif theme_style == "Dark": - color = get_color_from_hex("FFFFFF") - return color - - text_color = AliasProperty(_get_text_color, bind=["theme_style"]) - """ - Color of the text used in the :class:`~kivymd.uix.label.MDLabel`. - - :attr:`text_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`text_color`, - property is readonly. - """ - - def _get_op_text_color(self) -> list: - return self._get_text_color(True) - - opposite_text_color = AliasProperty( - _get_op_text_color, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`text_color`. - - :attr:`opposite_text_color` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`opposite_text_color`, - property is readonly. - """ - - def _get_secondary_text_color(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - color = get_color_from_hex("000000") - color[3] = 0.54 - elif theme_style == "Dark": - color = get_color_from_hex("FFFFFF") - color[3] = 0.70 - return color - - secondary_text_color = AliasProperty( - _get_secondary_text_color, bind=["theme_style"] - ) - """ - The color for the secondary text that is used in classes - from the module :class:`~kivymd/uix/list.TwoLineListItem`. - - :attr:`secondary_text_color` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`secondary_text_color`, - property is readonly. - """ - - def _get_op_secondary_text_color(self) -> list: - return self._get_secondary_text_color(True) - - opposite_secondary_text_color = AliasProperty( - _get_op_secondary_text_color, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`secondary_text_color`. - - :attr:`opposite_secondary_text_color` - is an :class:`~kivy.properties.AliasProperty` that returns the value - in ``rgba`` format for :attr:`opposite_secondary_text_color`, - property is readonly. - """ - - def _get_icon_color(self, opposite: bool = False) -> list: - theme_style = self._get_theme_style(opposite) - if theme_style == "Light": - color = get_color_from_hex("000000") - color[3] = 0.54 - elif theme_style == "Dark": - color = get_color_from_hex("FFFFFF") - return color - - icon_color = AliasProperty(_get_icon_color, bind=["theme_style"]) - """ - Color of the icon used in the :class:`~kivymd.uix.button.MDIconButton`. - - :attr:`icon_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`icon_color`, - property is readonly. - """ - - def _get_op_icon_color(self) -> list: - return self._get_icon_color(True) - - opposite_icon_color = AliasProperty( - _get_op_icon_color, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`icon_color`. - - :attr:`opposite_icon_color` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`opposite_icon_color`, - property is readonly. - """ - def _get_disabled_hint_text_color(self, opposite: bool = False) -> list: theme_style = self._get_theme_style(opposite) if theme_style == "Light": @@ -1226,146 +497,22 @@ class ThemeManager(EventDispatcher): property is readonly. """ - def _get_op_disabled_hint_text_color(self) -> list: - return self._get_disabled_hint_text_color(True) - - opposite_disabled_hint_text_color = AliasProperty( - _get_op_disabled_hint_text_color, bind=["theme_style"] - ) - """ - The opposite value of color in the :attr:`disabled_hint_text_color`. - - :attr:`opposite_disabled_hint_text_color` - is an :class:`~kivy.properties.AliasProperty` that returns the value - in ``rgba`` format for :attr:`opposite_disabled_hint_text_color`, - property is readonly. - """ - - # Hardcoded because muh standard - def _get_error_color(self) -> list: - return get_color_from_hex(self.colors["Red"]["A700"]) - - error_color = AliasProperty(_get_error_color, bind=["theme_style"]) - """ - Color of the error text used - in the :class:`~kivymd.uix.textfield.MDTextField`. - - :attr:`error_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`error_color`, - property is readonly. - """ - - def _get_ripple_color(self) -> list: - return self._ripple_color - - def _set_ripple_color(self, value) -> None: - self._ripple_color = value - - _ripple_color = ColorProperty(colors["Gray"]["400"]) - """Private value.""" - - ripple_color = AliasProperty( - _get_ripple_color, _set_ripple_color, bind=["_ripple_color"] - ) - """ - Color of ripple effects. - - :attr:`ripple_color` is an :class:`~kivy.properties.AliasProperty` that - returns the value in ``rgba`` format for :attr:`ripple_color`, - property is readonly. - """ - def _determine_device_orientation(self, _, window_size) -> None: if window_size[0] > window_size[1]: self.device_orientation = "landscape" elif window_size[1] >= window_size[0]: self.device_orientation = "portrait" - device_orientation = StringProperty("") + device_orientation = StringProperty() """ Device orientation. - :attr:`device_orientation` is an :class:`~kivy.properties.StringProperty`. + :attr:`device_orientation` is an :class:`~kivy.properties.StringProperty` + and defaults to `''`. """ - def _get_standard_increment(self) -> float: - if DEVICE_TYPE == "mobile": - if self.device_orientation == "landscape": - return dp(48) - else: - return dp(56) - else: - return dp(64) - - standard_increment = AliasProperty( - _get_standard_increment, bind=["device_orientation"] - ) - """ - Value of standard increment. - - :attr:`standard_increment` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`standard_increment`, - property is readonly. - """ - - def _get_horizontal_margins(self) -> float: - if DEVICE_TYPE == "mobile": - return dp(16) - else: - return dp(24) - - horizontal_margins = AliasProperty(_get_horizontal_margins) - """ - Value of horizontal margins. - - :attr:`horizontal_margins` is an :class:`~kivy.properties.AliasProperty` - that returns the value in ``rgba`` format for :attr:`horizontal_margins`, - property is readonly. - """ - - def on_theme_style(self, interval: int, theme_style: str) -> None: - if ( - hasattr(App.get_running_app(), "theme_cls") - and App.get_running_app().theme_cls == self - ): - self.set_clearcolor_by_theme_style(theme_style) - - _set_clearcolor = False - - def set_clearcolor_by_theme_style(self, theme_style): - if self.theme_style_switch_animation and self._set_clearcolor: - Animation( - clearcolor=get_color_from_hex( - self.colors[theme_style]["Background"] - ), - d=self.theme_style_switch_animation_duration, - t="linear", - ).start(Window) - else: - Window.clearcolor = get_color_from_hex( - self.colors[theme_style]["Background"] - ) - self._set_clearcolor = True - # Font name, size (sp), always caps, letter spacing (sp). - font_styles = DictProperty( - { - "H1": ["RobotoLight", 96, False, -1.5], - "H2": ["RobotoLight", 60, False, -0.5], - "H3": ["Roboto", 48, False, 0], - "H4": ["Roboto", 34, False, 0.25], - "H5": ["Roboto", 24, False, 0], - "H6": ["RobotoMedium", 20, False, 0.15], - "Subtitle1": ["Roboto", 16, False, 0.15], - "Subtitle2": ["RobotoMedium", 14, False, 0.1], - "Body1": ["Roboto", 16, False, 0.5], - "Body2": ["Roboto", 14, False, 0.25], - "Button": ["RobotoMedium", 14, True, 1.25], - "Caption": ["Roboto", 12, False, 0.4], - "Overline": ["Roboto", 10, True, 1.5], - "Icon": ["Icons", 24, False, 0], - } - ) + font_styles = DictProperty(theme_font_styles) """ Data of default font styles. @@ -1380,184 +527,167 @@ class ThemeManager(EventDispatcher): from kivy.core.text import LabelBase from kivy.lang import Builder + from kivy.metrics import sp from kivymd.app import MDApp - from kivymd.font_definitions import theme_font_styles KV = ''' MDScreen: - + md_bg_color: self.theme_cls.backgroundColor + MDLabel: - text: "JetBrainsMono" + text: "MDLabel" halign: "center" - font_style: "JetBrainsMono" + font_style: "nasalization" ''' - class MainApp(MDApp): + class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" LabelBase.register( - name="JetBrainsMono", - fn_regular="JetBrainsMono-Regular.ttf") + name="nasalization", + fn_regular="nasalization.ttf", + ) + + self.theme_cls.font_styles["nasalization"] = { + "large": { + "line-height": 1.64, + "font-name": "nasalization", + "font-size": sp(57), + }, + "medium": { + "line-height": 1.52, + "font-name": "nasalization", + "font-size": sp(45), + }, + "small": { + "line-height": 1.44, + "font-name": "nasalization", + "font-size": sp(36), + }, + } - theme_font_styles.append('JetBrainsMono') - self.theme_cls.font_styles["JetBrainsMono"] = [ - "JetBrainsMono", - 16, - False, - 0.15, - ] return Builder.load_string(KV) - MainApp().run() + Example().run() .. tab:: Declarative python style .. code-block:: python from kivy.core.text import LabelBase + from kivy.metrics import sp - from kivymd.app import MDApp - from kivymd.uix.screen import MDScreen from kivymd.uix.label import MDLabel - from kivymd.font_definitions import theme_font_styles + from kivymd.uix.screen import MDScreen + from kivymd.app import MDApp - class MainApp(MDApp): + class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" LabelBase.register( - name="JetBrainsMono", - fn_regular="JetBrainsMono-Regular.ttf") + name="nasalization", + fn_regular="/Users/urijivanov/Projects/Dev/MyGithub/Articles/StarTest/data/font/nasalization-rg.ttf", + ) + + self.theme_cls.font_styles["nasalization"] = { + "large": { + "line-height": 1.64, + "font-name": "nasalization", + "font-size": sp(57), + }, + "medium": { + "line-height": 1.52, + "font-name": "nasalization", + "font-size": sp(45), + }, + "small": { + "line-height": 1.44, + "font-name": "nasalization", + "font-size": sp(36), + }, + } - theme_font_styles.append('JetBrainsMono') - self.theme_cls.font_styles["JetBrainsMono"] = [ - "JetBrainsMono", - 16, - False, - 0.15, - ] return ( MDScreen( MDLabel( text="JetBrainsMono", halign="center", - font_style="JetBrainsMono", + font_style="nasalization", ) ) ) - MainApp().run() + Example().run() - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-styles.png + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/custom-font-styles.png :align: center :attr:`font_styles` is an :class:`~kivy.properties.DictProperty`. """ - def set_colors( - self, - primary_palette: str, - primary_hue: str, - primary_light_hue: str, - primary_dark_hue: str, - accent_palette: str, - accent_hue: str, - accent_light_hue: str, - accent_dark_hue: str, - ) -> None: - """ - Courtesy method to allow all of the theme color attributes to be set in one call. + on_colors = None + """ + A Helper function called when colors are changed. - :attr:`set_colors` allows all of the following to be set in one method call: + :attr: `on_colors` defaults to `None`. + """ - * primary palette color, - * primary hue, - * primary light hue, - * primary dark hue, - * accent palette color, - * accent hue, - * accent ligth hue, and - * accent dark hue. - - Note that all values *must* be provided. If you only want to set one or two values - use the appropriate method call for that. - - .. tabs:: - - .. tab:: Imperative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.screen import MDScreen - from kivymd.uix.button import MDRectangleFlatButton - - class MainApp(MDApp): - def build(self): - self.theme_cls.set_colors( - "Blue", "600", "50", "800", "Teal", "600", "100", "800" - ) - screen = MDScreen() - screen.add_widget( - MDRectangleFlatButton( - text="Hello, World", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) - ) - return screen - - - MainApp().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.screen import MDScreen - from kivymd.uix.button import MDRectangleFlatButton - - class MainApp(MDApp): - def build(self): - self.theme_cls.set_colors( - "Blue", "600", "50", "800", "Teal", "600", "100", "800" - ) - return ( - MDScreen( - MDRectangleFlatButton( - text="Hello, World", - pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) - ) - ) - - - MainApp().run() - """ - - self.primary_palette = primary_palette - self.primary_hue = primary_hue - self.primary_light_hue = primary_light_hue - self.primary_dark_hue = primary_dark_hue - self.accent_palette = accent_palette - self.accent_hue = accent_hue - self.accent_light_hue = accent_light_hue - self.accent_dark_hue = accent_dark_hue + _size_current_wallpaper = NumericProperty(0) + _dark_mode = lambda self : False if self.theme_style == "Light" else True def __init__(self, **kwargs): super().__init__(**kwargs) - Clock.schedule_once(lambda x: self.on_theme_style(0, self.theme_style)) self._determine_device_orientation(None, Window.size) Window.bind(size=self._determine_device_orientation) - self.bind(font_styles=self.sync_theme_styles) - self.colors = colors - Clock.schedule_once(self.sync_theme_styles) + + def set_colors(self, *args) -> None: + """Fired methods for setting a new color scheme.""" + + if not self.dynamic_color: + if not self.primary_palette: + self._set_application_scheme() + else: + self._set_palette_color() + else: + system_scheme = get_dynamic_scheme( + dark_mode=self._dark_mode(), + contrast=self.dynamic_scheme_contrast, + dynamic_color_quality=self.dynamic_color_quality, + fallback_wallpaper_path=self.path_to_wallpaper, + fallback_scheme_name=self.dynamic_scheme_name, + message_logger=Logger.info, + logger_head="KivyMD" + ) + if system_scheme: + self._set_color_names(system_scheme) + else: + self._set_application_scheme() + + def update_theme_colors(self, *args) -> None: + """Fired when the `theme_style` value changes.""" + + self.set_colors() + + def on_dynamic_scheme_name(self, *args): + self.set_colors() + + def on_dynamic_scheme_contrast(self, *args): + self.set_colors() + + def on_path_to_wallpaper(self, *args): + self.set_colors() + + def switch_theme(self) -> None: + """Switches the theme from light to dark.""" + + self.theme_style = "Dark" if self.theme_style == "Light" else "Light" def sync_theme_styles(self, *args) -> None: # Syncs the values from self.font_styles to theme_font_styles @@ -1568,6 +698,41 @@ class ThemeManager(EventDispatcher): for style in self.font_styles.keys(): theme_font_styles.append(style) + def _set_application_scheme( + self, + color = "blue", # Google default + ) -> None: + if not color: + color = "blue" + + color = get_color_from_hex(hex_colormap[color.lower()]) + color = Hct.from_int(argb_from_rgba_01(color)) + color = DislikeAnalyzer.fix_if_disliked(color).to_int() + + self._set_color_names( + SCHEMES[self.dynamic_scheme_name]( + Hct.from_int(color), + self._dark_mode(), + self.dynamic_scheme_contrast, + ) + ) + + def _set_color_names(self, scheme) -> None: + for color_name in vars(MaterialDynamicColors).keys(): + attr = getattr(MaterialDynamicColors, color_name) + if hasattr(attr, "get_hct"): + color_value = rgba(attr.get_hct(scheme).to_rgba()) + exec(f"self.{color_name}Color = {color_value}") + + self.disabledTextColor = self._get_disabled_hint_text_color() + if self.on_colors: + self.on_colors() + + def _set_palette_color(self) -> None: + if not self.primary_palette: + self.primary_palette = "Blue" + self._set_application_scheme(self.primary_palette) + class ThemableBehavior(EventDispatcher): theme_cls = ObjectProperty() @@ -1584,72 +749,214 @@ class ThemableBehavior(EventDispatcher): :attr:`device_ios` is an :class:`~kivy.properties.BooleanProperty`. """ - widget_style = OptionProperty( - "android", options=["android", "ios", "desktop"] + theme_line_color = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Line color scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_line_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_bg_color = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Background color scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_bg_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_shadow_color = OptionProperty( + "Primary", options=["Primary", "Custom"] ) """ - Allows to set one of the three style properties for the widget: - `'android'`, `'ios'`, `'desktop'`. + Elevation color scheme name. - For example, for the class :class:`~kivymd.uix.selectioncontrol.MDSwitch` - has two styles - `'android'` and `'ios'`: + .. versionadded:: 2.0.0 - .. code-block:: kv + Available options are: `'Primary'`, `'Custom'`. - MDSwitch: - widget_style: "ios" - - .. code-block:: kv - - MDSwitch: - widget_style: "android" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/switch-android-ios.png - :align: center - - :attr:`widget_style` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'android'`. + :attr:`theme_shadow_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. """ - opposite_colors = BooleanProperty(False) + theme_shadow_offset = OptionProperty( + "Primary", options=["Primary", "Custom"] + ) """ - For some widgets, for example, for a widget - :class:`~kivymd.uix.toolbar.MDTopAppBar` changes the color of the label to - the color opposite to the main theme. + Elevation offset scheme name. - .. code-block:: kv + .. versionadded:: 2.0.0 - MDTopAppBar: - title: "MDTopAppBar" - opposite_colors: True + Available options are: `'Primary'`, `'Custom'`. - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toolbar-opposite-true.png - :align: center + :attr:`theme_shadow_offset` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ - .. code-block:: kv + theme_elevation_level = OptionProperty( + "Primary", options=["Primary", "Custom"] + ) + """ + Elevation level scheme name. - MDTopAppBar: - title: "MDTopAppBar" - opposite_colors: True + .. versionadded:: 2.0.0 - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toolbar-opposite-false.png - :align: center + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_elevation_level` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_font_size = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Font size scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_font_size` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_width = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Widget width scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_width` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_height = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Widget width scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_height` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_line_height = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Line height scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_line_height` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_font_name = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Font name scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_font_name` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_shadow_softness = OptionProperty( + "Primary", options=["Primary", "Custom"] + ) + """ + Elevation softness scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_shadow_softness` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_focus_color = OptionProperty("Primary", options=["Primary", "Custom"]) + """ + Focus color scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_focus_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_divider_color = OptionProperty( + "Primary", options=["Primary", "Custom"] + ) + """ + Divider color scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_divider_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_text_color = OptionProperty( + "Primary", + options=[ + "Primary", + "Secondary", + "Hint", + "Error", + "Custom", + ], + ) + """ + Label color scheme name. + + Available options are: `'Primary'`, `'Secondary'`, `'Hint'`, `'Error'`, + `'Custom'`. + + :attr:`theme_text_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. + """ + + theme_icon_color = OptionProperty( + "Primary", + options=[ + "Primary", + "Secondary", + "Hint", + "Error", + "Custom", + ], + ) + """ + Label color scheme name. + + Available options are: `'Primary'`, `'Secondary'`, `'Hint'`, `'Error'`, + `'Custom'`. + + :attr:`theme_icon_color` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Primary'`. """ def __init__(self, **kwargs): - self.unbind_properties = [ - "theme_style", - "material_style", - "device_orientation", - "primary_color", - "primary_palette", - "accent_palette", - "text_color", - ] - - if self.theme_cls is not None: - pass - else: + if self.theme_cls is None: try: if not isinstance( App.get_running_app().property("theme_cls", True), @@ -1690,15 +997,7 @@ class ThemableBehavior(EventDispatcher): if hasattr(callback, "proxy") and hasattr( callback.proxy, "theme_cls" ): - if issubclass(widget.__class__, self.md_textfield): - widget.theme_cls.unbind( - **{ - "theme_style": getattr( - callback.proxy, callback.method_name - ) - } - ) - for property_name in self.unbind_properties: + for property_name in ["theme_style", "primary_palette"]: if widget == callback.proxy: widget.theme_cls.unbind( **{ @@ -1707,10 +1006,6 @@ class ThemableBehavior(EventDispatcher): ) } ) - # KivyMD widgets may contain other MD widgets. - for children in widget.children: - if hasattr(children, "theme_cls"): - self.remove_widget(children) except ReferenceError: pass diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/theming_dynamic_text.py b/kivy_venv/lib/python3.11/site-packages/kivymd/theming_dynamic_text.py deleted file mode 100644 index 64f9921..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/theming_dynamic_text.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Theming Dynamic Text -==================== - -Two implementations. The first is based on color brightness obtained from- -https://www.w3.org/TR/AERT#color-contrast -The second is based on relative luminance calculation for sRGB obtained from- -https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef -and contrast ratio calculation obtained from- -https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef - -Preliminary testing suggests color brightness more closely matches the -`Material Design spec` suggested text colors, but the alternative implementation -is both newer and the current 'correct' recommendation, so is included here -as an option. -""" - - -def _color_brightness(color): - # Implementation of color brightness method - brightness = color[0] * 299 + color[1] * 587 + color[2] * 114 - brightness = brightness - return brightness - - -def _black_or_white_by_color_brightness(color): - if _color_brightness(color) >= 500: - return "black" - else: - return "white" - - -def _normalized_channel(color): - # Implementation of contrast ratio and relative luminance method - if color <= 0.03928: - return color / 12.92 - else: - return ((color + 0.055) / 1.055) ** 2.4 - - -def _luminance(color): - rg = _normalized_channel(color[0]) - gg = _normalized_channel(color[1]) - bg = _normalized_channel(color[2]) - return 0.2126 * rg + 0.7152 * gg + 0.0722 * bg - - -def _black_or_white_by_contrast_ratio(color): - l_color = _luminance(color) - l_black = 0.0 - l_white = 1.0 - b_contrast = (l_color + 0.05) / (l_black + 0.05) - w_contrast = (l_white + 0.05) / (l_color + 0.05) - return "white" if w_contrast >= b_contrast else "black" - - -def get_contrast_text_color(color, use_color_brightness=True): - if use_color_brightness: - contrast_color = _black_or_white_by_color_brightness(color) - else: - contrast_color = _black_or_white_by_contrast_ratio(color) - if contrast_color == "white": - return 1, 1, 1, 1 - else: - return 0, 0, 0, 1 - - -if __name__ == "__main__": - from kivy.utils import get_color_from_hex - - from kivymd.color_definitions import colors, text_colors - - for c in colors.items(): - if c[0] in ["Light", "Dark"]: - continue - color = c[0] - print(f"For the {color} color palette:") - for name, hex_color in c[1].items(): - if hex_color: - col = get_color_from_hex(hex_color) - col_bri = get_contrast_text_color(col) - con_rat = get_contrast_text_color( - col, use_color_brightness=False - ) - text_color = text_colors[c[0]][name] - print( - f" The {name} hue gives {col_bri} using color " - f"brightness, {con_rat} using contrast ratio, and " - f"{text_color} from the MD spec" - ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__init__.py index d5270c6..2f0df60 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__init__.py @@ -1,11 +1,3 @@ __all__ = ("toast",) -from kivy.utils import platform - -if platform == "android": - try: - from .androidtoast import toast - except ModuleNotFoundError: - from .kivytoast import toast -else: - from .kivytoast import toast +from .androidtoast import toast diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/__init__.cpython-311.pyc index 740a92a..c7b08f6 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/androidtoast.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/androidtoast.cpython-311.pyc new file mode 100644 index 0000000..718f10e Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/__pycache__/androidtoast.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/androidtoast.py b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast.py similarity index 81% rename from kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/androidtoast.py rename to kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast.py index 18af63e..1ab9b4e 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/androidtoast.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast.py @@ -8,26 +8,27 @@ AndroidToast # Will be automatically used native implementation of the toast # if your application is running on an Android device. - # Otherwise, will be used toast implementation - # from the kivymd/toast/kivytoast package. + # On desktop use `MDSnackbar < https://kivymd.readthedocs.io/en/latest/components/snackbar/>`_ from kivy.lang import Builder - from kivy.uix.screenmanager import ScreenManager from kivymd.toast import toast from kivymd.app import MDApp KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor - MDFlatButton: - text: "My Toast" + MDButton: pos_hint:{"center_x": .5, "center_y": .5} on_press: app.show_toast() + + MDButtonText: + text: "Make toast" ''' - class Test(MDApp): + class Example(MDApp): def build(self): return Builder.load_string(KV) @@ -35,7 +36,7 @@ AndroidToast toast("Hello World", True, 80, 200, 0) - Test().run() + Example().run() """ __all__ = ("toast",) @@ -47,10 +48,10 @@ if platform != "android": f"{platform.capitalize()} platform does not support Android Toast" ) +from android import mActivity from android.runnable import run_on_ui_thread from jnius import autoclass -activity = autoclass("org.kivy.android.PythonActivity").mActivity Toast = autoclass("android.widget.Toast") String = autoclass("java.lang.String") @@ -63,7 +64,7 @@ def toast(text, length_long=False, gravity=0, y=0, x=0): :param length_long: the amount of time (in seconds) that the toast is visible on the screen; :param text: text to be displayed in the toast; - :param short_duration: duration of the toast, if `True` the toast + :param length_long: duration of the toast, if `True` the toast will last 2.3s but if it is `False` the toast will last 3.9s; :param gravity: refers to the toast position, if it is 80 the toast will be shown below, if it is 40 the toast will be displayed above; @@ -76,6 +77,6 @@ def toast(text, length_long=False, gravity=0, y=0, x=0): """ duration = Toast.LENGTH_SHORT if length_long else Toast.LENGTH_LONG - t = Toast.makeText(activity, String(text), duration) + t = Toast.makeText(mActivity, String(text), duration) t.setGravity(gravity, x, y) t.show() diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__init__.py deleted file mode 100644 index 300dd2d..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Toast for Android device -======================== - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toast.png - :align: center - -""" - -__all__ = ("toast",) - -from .androidtoast import toast diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 3746d72..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__pycache__/androidtoast.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__pycache__/androidtoast.cpython-311.pyc deleted file mode 100644 index 33b41e5..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/androidtoast/__pycache__/androidtoast.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__init__.py deleted file mode 100644 index 0d9c204..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -__all__ = ("toast",) - -from .kivytoast import toast diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 7d53d1f..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-311.pyc deleted file mode 100644 index 97d0b7f..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/kivytoast.py b/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/kivytoast.py deleted file mode 100644 index c190666..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/toast/kivytoast/kivytoast.py +++ /dev/null @@ -1,154 +0,0 @@ -""" -KivyToast -========= - -.. rubric:: Implementation of toasts for desktop. - -.. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - from kivymd.toast import toast - - KV = ''' - MDScreen: - - MDTopAppBar: - title: 'Test Toast' - pos_hint: {'top': 1} - left_action_items: [['menu', lambda x: x]] - - MDRaisedButton: - text: 'TEST KIVY TOAST' - pos_hint: {'center_x': .5, 'center_y': .5} - on_release: app.show_toast() - ''' - - - class Test(MDApp): - def show_toast(self): - '''Displays a toast on the screen.''' - - toast('Test Kivy Toast') - - def build(self): - return Builder.load_string(KV) - - Test().run() -""" - -from typing import List - -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ListProperty, NumericProperty -from kivy.uix.label import Label - -from kivymd.uix.dialog import BaseDialog - -Builder.load_string( - """ -: - size_hint: (None, None) - pos_hint: {"center_x": 0.5, "center_y": 0.1} - opacity: 0 - auto_dismiss: True - overlay_color: [0, 0, 0, 0] - canvas: - Color: - rgba: root._md_bg_color - RoundedRectangle: - pos: self.pos - size: self.size - radius: root.radius -""" -) - - -class Toast(BaseDialog): - duration = NumericProperty(2.5) - """ - The amount of time (in seconds) that the toast is visible on the screen. - - :attr:`duration` is an :class:`~kivy.properties.NumericProperty` - and defaults to `2.5`. - """ - - _md_bg_color = ListProperty() - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.label_toast = Label(size_hint=(None, None), markup=True, opacity=0) - self.label_toast.bind(texture_size=self.label_check_texture_size) - self.add_widget(self.label_toast) - - def label_check_texture_size( - self, instance_label: Label, texture_size: List[int] - ) -> None: - """ - Resizes the text if the text texture is larger than the screen size. - Sets the size of the toast according to the texture size of the toast - text. - """ - - texture_width, texture_height = texture_size - if texture_width > Window.width: - instance_label.text_size = (Window.width - dp(10), None) - instance_label.texture_update() - texture_width, texture_height = instance_label.texture_size - self.size = (texture_width + 25, texture_height + 25) - - def toast(self, text_toast: str) -> None: - """Displays a toast.""" - - self.label_toast.text = text_toast - self.open() - - def on_open(self) -> None: - """Default open event handler.""" - - self.fade_in() - Clock.schedule_once(self.fade_out, self.duration) - - def fade_in(self) -> None: - """Animation of opening toast on the screen.""" - - anim = Animation(opacity=1, duration=0.4) - anim.start(self.label_toast) - anim.start(self) - - def fade_out(self, *args) -> None: - """Animation of hiding toast on the screen.""" - - anim = Animation(opacity=0, duration=0.4) - anim.bind(on_complete=lambda *x: self.dismiss()) - anim.start(self.label_toast) - anim.start(self) - - def on_touch_down(self, touch): - if not self.collide_point(*touch.pos): - if self.auto_dismiss: - self.fade_out() - return False - super().on_touch_down(touch) - return True - - -def toast( - text: str = "", background: list = None, duration: float = 2.5 -) -> None: - """ - Displays a toast. - - :param text: text to be displayed in the toast; - :param duration: the amount of time (in seconds) that the toast is visible on the screen - :param background: toast background color in ``rgba`` format; - """ - - if background is None: - background = [0.2, 0.2, 0.2, 1] - Toast(duration=duration, _md_bg_color=background).toast(text) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/__init__.cpython-311.pyc index 8f6f999..307f084 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/argument_parser.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/argument_parser.cpython-311.pyc index 2fe6860..0e41f32 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/argument_parser.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/__pycache__/argument_parser.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc index 2c962a9..23d20be 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc index c812754..e1e64e4 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/hotreload/__pycache__/app.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc index b81432f..39f4a0a 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc index a107ec2..5d050c5 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc index 883723b..b39ac46 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/packaging/pyinstaller/__pycache__/hook-kivymd.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc index c4dcc33..44e1050 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc index f99442c..326044c 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_firebase.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc index 13cc4ce..50394df 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/Model/__pycache__/database_restdb.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc index f691a8d..0868e5e 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc index a81ee14..1e26d31 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc index d406224..acebfd9 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/MVC/libs/__pycache__/translation.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc index b862aa9..8a15b8f 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc index 1201988..3baff4a 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/add_view.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc index bc1de40..4abba75 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/tools/patterns/__pycache__/create_project.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__init__.py index 9aec2dc..bb70663 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__init__.py @@ -5,10 +5,8 @@ from kivy.uix.floatlayout import FloatLayout from kivy.uix.label import Label from kivy.uix.screenmanager import Screen -from kivymd.uix.behaviors import SpecificBackgroundColorBehavior - -class MDAdaptiveWidget(SpecificBackgroundColorBehavior): +class MDAdaptiveWidget: adaptive_height = BooleanProperty(False) """ If `True`, the following properties will be applied to the widget: diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/__init__.cpython-311.pyc index 1b629c9..f47480e 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc index 508b84d..5703abe 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/anchorlayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/boxlayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/boxlayout.cpython-311.pyc index f686ee0..ecae611 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/boxlayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/boxlayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/carousel.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/carousel.cpython-311.pyc deleted file mode 100644 index 470d066..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/carousel.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/circularlayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/circularlayout.cpython-311.pyc index 10f3c90..8a36d48 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/circularlayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/circularlayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/floatlayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/floatlayout.cpython-311.pyc index d596daf..4ca7bf7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/floatlayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/floatlayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/gridlayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/gridlayout.cpython-311.pyc index c8bb1e8..8a2a2f7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/gridlayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/gridlayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/hero.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/hero.cpython-311.pyc index 8655652..40f45bb 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/hero.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/hero.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc index 5ee01ef..eb0b9c9 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recyclegridlayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recycleview.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recycleview.cpython-311.pyc index df20625..d1c8389 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recycleview.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/recycleview.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/relativelayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/relativelayout.cpython-311.pyc index 086d1b4..3919a38 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/relativelayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/relativelayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc index 2abf31d..a35d893 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/responsivelayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screen.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screen.cpython-311.pyc index 3240ec3..48cbb12 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screen.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screen.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screenmanager.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screenmanager.cpython-311.pyc index aa8f94f..4eff232 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screenmanager.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/screenmanager.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/scrollview.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/scrollview.cpython-311.pyc index 474845f..a3fb0c7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/scrollview.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/scrollview.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/stacklayout.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/stacklayout.cpython-311.pyc index f534fc7..b5bc060 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/stacklayout.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/stacklayout.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/taptargetview.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/taptargetview.cpython-311.pyc deleted file mode 100644 index 43c945f..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/taptargetview.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/widget.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/widget.cpython-311.pyc index 0573ed8..4f92d4a 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/widget.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/__pycache__/widget.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/anchorlayout.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/anchorlayout.py index fe43542..381dc3a 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/anchorlayout.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/anchorlayout.py @@ -15,7 +15,7 @@ AnchorLayout AnchorLayout: canvas: Color: - rgba: app.theme_cls.primary_color + rgba: app.theme_cls.primaryColor Rectangle: pos: self.pos size: self.size @@ -26,7 +26,7 @@ MDAnchorLayout .. code-block:: kv MDAnchorLayout: - md_bg_color: app.theme_cls.primary_color + md_bg_color: app.theme_cls.primaryColor """ __all__ = ("MDAnchorLayout",) @@ -35,13 +35,24 @@ from kivy.uix.anchorlayout import AnchorLayout from kivymd.theming import ThemableBehavior from kivymd.uix import MDAdaptiveWidget -from kivymd.uix.behaviors import DeclarativeBehavior +from kivymd.uix.behaviors import DeclarativeBehavior, BackgroundColorBehavior class MDAnchorLayout( - DeclarativeBehavior, ThemableBehavior, AnchorLayout, MDAdaptiveWidget + DeclarativeBehavior, + ThemableBehavior, + BackgroundColorBehavior, + AnchorLayout, + MDAdaptiveWidget, ): """ - Anchor layout class. For more information, see in the - :class:`~kivy.uix.anchorlayout.AnchorLayout` class documentation. + Anchor layout class. + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivy.uix.anchorlayout.AnchorLayout` and + :class:`~kivymd.uix.MDAdaptiveWidget` + classes documentation. """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__init__.py new file mode 100644 index 0000000..b848375 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__init__.py @@ -0,0 +1,11 @@ +# NOQA F401 +from .appbar import ( + MDTopAppBar, + MDTopAppBarTitle, + MDBottomAppBar, + MDActionTopAppBarButton, + MDActionBottomAppBarButton, + MDFabBottomAppBarButton, + MDTopAppBarLeadingButtonContainer, + MDTopAppBarTrailingButtonContainer, +) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..eb32916 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__pycache__/appbar.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__pycache__/appbar.cpython-311.pyc new file mode 100644 index 0000000..e029a5d Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/__pycache__/appbar.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/appbar.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/appbar.kv new file mode 100644 index 0000000..fdd54de --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/appbar.kv @@ -0,0 +1,110 @@ + + size_hint_x: None + width: self.minimum_width + padding: "8dp", 0, "16dp", 0 + + + + size_hint_x: None + width: self.minimum_width + padding: "16dp", 0, "16dp", 0 + spacing: "4dp" + + + + pos_hint: {"center_y": .5} + color: + self.theme_cls.onSurfaceVariantColor \ + if self.theme_icon_color == "Primary" else \ + self.icon_color + + + + padding: + [ + self._appbar._left_padding if self._appbar else 0, + 0, + self._appbar._right_padding if self._appbar else 0, + 0, + ] + font_style: + { \ + "small": "Title", \ + "medium": "Headline", \ + "large": "Headline", \ + }[self._appbar.type if self._appbar else "small"] + role: + { \ + "small": "large", \ + "medium": "small", \ + "large": "medium", \ + }[self._appbar.type if self._appbar else "large"] + adaptive_width: + ( \ + True \ + if self._appbar.type == "small" else \ + False \ + ) \ + if self._appbar else True + size_hint_x: + ( \ + None \ + if self._appbar.type == "small" else \ + 1 \ + ) \ + if self._appbar else None + + + + canvas: + Color: + group: "md-top-app-bar-color" + rgba: + self.theme_cls.surfaceColor \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color + Rectangle: + pos: self.pos + size: self.size + + orientation: + "vertical" \ + if self.type in ("medium", "large") else \ + "horizontal" + size_hint_y: None + height: + { \ + "small": "64dp", \ + "medium": "112dp", \ + "large": "152dp", \ + }[self.type] + + BoxLayout: + id: root_box + + BoxLayout: + id: title_box + padding: "16dp", 0, "16dp", 0 + + + + elevation_level: 0 + theme_shadow_color: "Custom" + shadow_color: self.theme_cls.transparentColor + + + + size_hint_y: None + height: "80dp" + elevation_level: + 2 \ + if self.theme_elevation_level == "Primary" else \ + self.elevation_level + shadow_softness: + 2 \ + if self.theme_shadow_softness == "Primary" else \ + self.shadow_softness + md_bg_color: + self.theme_cls.surfaceContainerColor \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/appbar.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/appbar.py new file mode 100644 index 0000000..65a71a0 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/appbar/appbar.py @@ -0,0 +1,1272 @@ +""" +Components/Appbar +================= + +.. seealso:: + + `Material Design spec, App bars: top `_ + + `Material Design spec, App bars: bottom `_ + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/app-bar-top.png + :align: center + +`KivyMD` provides the following bar positions for use: + +- TopAppBar_ +- BottomAppBar_ + +.. TopAppBar_: + +TopAppBar +--------- + +- Contains a title and actions related to the current screen +- Four types: center-aligned, small, medium, and large +- On scroll, apply a container fill color to separate app bar from body content +- Top app bars have the same width as the device window + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/top-appbar-available-types.png + :align: center + +1. Center-aligned +2. Small +3. Medium +4. Large + +.. note:: KivyMD does not provide a `Center-aligned` type panel. But you can + easily create this pit panel yourself (read the documentation below). + +Usage +----- + +.. code-block:: kv + + MDTopAppBar: + type: "small" + + MDTopAppBarLeadingButtonContainer: + + MDActionTopAppBarButton: + icon: "menu" + + MDTopAppBarTitle: + text: "AppBar Center-aligned" + pos_hint: {"center_x": .5} + + MDTopAppBarTrailingButtonContainer: + + MDActionTopAppBarButton: + icon: "account-circle-outline" + +Anatomy +------- + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/top-appbar-anatomy.png + :align: center + +Configurations +============== + +1. Center-aligned +----------------- + +.. code-block:: kv + + MDScreen: + md_bg_color: self.theme_cls.secondaryContainerColor + + MDTopAppBar: + type: "small" + size_hint_x: .8 + pos_hint: {"center_x": .5, "center_y": .5} + + MDTopAppBarLeadingButtonContainer: + + MDActionTopAppBarButton: + icon: "menu" + + MDTopAppBarTitle: + text: "AppBar small" + pos_hint: {"center_x": .5} + + MDTopAppBarTrailingButtonContainer: + + MDActionTopAppBarButton: + icon: "account-circle-outline" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/top-appbar-center-aligned.png + :align: center + +2. Small +-------- + +.. code-block:: kv + + MDScreen: + md_bg_color: self.theme_cls.secondaryContainerColor + + MDTopAppBar: + type: "small" + size_hint_x: .8 + pos_hint: {"center_x": .5, "center_y": .5} + + MDTopAppBarLeadingButtonContainer: + + MDActionTopAppBarButton: + icon: "arrow-left" + + MDTopAppBarTitle: + text: "AppBar small" + + MDTopAppBarTrailingButtonContainer: + + MDActionTopAppBarButton: + icon: "attachment" + + MDActionTopAppBarButton: + icon: "calendar" + + MDActionTopAppBarButton: + icon: "dots-vertical" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/top-appbar-small.png + :align: center + +3. Medium +--------- + +.. code-block:: kv + + MDTopAppBar: + type: "medium" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/top-appbar-medium.png + :align: center + +4. Large +-------- + +.. code-block:: kv + + MDTopAppBar: + type: "large" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/top-appbar-large.png + :align: center + +.. BottomAppBar: + +BottomAppBar +------------ + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/app-bar-bottom-m3.png + :align: center + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + + KV = ''' + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDBottomAppBar: + + MDFabBottomAppBarButton: + icon: "plus" + ''' + + + class Example(MDApp): + def build(self): + self.theme_cls.theme_style = "Dark" + return Builder.load_string(KV) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-app-bar-m3-style-1.png + :align: center + +Add action items +---------------- + +.. code-block:: kv + + #:import MDActionBottomAppBarButton kivymd.uix.appbar.MDActionBottomAppBarButton + + + MDScreen: + + MDBottomAppBar: + action_items: + [ + MDActionBottomAppBarButton(icon="gmail"), + MDActionBottomAppBarButton(icon="label-outline"), + MDActionBottomAppBarButton(icon="bookmark"), + ] + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-app-bar-m3-style-2.png + :align: center + +Change action items +------------------- + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + from kivymd.uix.appbar import MDActionBottomAppBarButton + + KV = ''' + #:import MDActionBottomAppBarButton kivymd.uix.appbar.MDActionBottomAppBarButton + + + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDBottomAppBar: + id: bottom_appbar + action_items: + [ + MDActionBottomAppBarButton(icon="gmail"), + MDActionBottomAppBarButton(icon="bookmark"), + ] + + MDFabBottomAppBarButton: + icon: "plus" + on_release: app.change_actions_items() + ''' + + + class Example(MDApp): + def change_actions_items(self): + self.root.ids.bottom_appbar.action_items = [ + MDActionBottomAppBarButton(icon="magnify"), + MDActionBottomAppBarButton(icon="trash-can-outline"), + MDActionBottomAppBarButton(icon="download-box-outline"), + ] + + def build(self): + self.theme_cls.theme_style = "Dark" + return Builder.load_string(KV) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-app-bar-m3-style-3.gif + :align: center + +A practical example +------------------- + +.. code-block:: python + + import asynckivy + + from kivy.clock import Clock + from kivy.lang import Builder + from kivy.properties import StringProperty, BooleanProperty, ObjectProperty + from kivy.uix.behaviors import FocusBehavior + from kivy.uix.recycleboxlayout import RecycleBoxLayout + from kivy.uix.recycleview.layout import LayoutSelectionBehavior + from kivy.uix.recycleview.views import RecycleDataViewBehavior + + from kivymd.uix.appbar import MDActionBottomAppBarButton + from kivymd.uix.boxlayout import MDBoxLayout + from kivymd.app import MDApp + + from faker import Faker # pip install Faker + + KV = ''' + #:import MDFabBottomAppBarButton kivymd.uix.appbar.MDFabBottomAppBarButton + + + + orientation: "vertical" + adaptive_height: True + md_bg_color: "#373A22" if self.selected else "#1F1E15" + radius: 16 + padding: 0, 0, 0, "16dp" + + MDListItem: + theme_bg_color: "Custom" + md_bg_color: root.md_bg_color + radius: root.radius + ripple_effect: False + + MDListItemLeadingAvatar: + source: root.avatar + # radius: self.height / 2 + + MDListItemHeadlineText: + text: root.name + theme_text_color: "Custom" + text_color: "#8A8D79" + + MDListItemSupportingText: + text: root.time + theme_text_color: "Custom" + text_color: "#8A8D79" + + MDLabel: + text: root.text + adaptive_height: True + theme_text_color: "Custom" + text_color: "#8A8D79" + padding_x: "16dp" + shorten: True + shorten_from: "right" + + Widget: + + + MDFloatLayout: + md_bg_color: "#151511" + + RecycleView: + id: card_list + viewclass: "UserCard" + + SelectableRecycleGridLayout: + orientation: 'vertical' + spacing: "16dp" + padding: "16dp" + default_size: None, dp(120) + default_size_hint: 1, None + size_hint_y: None + height: self.minimum_height + multiselect: True + touch_multiselect: True + + MDBottomAppBar: + id: bottom_appbar + scroll_cls: card_list + allow_hidden: True + theme_bg_color: "Custom" + md_bg_color: "#232217" + + MDFabBottomAppBarButton: + id: fab_button + icon: "plus" + theme_bg_color: "Custom" + md_bg_color: "#373A22" + theme_icon_color: "Custom" + icon_color: "#ffffff" + ''' + + + class UserCard(RecycleDataViewBehavior, MDBoxLayout): + name = StringProperty() + time = StringProperty() + text = StringProperty() + avatar = StringProperty() + callback = ObjectProperty(lambda x: x) + + index = None + selected = BooleanProperty(False) + selectable = BooleanProperty(True) + + def refresh_view_attrs(self, rv, index, data): + self.index = index + return super().refresh_view_attrs(rv, index, data) + + def on_touch_down(self, touch): + if super().on_touch_down(touch): + return True + if self.collide_point(*touch.pos) and self.selectable: + Clock.schedule_once(self.callback) + return self.parent.select_with_touch(self.index, touch) + + def apply_selection(self, rv, index, is_selected): + self.selected = is_selected + rv.data[index]["selected"] = is_selected + + + class SelectableRecycleGridLayout( + FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout + ): + pass + + + class BottomAppBarButton(MDActionBottomAppBarButton): + theme_icon_color = "Custom" + icon_color = "#8A8D79" + + + class Example(MDApp): + selected_cards = False + + def build(self): + return Builder.load_string(KV) + + def on_tap_card(self, *args): + datas = [data["selected"] for data in self.root.ids.card_list.data] + if True in datas and not self.selected_cards: + self.root.ids.bottom_appbar.action_items = [ + BottomAppBarButton(icon="gmail"), + BottomAppBarButton(icon="label-outline"), + BottomAppBarButton(icon="bookmark"), + ] + self.root.ids.fab_button.icon = "pencil" + self.selected_cards = True + else: + if len(list(set(datas))) == 1 and not list(set(datas))[0]: + self.selected_cards = False + if not self.selected_cards: + self.root.ids.bottom_appbar.action_items = [ + BottomAppBarButton(icon="magnify"), + BottomAppBarButton(icon="trash-can-outline"), + BottomAppBarButton(icon="download-box-outline"), + ] + self.root.ids.fab_button.icon = "plus" + + def on_start(self): + async def generate_card(): + for i in range(10): + await asynckivy.sleep(0) + self.root.ids.card_list.data.append( + { + "name": fake.name(), + "time": fake.date(), + "avatar": fake.image_url(), + "text": fake.text(), + "selected": False, + "callback": self.on_tap_card, + } + ) + + self.on_tap_card() + fake = Faker() + Clock.schedule_once(lambda x: asynckivy.start(generate_card())) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-app-bar-m3-style-4.gif + :align: center + +API break +========= + +1.2.0 version +------------- + +.. code-block:: kv + + MDTopAppBar: + type_height: "large" + headline_text: "Headline" + left_action_items: [["arrow-left", lambda x: x]] + right_action_items: + [ \ + ["attachment", lambda x: x], \ + ["calendar", lambda x: x], \ + ["dots-vertical", lambda x: x], \ + ] + anchor_title: "left" + +2.0.0 version +------------- + +.. code-block:: kv + + MDTopAppBar: + type: "large" + + MDTopAppBarLeadingButtonContainer: + + MDActionTopAppBarButton: + icon: "arrow-left" + + MDTopAppBarTitle: + text: "AppBar small" + + MDTopAppBarTrailingButtonContainer: + + MDActionTopAppBarButton: + icon: "attachment" + + MDActionTopAppBarButton: + icon: "calendar" + + MDActionTopAppBarButton: + icon: "dots-vertical" +""" + +from __future__ import annotations + +__all__ = ( + "MDTopAppBar", + "MDTopAppBarTitle", + "MDBottomAppBar", + "MDActionTopAppBarButton", + "MDActionBottomAppBarButton", + "MDFabBottomAppBarButton", + "MDTopAppBarLeadingButtonContainer", + "MDTopAppBarTrailingButtonContainer", +) + +import os + +from kivy import Logger +from kivy.animation import Animation +from kivy.clock import Clock +from kivy.core.window import Window +from kivy.lang import Builder +from kivy.metrics import dp +from kivy.properties import ( + BooleanProperty, + ListProperty, + NumericProperty, + ObjectProperty, + OptionProperty, + StringProperty, + ColorProperty, +) +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.floatlayout import FloatLayout +from kivy.uix.scrollview import ScrollView +from kivy.uix.widget import Widget + +from kivymd import uix_path +from kivymd.theming import ThemableBehavior +from kivymd.uix.behaviors import ( + CommonElevationBehavior, + DeclarativeBehavior, + RotateBehavior, + ScaleBehavior, + BackgroundColorBehavior, +) +from kivymd.uix.button import MDFabButton, MDIconButton +from kivymd.uix.controllers import WindowController +from kivymd.uix.label import MDLabel +from kivymd.utils.set_bars_colors import set_bars_colors + +import asynckivy + +with open( + os.path.join(uix_path, "appbar", "appbar.kv"), encoding="utf-8" +) as kv_file: + Builder.load_string(kv_file.read()) + + +class BaseTopAppBarButtonContainer(DeclarativeBehavior, BoxLayout): + # kivymd.uix.appbar.appbar.MDTopAppBar object. + _appbar = ObjectProperty() + + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDActionTopAppBarButton): + Clock.schedule_once(lambda x: self._check_icon_color(widget)) + + return super().add_widget(widget) + + def _check_icon_color(self, widget): + if widget.theme_icon_color == "Primary" and widget.icon_color == None: + widget.theme_icon_color = "Custom" + widget.icon_color = widget.theme_cls.onSurfaceColor + + +class MDFabBottomAppBarButton(MDFabButton, RotateBehavior, ScaleBehavior): + """ + Implements a floating action button (FAB) for a bar with type 'bottom'. + + For more information, see in the + :class:`~kivymd.uix.button.button.MDFabButton` and + :class:`~kivymd.uix.behaviors.rotate_behavior.RotateBehavior` and + :class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and + classes documentation. + """ + + +class MDActionTopAppBarButton(MDIconButton): + """ + Implements action buttons on the bar. + + For more information, see in the + :class:`~kivymd.uix.button.button.MDIconButton` class documentation. + """ + + md_bg_color_disabled = ColorProperty(None) + """ + The background color in (r, g, b, a) or string format of the button when + the button is disabled. + + :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + +class MDActionBottomAppBarButton(MDActionTopAppBarButton): + """ + Implements action buttons for a + :class:'~kivymd.uix.appbar.appbar.MDBottomAppBar' class. + + .. versionadded:: 1.2.0 + + For more information, see in the + :class:`~kivymd.uix.appbar.appbar.MDActionTopAppBarButton` + class documentation. + """ + + +class MDTopAppBarTitle(MDLabel): + """ + Implements the panel title. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + """ + + _appbar = ObjectProperty() + _title_width = NumericProperty(0) + + # FIXME: When changing the text, the texture_size property returns an + # incorrect value, which causes the panel title to shift. + def on_text(self, instance, value) -> None: + """Fired when the :attr:`text` value changes.""" + + def set_title_width(*args) -> None: + self._title_width = self.texture_size[0] + + Clock.schedule_once(set_title_width) + + def on_pos_hint(self, instance, value) -> None: + """Fired when the :attr:`pos_hint` value changes.""" + + if self._appbar: + Clock.schedule_once( + lambda x: self._appbar._set_padding_title(value) + ) + + +class MDTopAppBarLeadingButtonContainer(BaseTopAppBarButtonContainer): + """ + Implements a container for the leading action buttons. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. + """ + + +class MDTopAppBarTrailingButtonContainer(BaseTopAppBarButtonContainer): + """ + Implements a container for the trailing action buttons. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. + """ + + +# FIXME: The on_enter/on_leave event is not triggered for +# MDActionTopAppBarButton buttons in the MDTopAppBarTrailingButtonContainer +# container. +# When the screen size is changed on desktop devices, the position of the +# trailing container is shifted until the screen size change is completed. +class MDTopAppBar( + DeclarativeBehavior, + ThemableBehavior, + CommonElevationBehavior, + BackgroundColorBehavior, + BoxLayout, + WindowController, +): + """ + Top app bar class. + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` and + :class:`~kivymd.uix.controllers.windowcontroller.WindowController` + classes documentation. + + :Events: + `on_action_button` + Method for the button used for the :class:`~MDBottomAppBar` class. + """ + + set_bars_color = BooleanProperty(False) + """ + If `True` the background color of the bar status will be set automatically + according to the current color of the bar. + + .. versionadded:: 1.0.0 + + See `set_bars_colors `_ + for more information. + + :attr:`set_bars_color` is an :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + type = OptionProperty("small", options=["medium", "large", "small"]) + """ + Bar height type. + + .. versionadded:: 1.0.0 + + Available options are: 'medium', 'large', 'small'. + + :attr:`type_height` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'small'`. + """ + + _trailing_button_container = ObjectProperty() + _leading_button_container = ObjectProperty() + _appbar_title = ObjectProperty() + _right_padding = NumericProperty(0) + _left_padding = NumericProperty(0) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + Clock.schedule_once(lambda x: self.on_size(self, (0, 0))) + + def on_type(self, instance, value) -> None: + def on_type(*args): + if value in ("medium", "large"): + self.ids.root_box.add_widget(Widget(), index=1) + + Clock.schedule_once(on_type, 0.5) + + def on_size(self, instance, size) -> None: + """Fired when the application screen size changes.""" + + if self._appbar_title: + if not self._appbar_title._title_width: + self._appbar_title._title_width = ( + self._appbar_title.texture_size[0] + ) + self._right_padding = 0 + self._left_padding = 0 + self._appbar_title.on_pos_hint( + self._appbar_title, self._appbar_title.pos_hint + ) + + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDTopAppBarTitle): + widget._appbar = self + self._appbar_title = widget + widget.bind(text=lambda *x: self.on_size(*x)) + Clock.schedule_once(lambda x: self._add_title(widget)) + elif isinstance(widget, MDTopAppBarTrailingButtonContainer): + self._trailing_button_container = widget + widget._appbar = self + Clock.schedule_once(lambda x: self.ids.root_box.add_widget(widget)) + elif isinstance(widget, MDTopAppBarLeadingButtonContainer): + widget._appbar = self + self._leading_button_container = widget + Clock.schedule_once(lambda x: self.ids.root_box.add_widget(widget)) + else: + return super().add_widget(widget) + + def _add_title(self, widget): + if self.type == "small": + self.ids.root_box.add_widget(widget) + else: + self.ids.title_box.add_widget(widget) + + def _set_padding_title(self, value): + if value.get("center_x", 0) == 0.5 and self.type == "small": + if ( + not self._trailing_button_container + and self._leading_button_container + ): + self._left_padding = ( + (self.width // 2) + - ( + self._leading_button_container.width + + (self._appbar_title._title_width // 2) + ) + ) - self._left_padding + elif ( + self._trailing_button_container + and not self._leading_button_container + ): + self._left_padding = ( + (self.width // 2) - (self._appbar_title._title_width // 2) + ) - self._left_padding + self._right_padding = ( + (self.width // 2) + - ( + self._trailing_button_container.width + + (self._appbar_title._title_width // 2) + ) + ) - self._right_padding + elif ( + not self._trailing_button_container + and not self._leading_button_container + ): + self._left_padding = ( + (self.width // 2) - (self._appbar_title._title_width // 2) + ) - self._left_padding + self._right_padding = ( + (self.width // 2) - (self._appbar_title._title_width // 2) + ) - self._right_padding + elif ( + self._trailing_button_container + and self._leading_button_container + ): + self._left_padding = ( + (self.width // 2) + - ( + self._leading_button_container.width + + (self._appbar_title._title_width // 2) + ) + ) - self._left_padding + self._right_padding = ( + (self.width // 2) + - ( + self._trailing_button_container.width + + (self._appbar_title._title_width // 2) + ) + ) - self._right_padding + elif ( + not value + and self._trailing_button_container + and self._leading_button_container + ): + if self.type == "small": + + self._right_padding = ( + self.width + - ( + self._trailing_button_container.width + + self._leading_button_container.width + + self._appbar_title._title_width + ) + - self._right_padding + ) + elif ( + not value + and self._trailing_button_container + and not self._leading_button_container + ): + if self.type == "small": + self._right_padding = ( + self.width + - ( + self._trailing_button_container.width + + self._appbar_title._title_width + ) + - self._right_padding + ) + self._left_padding = dp(16) + elif ( + not value + and not self._trailing_button_container + and not self._leading_button_container + ): + self._left_padding = dp(16) + + +class MDBottomAppBar( + DeclarativeBehavior, + ThemableBehavior, + BackgroundColorBehavior, + CommonElevationBehavior, + FloatLayout, +): + """ + Bottom app bar class. + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivy.uix.floatlayout.FloatLayout` + classes documentation. + + :Events: + `on_show_bar` + The method is fired when the :class:`~MDBottomAppBar` panel + is shown. + `on_hide_bar` + The method is fired when the :class:`~MDBottomAppBar` panel + is hidden. + """ + + action_items = ListProperty() + """ + The icons on the left bar. + + .. versionadded:: 1.2.0 + + :attr:`action_items` is an :class:`~kivy.properties.ListProperty` + and defaults to `[]`. + """ + + animation = BooleanProperty(True) + """ + # TODO: add description. + # FIXME: changing the value does not affect anything. + + .. versionadded:: 1.2.0 + + :attr:`animation` is an :class:`~kivy.properties.BooleanProperty` + and defaults to `True`. + """ + + show_transition = StringProperty("linear") + """ + Type of button display transition. + + .. versionadded:: 1.2.0 + + :attr:`show_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'linear'`. + """ + + hide_transition = StringProperty("in_back") + """ + Type of button hidden transition. + + .. versionadded:: 1.2.0 + + :attr:`hide_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'in_back'`. + """ + + hide_duration = NumericProperty(0.4) + """ + Duration of button hidden transition. + + .. versionadded:: 1.2.0 + + :attr:`hide_duration` is a :class:`~kivy.properties.NumericProperty` + and defaults to `0.2`. + """ + + show_duration = NumericProperty(0.2) + """ + Duration of button display transition. + + .. versionadded:: 1.2.0 + + :attr:`show_duration` is a :class:`~kivy.properties.NumericProperty` + and defaults to `0.2`. + """ + + scroll_cls = ObjectProperty() + """ + Widget inherited from the :class:`~kivy.uix.scrollview.ScrollView` class. + The value must be set if the :attr:`allow_hidden` parameter is `True`. + + .. versionadded:: 1.2.0 + + :attr:`scroll_cls` is a :class:`~kivy.properties.ObjectProperty` + and defaults to `None`. + """ + + allow_hidden = BooleanProperty(False) + """ + Allows or disables hiding the panel when scrolling content. + If the value is `True`, the :attr:`scroll_cls` parameter must be specified. + + .. versionadded:: 1.2.0 + + :attr:`allow_hidden` is a :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + bar_is_hidden = BooleanProperty(False) + """ + Is the panel currently hidden. + + .. versionadded:: 1.2.0 + + :attr:`bar_is_hidden` is a :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + _padding = dp(16) + _x = -dp(48) + _scroll_cls_y = 0 + _cache = [] + _current_data = [] + _wait_removed = False + _animated_hidden = True + _animated_show = True + _fab_bottom_app_bar_button = None + _action_overflow_button = None + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.register_event_type("on_show_bar") + self.register_event_type("on_hide_bar") + + def button_centering_animation( + self, + button: MDActionBottomAppBarButton | MDFabBottomAppBarButton, + ) -> None: + """ + Animation of centering buttons for + :class:`~MDActionOverFlowButton`, + :class:`~MDActionBottomAppBarButton` and + :class:`~MDFabBottomAppBarButton` classes. + """ + + if self.animation: + Animation( + y=self.height / 2 - dp(48) / 2, + opacity=1, + d=self.show_duration, + t=self.show_transition, + ).start(button) + + def check_scroll_direction(self, scroll_cls, y: float) -> None: + """ + Checks the scrolling direction. + Depending on the scrolling direction, hides or shows the + :class:`~MDBottomAppBar` panel. + """ + + if round(y, 1) < self._scroll_cls_y and not self.bar_is_hidden: + self.hide_bar() + if round(y, 1) > self._scroll_cls_y and self.bar_is_hidden: + self.show_bar() + + self._scroll_cls_y = round(y, 1) + + def show_bar(self) -> None: + """Show :class:`~MDBottomAppBar` panel.""" + + def on_complete(*args): + self.dispatch("on_show_bar") + + def on_progress(animation, instance, progress): + if progress > 0.5 and self._animated_show: + self._animated_show = False + for i, widget in enumerate(self.children): + if isinstance(widget, MDActionBottomAppBarButton): + anim_icon = Animation( + y=self.height / 2 - dp(48) / 2, + d=self.show_duration, + t=self.show_transition, + ) + Clock.schedule_once( + lambda x, y=widget: anim_icon.start(y), + i / 10, + ) + if self._fab_bottom_app_bar_button: + Animation( + y=self._fab_bottom_app_bar_button.y + dp(4), + d=self.show_duration, + t=self.show_transition, + ).start(self._fab_bottom_app_bar_button) + + self.bar_is_hidden = False + self._animated_show = True + anim = Animation( + y=0, + d=self.show_duration, + t=self.show_transition, + ) + anim.bind(on_progress=on_progress, on_complete=on_complete) + anim.start(self) + + def hide_bar(self) -> None: + """Hide :class:`~MDBottomAppBar` panel.""" + + def on_complete(*args): + self.dispatch("on_hide_bar") + + def on_progress(animation, instance, progress): + if ( + progress > 0.5 + and self._animated_hidden + and widget_icon == instance.icon + ): + self._animated_hidden = False + anim_bar = Animation( + y=-self.height, + d=self.hide_duration, + # t=self.hide_transition, + ) + anim_bar.bind(on_complete=on_complete) + anim_bar.start(self) + + if self._fab_bottom_app_bar_button: + Animation( + y=self._fab_bottom_app_bar_button.y - dp(4), + d=self.hide_duration, + t=self.hide_transition, + ).start(self._fab_bottom_app_bar_button) + + self.bar_is_hidden = True + self._animated_hidden = True + len_children = len(self.children) + widget_icon = "" + + for i, widget in enumerate(self.children): + if isinstance(widget, MDActionBottomAppBarButton): + anim = Animation( + y=-widget.height, + d=self.hide_duration, + t=self.hide_transition, + ) + if i + 2 == len_children: + widget_icon = widget.icon + anim.bind(on_progress=on_progress) + Clock.schedule_once( + lambda x, y=widget: anim.start(y), + i / 10, + ) + + def on_show_bar(self, *args) -> None: + """ + The method is fired when the :class:`~MDBottomAppBar` panel + is shown. + """ + + def on_hide_bar(self, *args) -> None: + """ + The method is fired when the :class:`~MDBottomAppBar` panel + is hidden. + """ + + def on_scroll_cls(self, instance, scroll_cls) -> None: + """ + Fired when the value of the :attr:`scroll_cls` attribute changes. + """ + + def on_scroll_cls(*args): + if not self.allow_hidden: + Logger.warning( + "KivyMD: " + "In order for the bottom bar to be automatically hidden " + "in addition to the `scroll_cls` parameter, set the value " + "of the `allow_hidden` parameter to `True`" + ) + + if issubclass(scroll_cls.__class__, ScrollView): + if self.allow_hidden: + scroll_cls.bind(scroll_y=self.check_scroll_direction) + else: + raise TypeError( + f"The `scroll_cls` parameter must be an object inherited " + f"from the {ScrollView} class" + ) + + Clock.schedule_once(on_scroll_cls) + + def on_size(self, *args) -> None: + """Fired when the root screen is resized.""" + + if self._fab_bottom_app_bar_button: + self._fab_bottom_app_bar_button.x = Window.width - (dp(56) + dp(16)) + + def on_action_items(self, instance, value: list) -> None: + """ + Fired when the value of the :attr:`action_items` attribute changes. + """ + + def wait_removed(*args): + if len(self.children) == 1 or not self.children: + Clock.unschedule(wait_removed) + self._wait_removed = False + self._x = -dp(48) + asynckivy.start(add_widget()) + + async def add_widget(): + for button in value: + await asynckivy.sleep(0) + self.add_widget(button) + + if self._cache: + self._cache.append(value) + + for data in self._cache: + if value[0] in data: + for i, widget in enumerate(self.children): + if not self._wait_removed: + Clock.schedule_interval(wait_removed, 0) + self._wait_removed = True + if isinstance(widget, MDActionBottomAppBarButton): + anim = Animation( + y=-widget.height, + d=self.hide_duration, + t=self.hide_transition, + ) + anim.bind( + on_complete=lambda x, y=widget: self.remove_widget( + y + ) + ) + Clock.schedule_once( + lambda x, y=widget: anim.start(y), + i / 10, + ) + else: + self._cache.append(value) + self._current_data = value + asynckivy.start(add_widget()) + + def set_fab_opacity(self, *ars) -> None: + """ + Sets the transparency value of the:class:`~MDFabBottomAppBarButton` + button. + """ + + # self._fab_bottom_app_bar_button.opacity = 1 + + def set_fab_icon(self, instance, value) -> None: + """ + Animates the size of the :class:`~MDFabBottomAppBarButton` button. + """ + + # self._fab_bottom_app_bar_button.opacity = 0 + anim = Animation( + scale_value_x=0, + scale_value_y=0, + opacity=0, + d=self.hide_duration, + t=self.hide_transition, + ) + Animation( + scale_value_x=1, + scale_value_y=1, + opacity=1, + d=self.show_duration, + t=self.show_transition, + ) + anim.bind(on_complete=self.set_fab_opacity) + anim.start(instance) + + def add_widget(self, widget, index=0, canvas=None): + if isinstance(widget, MDActionBottomAppBarButton): + self._x += widget.width + widget.pos = ( + self._x + self._padding, + -dp(48) if self.animation else self.height / 2 - dp(48) / 2, + ) + widget.opacity = int(not self.animation) + super().add_widget(widget) + self.button_centering_animation(widget) + elif isinstance(widget, MDFabBottomAppBarButton): + widget.bind(icon=self.set_fab_icon) + self._fab_bottom_app_bar_button = widget + Clock.schedule_once(self.set_fab_opacity) + widget.scale_value_x = int(not self.animation) + widget.scale_value_y = int(not self.animation) + widget.pos = ( + Window.width - (dp(56) + self._padding), + self.height / 2 - dp(56) / 2, + ) + super().add_widget(widget) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__init__.py deleted file mode 100644 index 7a5e6cf..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .backdrop import MDBackdrop # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 0370b7a..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__pycache__/backdrop.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__pycache__/backdrop.cpython-311.pyc deleted file mode 100644 index 727f12e..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/__pycache__/backdrop.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/backdrop.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/backdrop.kv deleted file mode 100644 index 2f56d5b..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/backdrop.kv +++ /dev/null @@ -1,50 +0,0 @@ - - md_bg_color: - root.theme_cls.primary_color \ - if not root.back_layer_color \ - else root.back_layer_color - - MDBackdropToolbar: - id: toolbar - type_height: "small" - anchor_title: root.anchor_title - title: root.title - elevation: 0 - left_action_items: root.left_action_items - right_action_items: root.right_action_items - pos_hint: {"top": 1} - md_bg_color: - root.theme_cls.primary_color \ - if not root.back_layer_color \ - else root.back_layer_color - - _BackLayer: - id: back_layer - y: -toolbar.height - padding: 0, 0, 0, toolbar.height + dp(10) - - _FrontLayer: - id: _front_layer - md_bg_color: 0, 0, 0, 0 - orientation: "vertical" - size_hint_y: None - height: root.height - toolbar.height - padding: root.padding - md_bg_color: - root.theme_cls.bg_normal \ - if not root.front_layer_color \ - else root.front_layer_color - radius: - [root.radius_left, root.radius_right, - 0, 0] - - OneLineListItem: - id: header_button - text: root.header_text - divider: None - _no_ripple_effect: True - on_press: root.open() - - MDBoxLayout: - id: front_layer - padding: 0, 0, 0, "10dp" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/backdrop.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/backdrop.py deleted file mode 100644 index 276eb1c..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/backdrop/backdrop.py +++ /dev/null @@ -1,548 +0,0 @@ -""" -Components/Backdrop -=================== - -.. seealso:: - - `Material Design spec, Backdrop `_ - -.. rubric:: Skeleton layout for using :class:`~MDBackdrop`: - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop.png - :align: center - -Usage ------ - -.. code-block:: kv - - - - MDBackdrop: - - MDBackdropBackLayer: - - ContentForBackdropBackLayer: - - MDBackdropFrontLayer: - - ContentForBackdropFrontLayer: - -Example -------- - -.. tabs:: - - .. tab:: Declarative KV styles - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.uix.screen import MDScreen - from kivymd.app import MDApp - - # Your layouts. - Builder.load_string( - ''' - #:import os os - #:import Window kivy.core.window.Window - #:import IconLeftWidget kivymd.uix.list.IconLeftWidget - #:import images_path kivymd.images_path - - - - icon: "android" - - IconLeftWidget: - icon: root.icon - - - - backdrop: None - text: "Lower the front layer" - secondary_text: " by 50 %" - icon: "transfer-down" - on_press: root.backdrop.open(-Window.height / 2) - pos_hint: {"top": 1} - _no_ripple_effect: True - - - - size_hint: .8, .8 - source: os.path.join(images_path, "logo", "kivymd-icon-512.png") - pos_hint: {"center_x": .5, "center_y": .6} - ''' - ) - - # Usage example of MDBackdrop. - Builder.load_string( - ''' - - - MDBackdrop: - id: backdrop - left_action_items: [['menu', lambda x: self.open()]] - title: "Example Backdrop" - radius_left: "25dp" - radius_right: "0dp" - header_text: "Menu:" - - MDBackdropBackLayer: - MyBackdropBackLayer: - id: backlayer - - MDBackdropFrontLayer: - MyBackdropFrontLayer: - backdrop: backdrop - ''' - ) - - - class ExampleBackdrop(MDScreen): - pass - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return ExampleBackdrop() - - - Example().run() - - .. tab:: Declarative python styles - - .. code-block:: python - - import os - - from kivy.core.window import Window - from kivy.uix.image import Image - - from kivymd import images_path - from kivymd.uix.backdrop import MDBackdrop - from kivymd.uix.backdrop.backdrop import ( - MDBackdropBackLayer, MDBackdropFrontLayer - ) - from kivymd.uix.list import TwoLineAvatarListItem, IconLeftWidget - from kivymd.uix.screen import MDScreen - from kivymd.app import MDApp - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - return ( - MDScreen( - MDBackdrop( - MDBackdropBackLayer( - Image( - size_hint=(0.8, 0.8), - source=os.path.join(images_path, "logo", "kivymd-icon-512.png"), - pos_hint={"center_x": 0.5, "center_y": 0.6}, - ) - ), - MDBackdropFrontLayer( - TwoLineAvatarListItem( - IconLeftWidget(icon="transfer-down"), - text="Lower the front layer", - secondary_text=" by 50 %", - on_press=self.backdrop_open_by_50_percent, - pos_hint={"top": 1}, - _no_ripple_effect=True, - ), - ), - id="backdrop", - title="Example Backdrop", - radius_left="25dp", - radius_right="0dp", - header_text="Menu:", - ) - ) - ) - - def backdrop_open_by_50_percent(self, *args): - self.root.ids.backdrop.open(-Window.height / 2) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop.gif - :align: center - -.. Note:: `See full example `_ -""" - -__all__ = ( - "MDBackdropToolbar", - "MDBackdropFrontLayer", - "MDBackdropBackLayer", - "MDBackdrop", -) - -import os -from typing import Union - -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.properties import ( - BooleanProperty, - ColorProperty, - ListProperty, - NumericProperty, - OptionProperty, - StringProperty, -) -from kivy.uix.boxlayout import BoxLayout - -from kivymd import uix_path -from kivymd.uix.boxlayout import MDBoxLayout -from kivymd.uix.card import MDCard -from kivymd.uix.floatlayout import MDFloatLayout -from kivymd.uix.toolbar.toolbar import ActionTopAppBarButton, MDTopAppBar - -with open( - os.path.join(uix_path, "backdrop", "backdrop.kv"), - encoding="utf-8", -) as kv_file: - Builder.load_string(kv_file.read()) - - -class MDBackdrop(MDFloatLayout): - """ - For more information, see in the - :class:`~kivymd.uix.floatlayout.MDFloatLayout` class documentation. - - :Events: - :attr:`on_open` - When the front layer drops. - :attr:`on_close` - When the front layer rises. - """ - - anchor_title = OptionProperty("left", options=["left", "center", "right"]) - """ - Position toolbar title. Only used with `material_style = 'M3'` - Available options are: `'left'`, `'center'`, `'right'`. - - .. versionadded:: 1.0.0 - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-anchor-title.png - :align: center - - :attr:`anchor_title` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'left'`. - """ - - padding = ListProperty([0, 0, 0, 0]) - """ - Padding for contents of the front layer. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-padding.png - :align: center - - :attr:`padding` is an :class:`~kivy.properties.ListProperty` - and defaults to `[0, 0, 0, 0]`. - """ - - left_action_items = ListProperty() - """ - The icons and methods left of the :class:`kivymd.uix.toolbar.MDTopAppBar` - in back layer. For more information, see the - :class:`kivymd.uix.toolbar.MDTopAppBar` module - and :attr:`left_action_items` parameter. - - :attr:`left_action_items` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - right_action_items = ListProperty() - """ - Works the same way as :attr:`left_action_items`. - - :attr:`right_action_items` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - title = StringProperty() - """ - See the :class:`kivymd.uix.toolbar.MDTopAppBar.title` parameter. - - :attr:`title` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - back_layer_color = ColorProperty(None) - """ - Background color of back layer in (r, g, b, a) or string format. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-back-layer-color.png - :align: center - - :attr:`back_layer_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - front_layer_color = ColorProperty(None) - """ - Background color of front layer in (r, g, b, a) or string format. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-front-layer-color.png - :align: center - - :attr:`front_layer_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - radius_left = NumericProperty("16dp") - """ - The value of the rounding radius of the upper left corner - of the front layer. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-radius-left.png - :align: center - - :attr:`radius_left` is an :class:`~kivy.properties.NumericProperty` - and defaults to `16dp`. - """ - - radius_right = NumericProperty("16dp") - """ - The value of the rounding radius of the upper right corner - of the front layer. - - :attr:`radius_right` is an :class:`~kivy.properties.NumericProperty` - and defaults to `16dp`. - """ - - header = BooleanProperty(True) - """ - Whether to use a header above the contents of the front layer. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-header.png - :align: center - - :attr:`header` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. - """ - - header_text = StringProperty("Header") - """ - Text of header. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-header-text.png - :align: center - - :attr:`header_text` is an :class:`~kivy.properties.StringProperty` - and defaults to `'Header'`. - """ - - close_icon = StringProperty("close") - """ - The name of the icon that will be installed on the toolbar - on the left when opening the front layer. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/backdrop-close-icon.png - :align: center - - :attr:`close_icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `'close'`. - """ - - opening_time = NumericProperty(0.2) - """ - The time taken for the panel to slide to the :attr:`state` `'open'`. - - .. versionadded:: 1.0.0 - - :attr:`opening_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - opening_transition = StringProperty("out_quad") - """ - The name of the animation transition type to use when animating to - the :attr:`state` `'open'`. - - .. versionadded:: 1.0.0 - - :attr:`opening_transition` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_quad'`. - """ - - closing_time = NumericProperty(0.2) - """ - The time taken for the panel to slide to the :attr:`state` `'close'`. - - .. versionadded:: 1.0.0 - - :attr:`closing_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - closing_transition = StringProperty("out_quad") - """ - The name of the animation transition type to use when animating to - the :attr:`state` 'close'. - - .. versionadded:: 1.0.0 - - :attr:`closing_transition` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_quad'`. - """ - - _open_icon = "" - _front_layer_open = False - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.register_event_type("on_open") - self.register_event_type("on_close") - Clock.schedule_once( - lambda x: self.on_left_action_items(self, self.left_action_items) - ) - - def on_open(self) -> None: - """When the front layer drops.""" - - def on_close(self) -> None: - """When the front layer rises.""" - - def on_left_action_items(self, instance_backdrop, menu: list) -> None: - if menu: - self.left_action_items = [menu[0]] - else: - self.left_action_items = [["menu", lambda x: self.open()]] - self._open_icon = self.left_action_items[0][0] - - def on_header(self, instance_backdrop, value: bool) -> None: - def on_header(*args): - if not value: - self.ids._front_layer.remove_widget(self.ids.header_button) - - Clock.schedule_once(on_header) - - def open(self, open_up_to: int = 0) -> None: - """ - Opens the front layer. - - :open_up_to: - the height to which the front screen will be lowered; - if equal to zero - falls to the bottom of the screen; - """ - - self.animate_opacity_icon() - if self._front_layer_open: - self.close() - return - - if open_up_to: - if open_up_to < ( - self.ids.header_button.height - self.ids._front_layer.height - ): - y = self.ids.header_button.height - self.ids._front_layer.height - elif open_up_to > 0: - y = 0 - else: - y = open_up_to - else: - y = self.ids.header_button.height - self.ids._front_layer.height - - Animation(y=y, d=self.opening_time, t=self.opening_transition).start( - self.ids._front_layer - ) - self._front_layer_open = True - self.dispatch("on_open") - - def close(self) -> None: - """Opens the front layer.""" - - Animation(y=0, d=self.closing_time, t=self.closing_transition).start( - self.ids._front_layer - ) - self._front_layer_open = False - self.dispatch("on_close") - - def animate_opacity_icon( - self, - instance_icon_menu: Union[ActionTopAppBarButton, None] = None, - opacity_value: int = 0, - call_set_new_icon: bool = True, - ) -> None: - """Starts the opacity animation of the icon.""" - - if not instance_icon_menu: - instance_icon_menu = self.ids.toolbar.ids.left_actions.children[0] - anim = Animation( - opacity=opacity_value, - d=self.opening_time, - t=self.opening_transition, - ) - if call_set_new_icon: - anim.bind(on_complete=self.set_new_icon) - anim.start(instance_icon_menu) - - def set_new_icon( - self, - instance_animation: Animation, - instance_icon_menu: ActionTopAppBarButton, - ) -> None: - """ - Sets the icon of the button depending on the state of the backdrop. - """ - - instance_icon_menu.icon = ( - self.close_icon - if instance_icon_menu.icon == self._open_icon - else self._open_icon - ) - self.animate_opacity_icon(instance_icon_menu, 1, False) - - def add_widget(self, widget, index=0, canvas=None): - if widget.__class__ in (MDBackdropToolbar, _BackLayer, _FrontLayer): - return super().add_widget(widget) - else: - if widget.__class__ is MDBackdropBackLayer: - self.ids.back_layer.add_widget(widget) - elif widget.__class__ is MDBackdropFrontLayer: - self.ids.front_layer.add_widget(widget) - - -class MDBackdropToolbar(MDTopAppBar): - """ - Implements a toolbar for back content. - - For more information, see in the - :class:`~kivymd.uix.toolbar.toolbar.MDTopAppBar` classes documentation. - """ - - -class MDBackdropFrontLayer(MDBoxLayout): - """ - Container for front content. - - For more information, see in the - :class:`~kivymd.uix.boxlayout.MDBoxLayout` classes documentation. - """ - - -class MDBackdropBackLayer(MDBoxLayout): - """ - Container for back content. - - For more information, see in the - :class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation. - """ - - -class _BackLayer(BoxLayout): - pass - - -class _FrontLayer(MDCard): - pass diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__init__.py new file mode 100644 index 0000000..043d8e1 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__init__.py @@ -0,0 +1 @@ +from .badge import MDBadge # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..be3b64f Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__pycache__/badge.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__pycache__/badge.cpython-311.pyc new file mode 100644 index 0000000..a7db700 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/__pycache__/badge.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/badge.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/badge.kv new file mode 100644 index 0000000..4ab649e --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/badge.kv @@ -0,0 +1,19 @@ + + font_style: "Label" + role: "small" + radius: [self.texture_size[1] / 2, ] + pos_hint: {"center_x": 0.5, "center_y": 0.5} + padding: "4dp", "2dp" + halign: "center" + valign: "center" + adaptive_size: True + md_bg_color: self.theme_cls.errorColor + text_color: self.theme_cls.onErrorColor + size_hint: None, None + size: self.texture_size + pos: + ( \ + self.parent.x + (self.parent.width / 2), \ + self.parent.y + (self.parent.height / 2) \ + ) \ + if self.parent else (0, 0) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/badge.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/badge.py new file mode 100644 index 0000000..8134046 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/badge/badge.py @@ -0,0 +1,74 @@ +""" +Components/Badge +================ + +.. versionadded:: 2.0.0 + + +.. seealso:: + + `Material Design 3 spec, Badge `_ + +.. rubric:: Badges show notifications, counts, or status information on + navigation items and icons. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/badges.png + :align: center + +Example +------- + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + + KV = ''' + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDIcon: + icon: "gmail" + pos_hint: {'center_x': .5, 'center_y': .5} + + MDBadge: + text: "12" + ''' + + + class Example(MDApp): + def build(self): + return Builder.load_string(KV) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/badges-example.png + :align: center +""" + +__all__ = ("MDBadge",) + +import os + +from kivy.lang import Builder + +from kivymd.uix.label import MDLabel +from kivymd import uix_path + +with open( + os.path.join(uix_path, "badge", "badge.kv"), encoding="utf-8" +) as kv_file: + Builder.load_string(kv_file.read()) + + +class MDBadge(MDLabel): + """ + Badge class. + + .. versionadded:: 2.0.0 + + For more information see in the + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__init__.py deleted file mode 100644 index 3ed33d0..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .banner import MDBanner # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index adcaa4f..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__pycache__/banner.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__pycache__/banner.cpython-311.pyc deleted file mode 100644 index 18e7813..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/__pycache__/banner.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/banner.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/banner.kv deleted file mode 100644 index 3d874ce..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/banner.kv +++ /dev/null @@ -1,85 +0,0 @@ -#:import Window kivy.core.window.Window - - - - text: root.text_message[0] - secondary_text: root.text_message[1] - tertiary_text: root.text_message[2] - divider: None - _no_ripple_effect: True - - ImageLeftWidget: - source: root.icon - - - - text: root.text_message[0] - secondary_text: root.text_message[1] - divider: None - _no_ripple_effect: True - - ImageLeftWidget: - source: root.icon - - - - text: root.text_message[0] - divider: None - _no_ripple_effect: True - - ImageLeftWidget: - source: root.icon - - - - text: root.text_message[0] - secondary_text: root.text_message[1] - tertiary_text: root.text_message[2] - divider: None - _no_ripple_effect: True - - - - text: root.text_message[0] - secondary_text: root.text_message[1] - divider: None - _no_ripple_effect: True - - - - text: root.text_message[0] - divider: None - _no_ripple_effect: True - - - - size_hint_y: None - height: self.minimum_height - banner_y: 0 - orientation: "vertical" - y: Window.height - self.banner_y - - canvas: - Color: - rgba: 0, 0, 0, 0 - Rectangle: - pos: self.pos - size: self.size - - MDBoxLayout: - id: container_message - adaptive_height: True - - MDBoxLayout: - adaptive_size: True - pos_hint: {"right": 1} - padding: 0, 0, "8dp", "8dp" - spacing: "8dp" - - MDBoxLayout: - id: left_action_box - adaptive_size: True - - MDBoxLayout: - id: right_action_box - adaptive_size: True diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/banner.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/banner.py deleted file mode 100644 index 534783c..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/banner/banner.py +++ /dev/null @@ -1,439 +0,0 @@ -""" -Components/Banner -================= - -.. seealso:: - - `Material Design spec, Banner `_ - -.. rubric:: A banner displays a prominent message and related optional actions. - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner.png - :align: center - -Usage -===== - -.. code-block:: python - - from kivy.lang import Builder - from kivy.factory import Factory - - from kivymd.app import MDApp - - Builder.load_string(''' - - - MDBanner: - id: banner - text: ["One line string text example without actions."] - # The widget that is under the banner. - # It will be shifted down to the height of the banner. - over_widget: screen - vertical_pad: toolbar.height - - MDTopAppBar: - id: toolbar - title: "Example Banners" - elevation: 4 - pos_hint: {'top': 1} - - MDBoxLayout: - id: screen - orientation: "vertical" - size_hint_y: None - height: Window.height - toolbar.height - - OneLineListItem: - text: "Banner without actions" - on_release: banner.show() - - Widget: - ''') - - - class Test(MDApp): - def build(self): - return Factory.ExampleBanner() - - - Test().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-example-1.gif - :align: center - -.. rubric:: Banner type. - -By default, the banner is of the type ``'one-line'``: - -.. code-block:: kv - - MDBanner: - text: ["One line string text example without actions."] - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-one-line.png - :align: center - -To use a two-line banner, specify the ``'two-line'`` :attr:`MDBanner.type` for the banner -and pass the list of two lines to the :attr:`MDBanner.text` parameter: - -.. code-block:: kv - - MDBanner: - type: "two-line" - text: - ["One line string text example without actions.", "This is the second line of the banner message."] - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-two-line.png - :align: center - -Similarly, create a three-line banner: - -.. code-block:: kv - - MDBanner: - type: "three-line" - text: - ["One line string text example without actions.", "This is the second line of the banner message.", "and this is the third line of the banner message."] - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-three-line.png - :align: center - -To add buttons to any type of banner, -use the :attr:`MDBanner.left_action` and :attr:`MDBanner.right_action` parameters, -which should take a list ['Button name', function]: - -.. code-block:: kv - - MDBanner: - text: ["One line string text example without actions."] - left_action: ["CANCEL", lambda x: None] - -Or two buttons: - -.. code-block:: kv - - MDBanner: - text: ["One line string text example without actions."] - left_action: ["CANCEL", lambda x: None] - right_action: ["CLOSE", lambda x: None] - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-actions.png - :align: center - -If you want to use the icon on the left in the banner, -add the prefix `'-icon'` to the banner type: - -.. code-block:: kv - - MDBanner: - type: "one-line-icon" - icon: f"{images_path}/kivymd.png" - text: ["One line string text example without actions."] - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-icon.png - :align: center - -.. Note:: `See full example `_ -""" - -__all__ = ("MDBanner",) - -import os -from typing import Union - -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ( - BoundedNumericProperty, - ListProperty, - NumericProperty, - ObjectProperty, - OptionProperty, - StringProperty, -) -from kivy.uix.widget import Widget - -from kivymd import uix_path -from kivymd.uix.boxlayout import MDBoxLayout -from kivymd.uix.button import MDFlatButton -from kivymd.uix.card import MDCard -from kivymd.uix.list import ( - OneLineAvatarListItem, - OneLineListItem, - ThreeLineAvatarListItem, - ThreeLineListItem, - TwoLineAvatarListItem, - TwoLineListItem, -) - -with open( - os.path.join(uix_path, "banner", "banner.kv"), - encoding="utf-8", -) as kv_file: - Builder.load_string(kv_file.read()) - - -class MDBanner(MDCard): - """ - Banner class. - - For more information, see in the :class:`~kivymd.uix.card.MDCard` - class documentation. - """ - - vertical_pad = NumericProperty(dp(68)) - """ - Indent the banner at the top of the screen. - - :attr:`vertical_pad` is an :class:`~kivy.properties.NumericProperty` - and defaults to `dp(68)`. - """ - - opening_transition = StringProperty("in_quad") - """ - The name of the animation transition. - - :attr:`opening_transition` is an :class:`~kivy.properties.StringProperty` - and defaults to `'in_quad'`. - """ - - icon = StringProperty("data/logo/kivy-icon-128.png") - """ - Icon banner. - - :attr:`icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `'data/logo/kivy-icon-128.png'`. - """ - - over_widget = ObjectProperty() - """ - The widget that is under the banner. - It will be shifted down to the height of the banner. - - :attr:`over_widget` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - text = ListProperty() - """ - List of lines for banner text. - Must contain no more than three lines for a - `'one-line'`, `'two-line'` and `'three-line'` banner, respectively. - - :attr:`text` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - left_action = ListProperty() - """ - The action of banner. - - To add one action, make a list [`'name_action'`, callback] - where `'name_action'` is a string that corresponds to an action name and - ``callback`` is the function called on a touch release event. - - :attr:`left_action` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - right_action = ListProperty() - """ - Works the same way as :attr:`left_action`. - - :attr:`right_action` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - type = OptionProperty( - "one-line", - options=[ - "one-line", - "two-line", - "three-line", - "one-line-icon", - "two-line-icon", - "three-line-icon", - ], - allownone=True, - ) - """ - Banner type. . Available options are: (`"one-line"`, `"two-line"`, - `"three-line"`, `"one-line-icon"`, `"two-line-icon"`, `"three-line-icon"`). - - :attr:`type` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'one-line'`. - """ - - opening_timeout = BoundedNumericProperty(0.7, min=0.7) - """ - Time interval after which the banner will be shown. - - .. versionadded:: 1.0.0 - - :attr:`opening_timeout` is an :class:`~kivy.properties.BoundedNumericProperty` - and defaults to `0.7`. - """ - - opening_time = NumericProperty(0.15) - """ - The time taken for the banner to slide to the :attr:`state` `'open'`. - - .. versionadded:: 1.0.0 - - :attr:`opening_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.15`. - """ - - closing_time = NumericProperty(0.15) - """ - The time taken for the banner to slide to the :attr:`state` `'close'`. - - .. versionadded:: 1.0.0 - - :attr:`closing_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.15`. - """ - - _type_message = None - _progress = False - - def add_actions_buttons( - self, instance_box: MDBoxLayout, data: list - ) -> None: - """ - Adds buttons to the banner. - - :param data: ['NAME BUTTON', ]; - """ - - if data: - name_action_button, function_action_button = data - action_button = MDFlatButton( - text=f"[b]{name_action_button}[/b]", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - on_release=function_action_button, - ) - action_button.markup = True - instance_box.add_widget(action_button) - - def show(self) -> None: - """Displays a banner on the screen.""" - - def show(interval: Union[int, float]): - self.set_type_banner() - self.add_actions_buttons(self.ids.left_action_box, self.left_action) - self.add_actions_buttons( - self.ids.right_action_box, self.right_action - ) - self._add_banner_to_container() - Clock.schedule_once(self.animation_display_banner, 0.1) - - if not self._progress: - self._progress = True - if self.ids.container_message.children: - self.hide() - Clock.schedule_once(show, self.opening_timeout) - - def hide(self) -> None: - """Hides the banner from the screen.""" - - def hide(interval: Union[int, float]): - anim = Animation(banner_y=0, d=self.closing_time) - anim.bind(on_complete=self._remove_banner) - anim.start(self) - Animation( - y=self.over_widget.y + self.height, d=self.closing_time - ).start(self.over_widget) - - if not self._progress: - self._progress = True - Clock.schedule_once(hide, 0.5) - - def set_type_banner(self) -> None: - self._type_message = { - "three-line-icon": ThreeLineIconBanner, - "two-line-icon": TwoLineIconBanner, - "one-line-icon": OneLineIconBanner, - "three-line": ThreeLineBanner, - "two-line": TwoLineBanner, - "one-line": OneLineBanner, - }[self.type] - - def animation_display_banner(self, interval: Union[int, float]) -> None: - Animation( - banner_y=self.height + self.vertical_pad, - d=self.opening_time, - t=self.opening_transition, - ).start(self) - anim = Animation( - y=self.over_widget.y - self.height, - d=self.opening_time, - t=self.opening_transition, - ) - anim.bind(on_complete=self._reset_progress) - anim.start(self.over_widget) - - def _remove_banner(self, *args): - self.ids.container_message.clear_widgets() - self.ids.left_action_box.clear_widgets() - self.ids.right_action_box.clear_widgets() - self._reset_progress() - - def _reset_progress(self, *args): - self._progress = False - - def _add_banner_to_container(self) -> None: - self.ids.container_message.add_widget( - self._type_message(text_message=self.text, icon=self.icon) - ) - - -class BaseBanner(Widget): - """Implements the base banner class.""" - - text_message = ListProperty(["", "", ""]) - """ - List of banner strings. First, second and, respectively, third lines. - - :attr:`text_message` is an :class:`~kivy.properties.ListProperty` - and defaults to `['', '', '']`. - """ - - icon = StringProperty() - """ - Icon banner. - - :attr:`icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - def on_touch_down(self, touch): - self.parent.parent.hide() - - -class ThreeLineIconBanner(ThreeLineAvatarListItem, BaseBanner): - pass - - -class TwoLineIconBanner(TwoLineAvatarListItem, BaseBanner): - pass - - -class OneLineIconBanner(OneLineAvatarListItem, BaseBanner): - pass - - -class ThreeLineBanner(ThreeLineListItem, BaseBanner): - pass - - -class TwoLineBanner(TwoLineListItem, BaseBanner): - pass - - -class OneLineBanner(OneLineListItem, BaseBanner): - pass diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__init__.py index d80d8c1..5d26fef 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__init__.py @@ -5,21 +5,11 @@ Behaviors Modules and classes implementing various behaviors for buttons etc. """ -from .backgroundcolor_behavior import ( - BackgroundColorBehavior, - SpecificBackgroundColorBehavior, -) +from .backgroundcolor_behavior import BackgroundColorBehavior # flake8: NOQA from .declarative_behavior import DeclarativeBehavior -from .elevation import ( - CircularElevationBehavior, - CommonElevationBehavior, - FakeCircularElevationBehavior, - FakeRectangularElevationBehavior, - RectangularElevationBehavior, - RoundedRectangularElevationBehavior, -) +from .elevation import CommonElevationBehavior from .motion_behavior import ( MotionDialogBehavior, MotionShackBehavior, diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc index df1b5c8..9260d30 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc index d984cd1..5eafe9a 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc index 73e7ad1..449c70b 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/declarative_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc index 04af103..1c12590 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/elevation.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc index d8e1a41..dc051c8 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc index f60dddd..53e78de 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc index 20f9881..98f07ed 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc index c667f1a..36b5d77 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/motion_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc index 811ebcb..63e0e6d 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc index 2846959..35f386c 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/rotate_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc index ddbf1b8..b1f16f0 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/scale_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/state_layer_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/state_layer_behavior.cpython-311.pyc new file mode 100644 index 0000000..2fa0081 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/state_layer_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc index aa28592..83ab380 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/stencil_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc index 219c014..2a0b4a8 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/toggle_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc index e24bbbf..7bcd10e 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/backgroundcolor_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/backgroundcolor_behavior.py index a24166d..c9fe16c 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/backgroundcolor_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/backgroundcolor_behavior.py @@ -7,7 +7,7 @@ Behaviors/Background Color from __future__ import annotations -__all__ = ("BackgroundColorBehavior", "SpecificBackgroundColorBehavior") +__all__ = ("BackgroundColorBehavior",) from kivy.animation import Animation from kivy.lang import Builder @@ -15,15 +15,10 @@ from kivy.properties import ( ColorProperty, ListProperty, NumericProperty, - OptionProperty, ReferenceListProperty, StringProperty, VariableListProperty, ) -from kivy.utils import get_color_from_hex - -from kivymd.color_definitions import hue, palette, text_colors -from kivymd.theming import ThemeManager Builder.load_string( """ @@ -37,8 +32,9 @@ Builder.load_string( angle: self.angle origin: self._background_origin Color: + group: "backgroundcolor-behavior-bg-color" rgba: self._md_bg_color - RoundedRectangle: + SmoothRoundedRectangle: group: "Background_instruction" size: self.size pos: self.pos if not isinstance(self, RelativeLayout) else (0, 0) @@ -49,11 +45,17 @@ Builder.load_string( source: root.background Color: rgba: self.line_color if self.line_color else (0, 0, 0, 0) - # TODO: maybe we should use SmoothLine, - # but this should be tested on all widgets. - Line: + SmoothLine: width: root.line_width rounded_rectangle: + [ \ + 0, + 0, \ + self.width, \ + self.height, \ + *self.radius, \ + ] \ + if isinstance(self, RelativeLayout) else \ [ \ self.x, self.y, \ @@ -73,7 +75,7 @@ class BackgroundColorBehavior: Background image path. :attr:`background` is a :class:`~kivy.properties.StringProperty` - and defaults to `None`. + and defaults to `''`. """ radius = VariableListProperty([0], length=4) @@ -93,7 +95,7 @@ class BackgroundColorBehavior: # FIXME: in this case, we will not be able to animate this property # using the `Animation` class. - md_bg_color = ColorProperty([1, 1, 1, 0]) + md_bg_color = ColorProperty([0, 0, 0, 0]) """ The background color of the widget (:class:`~kivy.uix.widget.Widget`) that will be inherited from the :attr:`BackgroundColorBehavior` class. @@ -118,12 +120,12 @@ class BackgroundColorBehavior: md_bg_color: 0, 1, 1, 1 :attr:`md_bg_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[1, 1, 1, 0]`. + and defaults to `[0, 0, 0, 0]`. """ line_color = ColorProperty([0, 0, 0, 0]) """ - If a custom value is specified for the `line_color parameter`, the border + If a custom value is specified for the `line_color` parameter, the border of the specified color will be used to border the widget: .. code-block:: kv @@ -157,37 +159,18 @@ class BackgroundColorBehavior: _background_y = NumericProperty(0) _background_origin = ReferenceListProperty(_background_x, _background_y) _md_bg_color = ColorProperty([0, 0, 0, 0]) - _origin_line_color = ColorProperty(None) - _origin_md_bg_color = ColorProperty(None) def __init__(self, **kwarg): super().__init__(**kwarg) - self.bind( - pos=self.update_background_origin, - disabled=self.restore_color_origin, - ) + self.bind(pos=self.update_background_origin) - def restore_color_origin(self, instance_md_widget, value: bool) -> None: - """Called when the values of :attr:`disabled` change.""" - - if not value: - if self._origin_line_color: - self.line_color = self._origin_line_color - if self._origin_md_bg_color: - self.md_bg_color = self._origin_md_bg_color - - def on_line_color(self, instance_md_widget, value: list | str) -> None: - """Called when the values of :attr:`line_color` change.""" - - if not self.disabled: - self._origin_line_color = value - - def on_md_bg_color(self, instance_md_widget, color: list | str): - """Called when the values of :attr:`md_bg_color` change.""" + def on_md_bg_color(self, instance, color: list | str): + """Fired when the values of :attr:`md_bg_color` change.""" if ( hasattr(self, "theme_cls") and self.theme_cls.theme_style_switch_animation + and self.__class__.__name__ != "MDDropdownMenu" ): Animation( _md_bg_color=color, @@ -197,94 +180,10 @@ class BackgroundColorBehavior: else: self._md_bg_color = color - if not self.disabled: - self._origin_md_bg_color = color - - def update_background_origin(self, instance_md_widget, pos: list) -> None: - """Called when the values of :attr:`pos` change.""" + def update_background_origin(self, instance, pos: list) -> None: + """Fired when the values of :attr:`pos` change.""" if self.background_origin: self._background_origin = self.background_origin else: self._background_origin = self.center - - -class SpecificBackgroundColorBehavior(BackgroundColorBehavior): - background_palette = OptionProperty( - "Primary", options=["Primary", "Accent", *palette] - ) - """ - See :attr:`kivymd.color_definitions.palette`. - - :attr:`background_palette` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'Primary'`. - """ - - background_hue = OptionProperty("500", options=hue) - """ - See :attr:`kivymd.color_definitions.hue`. - - :attr:`background_hue` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'500'`. - """ - - specific_text_color = ColorProperty([0, 0, 0, 0.87]) - """ - :attr:`specific_text_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 0.87]`. - """ - - specific_secondary_text_color = ColorProperty([0, 0, 0, 0.87]) - """ - :attr:`specific_secondary_text_color`is an :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 0.87]`. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - if hasattr(self, "theme_cls"): - self.theme_cls.bind( - primary_palette=self._update_specific_text_color, - accent_palette=self._update_specific_text_color, - theme_style=self._update_specific_text_color, - ) - self.bind( - background_hue=self._update_specific_text_color, - background_palette=self._update_specific_text_color, - ) - self._update_specific_text_color(None, None) - - def _update_specific_text_color( - self, instance_theme_manager: ThemeManager, theme_style: str - ) -> None: - if hasattr(self, "theme_cls"): - palette = { - "Primary": self.theme_cls.primary_palette, - "Accent": self.theme_cls.accent_palette, - }.get(self.background_palette, self.background_palette) - else: - palette = {"Primary": "Blue", "Accent": "Amber"}.get( - self.background_palette, self.background_palette - ) - color = get_color_from_hex(text_colors[palette][self.background_hue]) - secondary_color = color[:] - # Check for black text (need to adjust opacity). - if (color[0] + color[1] + color[2]) == 0: - color[3] = 0.87 - secondary_color[3] = 0.54 - else: - secondary_color[3] = 0.7 - - if ( - hasattr(self, "theme_cls") - and self.theme_cls.theme_style_switch_animation - ): - Animation( - specific_text_color=color, - specific_secondary_text_color=secondary_color, - d=self.theme_cls.theme_style_switch_animation_duration, - t="linear", - ).start(self) - else: - self.specific_text_color = color - self.specific_secondary_text_color = secondary_color diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/declarative_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/declarative_behavior.py index 0fb5eb7..de94093 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/declarative_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/declarative_behavior.py @@ -33,31 +33,35 @@ Imperative style .. code-block:: python from kivymd.app import MDApp - from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem - from kivymd.uix.label import MDLabel + from kivymd.uix.navigationbar import ( + MDNavigationBar, + MDNavigationItem, + MDNavigationItemIcon, + MDNavigationItemLabel, + ) from kivymd.uix.screen import MDScreen class Example(MDApp): def build(self): screen = MDScreen() - bottom_navigation = MDBottomNavigation( - panel_color="#eeeaea", - selected_color_background="#97ecf8", - text_color_active="white", - ) + bottom_navigation = MDNavigationBar() - data = { - "screen 1": {"text": "Mail", "icon": "gmail"}, - "screen 2": {"text": "Discord", "icon": "discord"}, - "screen 3": {"text": "LinkedIN", "icon": "linkedin"}, - } - for key in data.keys(): - text = data[key]["text"] - navigation_item = MDBottomNavigationItem( - name=key, text=text, icon=data[key]["icon"] + datas = [ + {"text": "Mail", "icon": "gmail"}, + {"text": "GitHub", "icon": "git"}, + {"text": "LinkedIN", "icon": "linkedin"}, + ] + for data in datas: + text = data["text"] + navigation_item = MDNavigationItem( + MDNavigationItemIcon( + icon=data["icon"], + ), + MDNavigationItemLabel( + text=text, + ), ) - navigation_item.add_widget(MDLabel(text=text, halign="center")) bottom_navigation.add_widget(navigation_item) screen.add_widget(bottom_navigation) @@ -66,9 +70,6 @@ Imperative style Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-styles-programming.png - :align: center - Take a look at the above code example. This is a very simple UI. But looking at this code, you will not be able to figure the widget tree and understand which UI this code implements. This is named imperative programming style, @@ -87,51 +88,42 @@ Declarative style with KV language from kivymd.app import MDApp - class Test(MDApp): + class Example(MDApp): def build(self): return Builder.load_string( ''' MDScreen: - MDBottomNavigation: - panel_color: "#eeeaea" - selected_color_background: "#97ecf8" - text_color_active: "white" + MDNavigationBar: - MDBottomNavigationItem: - name: "screen 1" - text: "Mail" - icon: "gmail" + MDNavigationItem: - MDLabel: + MDNavigationItemIcon: + icon: "gmail" + + MDNavigationItemLabel: text: "Mail" - halign: "center" - MDBottomNavigationItem: - name: "screen 2" - text: "Discord" - icon: "discord" + MDNavigationItem: - MDLabel: - text: "Discord" - halign: "center" + MDNavigationItemIcon: + icon: "git" - MDBottomNavigationItem: - name: "screen 3" - text: "LinkedIN" - icon: "linkedin" + MDNavigationItemLabel: + text: "GitHub" - MDLabel: + MDNavigationItem: + + MDNavigationItemIcon: + icon: "linkedin" + + MDNavigationItemLabel: text: "LinkedIN" - halign: "center" ''' ) - Test().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-styles-programming.png - :align: center + Example().run() Looking at this code, we can now clearly see the widget tree and their properties. We can quickly navigate through the components of the screen and quickly @@ -146,48 +138,41 @@ Declarative style with Python code .. code-block:: python from kivymd.app import MDApp - from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem - from kivymd.uix.label import MDLabel - from kivymd.uix.screen import MDScreen + from kivymd.uix.navigationbar import ( + MDNavigationBar, + MDNavigationItemIcon, + MDNavigationItem, + MDNavigationItemLabel, + ) class Example(MDApp): def build(self): - return ( - MDScreen( - MDBottomNavigation( - MDBottomNavigationItem( - MDLabel( - text="Mail", - halign="center", - ), - name="screen 1", - text="Mail", - icon="gmail", - ), - MDBottomNavigationItem( - MDLabel( - text="Discord", - halign="center", - ), - name="screen 2", - text="Discord", - icon="discord", - ), - MDBottomNavigationItem( - MDLabel( - text="LinkedIN", - halign="center", - ), - name="screen 3", - text="LinkedIN", - icon="linkedin", - ), - panel_color="#eeeaea", - selected_color_background="#97ecf8", - text_color_active="white", - ) - ) + return MDNavigationBar( + MDNavigationItem( + MDNavigationItemIcon( + icon="gmail", + ), + MDNavigationItemLabel( + text="Mail", + ), + ), + MDNavigationItem( + MDNavigationItemIcon( + icon="twitter", + ), + MDNavigationItemLabel( + text="Twitter", + ), + ), + MDNavigationItem( + MDNavigationItemIcon( + icon="linkedin", + ), + MDNavigationItemLabel( + text="LinkedIN", + ), + ), ) @@ -239,7 +224,7 @@ get to the desired id: from kivymd.app import MDApp from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.button import MDRaisedButton + from kivymd.uix.button import MDButton, MDButtonText from kivymd.uix.floatlayout import MDFloatLayout @@ -248,18 +233,22 @@ get to the desired id: return ( MDBoxLayout( MDFloatLayout( - MDRaisedButton( + MDButton( + MDButtonText( + text="Button 1", + ), id="button_1", - text="Button 1", pos_hint={"center_x": 0.5, "center_y": 0.5}, ), id="box_container_1", ), MDBoxLayout( MDFloatLayout( - MDRaisedButton( + MDButton( + MDButtonText( + text="Button 2", + ), id="button_2", - text="Button 2", pos_hint={"center_x": 0.5, "center_y": 0.5}, ), id="float_container", @@ -271,13 +260,13 @@ get to the desired id: def on_start(self): # { - # 'box_container_1': , - # 'box_container_2': + # 'button_1': , + # 'button_2': , + # 'float_container': , + # 'box_container_1': , + # 'box_container_2': , # } - print(self.root.ids) - - # - print(self.root.ids.box_container_2.ids.float_container.ids.button_2) + print(self.root.get_ids()) Example().run() @@ -293,6 +282,15 @@ from kivy.properties import StringProperty from kivy.uix.widget import Widget +class _Dict(dict): + """Implements access to dictionary values via a dot.""" + + def __getattr__(self, name): + return self[name] + + +# TODO: Add cleaning of the `__ids` collection when removing child widgets +# from the parent. class DeclarativeBehavior: """ Implements the creation and addition of child widgets as declarative @@ -307,6 +305,8 @@ class DeclarativeBehavior: and defaults to `''`. """ + __ids = _Dict() + def __init__(self, *args, **kwargs): super().__init__(**kwargs) @@ -314,4 +314,12 @@ class DeclarativeBehavior: if issubclass(child.__class__, Widget): self.add_widget(child) if hasattr(child, "id") and child.id: - self.ids[child.id] = child + self.__ids[child.id] = child + + def get_ids(self) -> dict: + """ + Returns a dictionary of widget IDs defined in Python + code that is written in a declarative style. + """ + + return self.__ids diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/elevation.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/elevation.py index f081d5c..ce219e1 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/elevation.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/elevation.py @@ -31,7 +31,7 @@ For example, let's create a button with a rectangular elevation effect: ) KV = ''' - + size_hint: None, None size: "250dp", "50dp" @@ -39,19 +39,19 @@ For example, let's create a button with a rectangular elevation effect: MDScreen: # With elevation effect - RectangularElevationButton: + ElevationWidget: pos_hint: {"center_x": .5, "center_y": .6} elevation: 4 shadow_offset: 0, -6 shadow_softness: 4 # Without elevation effect - RectangularElevationButton: + ElevationWidget: pos_hint: {"center_x": .5, "center_y": .4} ''' - class RectangularElevationButton( + class ElevationWidget( RectangularRippleBehavior, CommonElevationBehavior, ButtonBehavior, @@ -84,7 +84,7 @@ For example, let's create a button with a rectangular elevation effect: from kivymd.uix.screen import MDScreen - class RectangularElevationButton( + class ElevationWidget( RectangularRippleBehavior, CommonElevationBehavior, ButtonBehavior, @@ -101,13 +101,13 @@ For example, let's create a button with a rectangular elevation effect: def build(self): return ( MDScreen( - RectangularElevationButton( + ElevationWidget( pos_hint={"center_x": .5, "center_y": .6}, elevation=4, shadow_softness=4, shadow_offset=(0, -6), ), - RectangularElevationButton( + ElevationWidget( pos_hint={"center_x": .5, "center_y": .4}, ), ) @@ -271,7 +271,7 @@ Animating the elevation size: 100, 100 md_bg_color: 0, 0, 1, 1 elevation: 2 - radius: 18 + radius: dp(18) ''' @@ -306,6 +306,7 @@ Animating the elevation from kivy.animation import Animation from kivy.uix.behaviors import ButtonBehavior + from kivy.metrics import dp from kivymd.app import MDApp from kivymd.uix.behaviors import CommonElevationBehavior, RectangularRippleBehavior @@ -341,7 +342,7 @@ Animating the elevation size=(100, 100), md_bg_color="blue", elevation=2, - radius=18, + radius=dp(18), ) ) ) @@ -355,23 +356,17 @@ Animating the elevation from __future__ import annotations -__all__ = ( - "CommonElevationBehavior", - "RectangularElevationBehavior", - "CircularElevationBehavior", - "RoundedRectangularElevationBehavior", - "FakeRectangularElevationBehavior", - "FakeCircularElevationBehavior", -) +__all__ = ("CommonElevationBehavior",) -from kivy import Logger from kivy.lang import Builder +from kivy.metrics import dp from kivy.properties import ( BoundedNumericProperty, ColorProperty, ListProperty, NumericProperty, VariableListProperty, + DictProperty, ) from kivy.uix.widget import Widget @@ -393,18 +388,15 @@ Builder.load_string( axis: tuple(self.rotate_value_axis) origin: self.center Color: - rgba: - (0, 0, 0, 0) \ - if self.disabled or not self.elevation else \ - root.shadow_color + rgba: root.shadow_color BoxShadow: - pos: self.pos + pos: self.pos if not isinstance(self, RelativeLayout) else (0, 0) size: self.size offset: root.shadow_offset spread_radius: -(root.shadow_softness), -(root.shadow_softness) - blur_radius: root.elevation * 10 + blur_radius: root.elevation_levels[root.elevation_level] border_radius: - (root.radius if hasattr(self, "radius") else [0, 0, 0, 0]) \ + (root.radius if hasattr(self, "radius") and root.radius else [0, 0, 0, 0]) \ if root.shadow_radius == [0.0, 0.0, 0.0, 0.0] else \ root.shadow_radius canvas.after: @@ -421,6 +413,36 @@ class CommonElevationBehavior(Widget): class documentation. """ + elevation_level = BoundedNumericProperty(0, min=0, max=5) + """ + Elevation level (values from 0 to 5) + + .. versionadded:: 1.2.0 + + :attr:`elevation_level` is an :class:`~kivy.properties.BoundedNumericProperty` + and defaults to `0`. + """ + + elevation_levels = DictProperty( + { + 0: 0, + 1: dp(8), + 2: dp(12), + 3: dp(16), + 4: dp(20), + 5: dp(24), + } + ) + """ + Elevation is measured as the distance between components along the z-axis + in density-independent pixels (dps). + + .. versionadded:: 1.2.0 + + :attr:`elevation_levels` is an :class:`~kivy.properties.DictProperty` + and defaults to `{0: dp(0), 1: dp(8), 2: dp(23), 3: dp(16), 4: dp(20), 5: dp(24)}`. + """ + elevation = BoundedNumericProperty(0, min=0, errorvalue=0) """ Elevation of the widget. @@ -449,7 +471,7 @@ class CommonElevationBehavior(Widget): MDScreen: MDCard: - radius: 12, 46, 12, 46 + radius: dp(12), dp(46), dp(12), dp(46) size_hint: .5, .3 pos_hint: {"center_x": .5, "center_y": .5} elevation: 2 @@ -486,26 +508,26 @@ class CommonElevationBehavior(Widget): from kivymd.uix.behaviors import BackgroundColorBehavior, CommonElevationBehavior KV = ''' - + size_hint: None, None size: "250dp", "50dp" MDScreen: - RectangularElevationButton: + ElevationWidget: pos_hint: {"center_x": .5, "center_y": .6} elevation: 6 shadow_softness: 6 - RectangularElevationButton: + ElevationWidget: pos_hint: {"center_x": .5, "center_y": .4} elevation: 6 shadow_softness: 12 ''' - class RectangularElevationButton(CommonElevationBehavior, BackgroundColorBehavior): + class ElevationWidget(CommonElevationBehavior, BackgroundColorBehavior): def __init__(self, **kwargs): super().__init__(**kwargs) self.md_bg_color = "blue" @@ -522,19 +544,7 @@ class CommonElevationBehavior(Widget): :align: center :attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty` - and defaults to `12`. - """ - - shadow_softness_size = BoundedNumericProperty(2, min=2, deprecated=True) - """ - The value of the softness of the shadow. - - .. versionadded:: 1.1.0 - - .. deprecated:: 1.2.0 - - :attr:`shadow_softness_size` is an :class:`~kivy.properties.NumericProperty` - and defaults to `2`. + and defaults to `0.0`. """ shadow_offset = ListProperty((0, 0)) @@ -551,23 +561,23 @@ class CommonElevationBehavior(Widget): from kivymd.uix.behaviors import BackgroundColorBehavior, CommonElevationBehavior KV = ''' - + size_hint: None, None size: "100dp", "100dp" MDScreen: - RectangularElevationButton: + ElevationWidget: pos_hint: {"center_x": .5, "center_y": .5} elevation: 6 - shadow_radius: 6 + shadow_radius: dp(6) shadow_softness: 12 shadow_offset: -12, -12 ''' - class RectangularElevationButton(CommonElevationBehavior, BackgroundColorBehavior): + class ElevationWidget(CommonElevationBehavior, BackgroundColorBehavior): def __init__(self, **kwargs): super().__init__(**kwargs) self.md_bg_color = "blue" @@ -585,7 +595,7 @@ class CommonElevationBehavior(Widget): .. code-block:: kv - RectangularElevationButton: + ElevationWidget: shadow_offset: 12, -12 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-offset-2.png @@ -593,7 +603,7 @@ class CommonElevationBehavior(Widget): .. code-block:: kv - RectangularElevationButton: + ElevationWidget: shadow_offset: 12, 12 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-offset-3.png @@ -601,7 +611,7 @@ class CommonElevationBehavior(Widget): .. code-block:: kv - RectangularElevationButton: + ElevationWidget: shadow_offset: -12, 12 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-offset-4.png @@ -619,7 +629,7 @@ class CommonElevationBehavior(Widget): .. code-block:: python - RectangularElevationButton: + ElevationWidget: shadow_color: 0, 0, 1, .8 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-color.png @@ -691,82 +701,10 @@ class CommonElevationBehavior(Widget): and defaults to `(0, 0, 1)`. """ - _elevation = 0 + # _elevation = 0 + _elevation_level = 0 + _shadow_softness = 0 + _shadow_color = (0, 0, 0, 0) - def on_elevation(self, instance, value) -> None: - self._elevation = value - - -class RectangularElevationBehavior(CommonElevationBehavior): - """ - .. deprecated:: 1.1.0 - Use :class:`~CommonElevationBehavior` class instead. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Logger.warning( - "KivyMD: " - "The `RectangularElevationBehavior` class has been deprecated. " - "Use the `CommonElevationBehavior` class instead.`" - ) - - -class CircularElevationBehavior(CommonElevationBehavior): - """ - .. deprecated:: 1.1.0 - Use :class:`~CommonElevationBehavior` class instead. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Logger.warning( - "KivyMD: " - "The `CircularElevationBehavior` class has been deprecated. " - "Use the `CommonElevationBehavior` class instead.`" - ) - - -class RoundedRectangularElevationBehavior(CommonElevationBehavior): - """ - .. deprecated:: 1.1.0 - Use :class:`~CommonElevationBehavior` class instead. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Logger.warning( - "KivyMD: " - "The `RoundedRectangularElevationBehavior` class has been " - "deprecated. Use the `CommonElevationBehavior` class instead.`" - ) - - -class FakeRectangularElevationBehavior(CommonElevationBehavior): - """ - .. deprecated:: 1.1.0 - Use :class:`~CommonElevationBehavior` class instead. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Logger.warning( - "KivyMD: " - "The `FakeRectangularElevationBehavior` class has been " - "deprecated. Use the `CommonElevationBehavior` class instead." - ) - - -class FakeCircularElevationBehavior(CommonElevationBehavior): - """ - .. deprecated:: 1.1.0 - Use :class:`~CommonElevationBehavior` class instead. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Logger.warning( - "KivyMD: " - "The `FakeCircularElevationBehavior` class has been deprecated. " - "Use the `CommonElevationBehavior` class instead." - ) + # def on_elevation(self, instance, value) -> None: + # self._elevation = value diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/focus_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/focus_behavior.py index 33e00bd..d9ad37e 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/focus_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/focus_behavior.py @@ -15,7 +15,7 @@ Usage from kivy.lang import Builder from kivymd.app import MDApp - from kivymd.uix.behaviors import RectangularElevationBehavior + from kivymd.uix.behaviors import CommonElevationBehavior from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.behaviors.focus_behavior import FocusBehavior @@ -36,7 +36,7 @@ Usage ''' - class FocusWidget(MDBoxLayout, RectangularElevationBehavior, FocusBehavior): + class FocusWidget(MDBoxLayout, CommonElevationBehavior, FocusBehavior): pass @@ -65,25 +65,26 @@ Color change at focus/defocus __all__ = ("FocusBehavior",) -from kivy.app import App from kivy.properties import BooleanProperty, ColorProperty -from kivy.uix.behaviors import ButtonBehavior from kivymd.uix.behaviors import HoverBehavior -class FocusBehavior(HoverBehavior, ButtonBehavior): +class FocusBehavior(HoverBehavior): """ Focus behavior class. - For more information, see in the :class:`~kivymd.uix.behavior.HoverBehavior` - and :class:`~kivy.uix.button.ButtonBehavior` classes documentation. + For more information, see in the + :class:`~kivymd.uix.behavior.HoverBehavior` and + :class:`~kivy.uix.button.ButtonBehavior` + classes documentation. :Events: :attr:`on_enter` - Called when mouse enters the bbox of the widget AND the widget is visible + Fired when mouse enters the bbox of the widget AND the widget is + visible. :attr:`on_leave` - Called when the mouse exits the widget AND the widget is visible + Fired when the mouse exits the widget AND the widget is visible. """ focus_behavior = BooleanProperty(True) @@ -109,39 +110,3 @@ class FocusBehavior(HoverBehavior, ButtonBehavior): :attr:`unfocus_color` is a :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ - - def on_enter(self): - """Called when mouse enter the bbox of the widget.""" - - if ( - hasattr(self, "md_bg_color") or hasattr(self, "bg_color") - ) and self.focus_behavior: - if hasattr(self, "theme_cls") and not self.focus_color: - color = self.theme_cls.bg_normal - else: - if not self.focus_color: - color = App.get_running_app().theme_cls.bg_normal - else: - color = self.focus_color - self._set_bg_color(color) - - def on_leave(self): - """Called when the mouse exit the widget.""" - - if ( - hasattr(self, "md_bg_color") or hasattr(self, "bg_color") - ) and self.focus_behavior: - if hasattr(self, "theme_cls") and not self.unfocus_color: - color = self.theme_cls.bg_light - else: - if not self.unfocus_color: - color = App.get_running_app().theme_cls.bg_light - else: - color = self.unfocus_color - self._set_bg_color(color) - - def _set_bg_color(self, color): - if hasattr(self, "md_bg_color"): - self.md_bg_color = color - elif hasattr(self, "bg_color"): - self.bg_color = color diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/hover_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/hover_behavior.py index dbe1ce2..e207d03 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/hover_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/hover_behavior.py @@ -27,9 +27,13 @@ the widget. .. note:: - :class:`~HoverBehavior` will by default check to see if the current Widget is visible (i.e. not covered by a modal or popup and not a part of a Relative Layout, MDTab or Carousel that is not currently visible etc) and will only issue events if the widget is visible. + :class:`~HoverBehavior` will by default check to see if the current Widget + is visible (i.e. not covered by a modal or popup and not a part of a + RelativeLayout, MDTab or Carousel that is not currently visible etc) + and will only issue events if the widget is visible. - To get the legacy behavior that the events are always triggered, you can set `detect_visible` on the Widget to `False`. + To get the legacy behavior that the events are always triggered, you can + set `detect_visible` on the Widget to `False`. .. code-block:: python @@ -40,13 +44,14 @@ the widget. from kivymd.uix.boxlayout import MDBoxLayout KV = ''' - Screen + MDScreen + md_bg_color: self.theme_cls.backgroundColor MDBoxLayout: id: box pos_hint: {'center_x': .5, 'center_y': .5} size_hint: .8, .8 - md_bg_color: app.theme_cls.bg_darkest + md_bg_color: self.theme_cls.secondaryContainerColor ''' @@ -54,19 +59,23 @@ the widget. '''Custom item implementing hover behavior.''' def on_enter(self, *args): - '''The method will be called when the mouse cursor - is within the borders of the current widget.''' + ''' + The method will be called when the mouse cursor + is within the borders of the current widget. + ''' - self.md_bg_color = (1, 1, 1, 1) + self.md_bg_color = "white" def on_leave(self, *args): - '''The method will be called when the mouse cursor goes beyond - the borders of the current widget.''' + ''' + The method will be called when the mouse cursor goes beyond + the borders of the current widget. + ''' - self.md_bg_color = self.theme_cls.bg_darkest + self.md_bg_color = self.theme_cls.secondaryContainerColor - class Test(MDApp): + class Example(MDApp): def build(self): self.screen = Builder.load_string(KV) for i in range(5): @@ -74,10 +83,9 @@ the widget. return self.screen - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hover-behavior.gif - :width: 250 px :align: center """ @@ -85,23 +93,25 @@ __all__ = ("HoverBehavior",) from kivy.core.window import Window from kivy.properties import BooleanProperty, ObjectProperty +from kivy.uix.relativelayout import RelativeLayout from kivy.uix.widget import Widget -class HoverBehavior(object): +class HoverBehavior: """ :Events: :attr:`on_enter` - Called when mouse enters the bbox of the widget AND the widget is visible + Fired when mouse enters the bbox of the widget and the widget is + visible. :attr:`on_leave` - Called when the mouse exits the widget AND the widget is visible + Fired when the mouse exits the widget and the widget is visible. """ hovering = BooleanProperty(False) """ `True`, if the mouse cursor is within the borders of the widget. - Note that this is set and cleared even if the widget is not visible + Note that this is set and cleared even if the widget is not visible. :attr:`hover` is a :class:`~kivy.properties.BooleanProperty` and defaults to `False`. @@ -109,7 +119,7 @@ class HoverBehavior(object): hover_visible = BooleanProperty(False) """ - `True` if hovering is True AND is the current widget is visible + `True` if hovering is `True` and is the current widget is visible. :attr:`hover_visible` is a :class:`~kivy.properties.BooleanProperty` and defaults to `False`. @@ -118,7 +128,7 @@ class HoverBehavior(object): enter_point = ObjectProperty(allownone=True) """ Holds the last position where the mouse pointer crossed into the Widget - if the Widget is visible and is currently in a hovering state + if the Widget is visible and is currently in a hovering state. :attr:`enter_point` is a :class:`~kivy.properties.ObjectProperty` and defaults to `None`. @@ -132,22 +142,24 @@ class HoverBehavior(object): and defaults to `True`. """ - def __init__(self, **kwargs): + def __init__(self, *args, **kwargs): self.register_event_type("on_enter") self.register_event_type("on_leave") Window.bind(mouse_pos=self.on_mouse_update) - super(HoverBehavior, self).__init__(**kwargs) + super().__init__(*args, **kwargs) def on_mouse_update(self, *args): - # If the Widget currently has no parent, do nothing + # If the Widget currently has no parent, do nothing. if not self.get_root_window(): return pos = args[1] - # - # is the pointer in the same position as the widget? - # If not - then issue an on_exit event if needed - # - if not self.collide_point(*self.to_widget(*pos)): + # Is the pointer in the same position as the widget? + # If not - then issue an on_exit event if needed. + if not self.collide_point( + *self.to_widget(*pos) + if not isinstance(self, RelativeLayout) + else (pos[0], pos[1]) + ): self.hovering = False self.enter_point = None if self.hover_visible: @@ -155,72 +167,59 @@ class HoverBehavior(object): self.dispatch("on_leave") return - # - # The pointer is in the same position as the widget - # - + # The pointer is in the same position as the widget. if self.hovering: - # - # nothing to do here. Not - this does not handle the case where - # a popup comes over an existing hover event. - # This seems reasonable - # + # Nothing to do here. Not - this does not handle the case where + # a popup comes over an existing hover event. + # This seems reasonable. return - # # Otherwise - set the hovering attribute - # self.hovering = True - # - # We need to traverse the tree to see if the Widget is visible - # - # This is a two stage process: - # - first go up the tree to the root Window. - # At each stage - check that the Widget is actually visible - # - Second - At the root Window check that there is not another branch - # covering the Widget - # - + # We need to traverse the tree to see if the Widget is visible. + # This is a two stage process - first go up the tree to the root. + # Window. At each stage - check that the Widget is actually visible. + # Second - at the root Window check that there is not another branch + # covering the Widget. self.hover_visible = True + if self.detect_visible: widget: Widget = self while True: - # Walk up the Widget tree from the target Widget + # Walk up the Widget tree from the target Widget. parent = widget.parent try: # See if the mouse point collides with the parent - # using both local and glabal coordinates to cover absoluet and relative layouts + # using both local and global coordinates to cover absolute + # and relative layouts. pinside = parent.collide_point( *parent.to_widget(*pos) ) or parent.collide_point(*pos) except Exception: - # The collide_point will error when you reach the root Window + # The collide_point will error when you reach the root + # Window. break if not pinside: self.hover_visible = False break - # Iterate upwards + # Iterate upwards. widget = parent - # # parent = root window # widget = first Widget on the current branch - # - children = parent.children for child in children: - # For each top level widget - check if is current branch + # For each top level widget - check if is current branch. # If it is - then break. - # If not then - since we start at 0 - this widget is visible - # - # Check to see if it should take the hover - # + # If not then - since we start at 0 - this widget is visible. + # Check to see if it should take the hover. if child == widget: - # this means that the current widget is visible + # This means that the current widget is visible. break if child.collide_point(*pos): - # this means that the current widget is covered by a modal or popup + # This means that the current widget is covered by a modal + # or popup. self.hover_visible = False break if self.hover_visible: @@ -228,7 +227,7 @@ class HoverBehavior(object): self.dispatch("on_enter") def on_enter(self): - """Called when mouse enters the bbox of the widget AND the widget is visible.""" + """Fired when mouse enter the bbox of the widget.""" def on_leave(self): - """Called when the mouse exits the widget AND the widget is visible.""" + """Fired when the mouse goes outside the widget border.""" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/motion_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/motion_behavior.py index 044970f..5616c32 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/motion_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/motion_behavior.py @@ -15,17 +15,20 @@ as dialogs, dropdown menu, snack bars, and so on. __all__ = ( "MotionBase", + "MotionExtendedFabButtonBehavior", "MotionDropDownMenuBehavior", "MotionDialogBehavior", "MotionShackBehavior", + "MotionDatePickerBehavior", + "MotionTimePickerBehavior", ) from kivy.animation import Animation from kivy.clock import Clock from kivy.core.window import Window -from kivy.properties import StringProperty, NumericProperty - -from kivymd.uix.behaviors.stencil_behavior import StencilBehavior +from kivy.metrics import dp +from kivy.properties import StringProperty, NumericProperty, ObjectProperty +from kivymd.uix.behaviors.scale_behavior import ScaleBehavior class MotionBase: @@ -166,80 +169,288 @@ class MotionDropDownMenuBehavior(MotionBase): self.scale_value_y = value -class MotionDialogBehavior(MotionBase): +class MotionExtendedFabButtonBehavior(MotionBase): """ - Base class for dialog movement behavior. + Base class for extended Fab button movement behavior. For more information, see in the :class:`~MotionBase` class documentation. """ - show_duration = NumericProperty(0.1) + show_transition = StringProperty("out_circ") + """ + The type of transition of the widget opening. + + :attr:`show_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'out_circ'`. + """ + + shift_transition = StringProperty("out_sine") + """ + Text label transition. + + :attr:`shift_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'out_sine'`. + """ + + show_duration = NumericProperty(0.3) """ Duration of widget display transition. :attr:`show_duration` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.1`. + and defaults to `0.3`. """ - scale_x = NumericProperty(1.5) + hide_transition = StringProperty("out_sine") """ - Default X-axis scaling values. + The type of transition of the widget closing. - :attr:`scale_x` is a :class:`~kivy.properties.NumericProperty` - and defaults to `1.5`. + :attr:`hide_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'linear'`. """ - scale_y = NumericProperty(1.5) + hide_duration = NumericProperty(0.2) """ - Default Y-axis scaling values. + Duration of widget closing transition. - :attr:`scale_y` is a :class:`~kivy.properties.NumericProperty` - and defaults to `1.5`. + :attr:`hide_duration` is a :class:`~kivy.properties.NumericProperty` + and defaults to `0.2`. """ - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.set_default_values() + _x = NumericProperty(0) + _anim_opacity = None - def set_default_values(self): - """Sets default scaled and transparency values.""" + def collapse(self, *args) -> None: + """Collapses the button.""" - self.scale_value_x = self.scale_x - self.scale_value_y = self.scale_y - self.opacity = 0 + def collapse(*args): + if self._label and self._icon: + Animation(_x=0, d=self.hide_duration).start(self) + anim = Animation( + width=dp(56), d=self.hide_duration, t=self.hide_transition + ) + anim.bind(on_progress=self._check_collapse_progress) + anim.start(self) + + Clock.schedule_once(collapse) + + def expand(self, *args) -> None: + """Expands the button.""" + + def expand(*args): + if self._label and self._icon: + anim = Animation( + width=self.width + + self._label.texture_size[0] + + (dp(18) if self._icon else 0), + d=self.show_duration, + t=self.show_transition, + ) + anim.bind(on_progress=self._check_expand_progress) + anim.start(self) + Animation( + _x=dp(12), d=self.show_duration, t=self.shift_transition + ).start(self) + + Clock.schedule_once(expand) + + def set_opacity_text_button(self, value: int) -> None: + if self._label: + self._anim_opacity = Animation( + opacity=value, + d=self.show_duration * 16.666666666666668 / 100 + if value + else self.show_duration * 1.6666666666666667 / 100, + ) + self._anim_opacity.bind( + on_complete=lambda *x: setattr(self, "_anim_opacity", None) + ) + self._anim_opacity.start(self._label) + + def _check_collapse_progress(self, animation, instance, progress) -> None: + if progress > 0.1: + if not self._anim_opacity: + self.set_opacity_text_button(0) + + def _check_expand_progress(self, animation, instance, progress) -> None: + if progress > 0.3: + if not self._anim_opacity: + self.set_opacity_text_button(1) + + +class MotionDialogBehavior(ScaleBehavior, MotionBase): + """ + Base class for dialog movement behavior. + + For more information, see in the + :class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` + :class:`~MotionBase` + classes documentation. + """ + + show_transition = StringProperty("out_expo") + """ + The type of transition of the widget opening. + + :attr:`show_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'out_expo'`. + """ + + show_button_container_transition = StringProperty("out_circ") + """ + The type of transition of the widget opening. + + :attr:`show_button_container_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'out_circ'`. + """ + + hide_transition = StringProperty("out_circ") + """ + The type of transition of the widget opening. + + :attr:`show_transition` is a :class:`~kivy.properties.StringProperty` + and defaults to `'hide_transition'`. + """ + + show_duration = NumericProperty(0.4) + """ + Duration of widget display transition. + + :attr:`show_duration` is a :class:`~kivy.properties.NumericProperty` + and defaults to `0.2`. + """ def on_dismiss(self, *args): - """Called when a dialog closed.""" + """Fired when a dialog closed.""" - self.set_default_values() + def remove_dialog(*args): + Window.remove_widget(self) + if self._scrim: + Window.remove_widget(self._scrim) - def on_open(self, *args): - """Called when a dialog opened.""" + if self._scrim: + Animation(alpha=0, d=self.hide_duration).start(self._scrim) Animation( - opacity=1, - scale_value_x=1, - scale_value_y=1, - t=self.show_transition, - d=self.show_duration, - ).start(self) + y=self.ids.content_container.y, + t=self.hide_transition, + d=self.hide_duration, + ).start(self.ids.button_container) + + anim = Animation( + opacity=0, + scale_value_y=0, + t=self.hide_transition, + d=self.hide_duration, + ) + anim.bind(on_complete=remove_dialog) + anim.start(self) + + def on_open(self, *args): + """Fired when a dialog opened.""" + + def open(*args): + self.scale_value_y = 0 + self.scale_value_center = (0, self.center[1] + self.height / 2) + Animation( + opacity=1, + scale_value_y=1, + t=self.show_transition, + d=self.show_duration, + ).start(self) + + Animation( + y=dp(24), + t=self.show_button_container_transition, + d=self.show_duration + 0.15, + ).start(self.ids.button_container) + + if self._scrim: + Animation(alpha=0.4, d=self.show_duration).start(self._scrim) + + Clock.schedule_once(open) -class MotionShackBehavior(StencilBehavior, MotionBase): +class MotionPickerBehavior(MotionDialogBehavior): + """ + Base class for date/time pickers movement behavior. + + For more information, see in the + :class:`~MotionDialogBehavior` class documentation. + """ + + _scrim = ObjectProperty() + + def on_open(self, *args): + """Fired when a dialog opened.""" + + def open(*args): + self.scale_value_y = 0 + self.scale_value_center = (0, self.center[1] + self.height / 2) + Animation( + opacity=1, + scale_value_y=1, + t=self.show_transition, + d=self.show_duration, + ).start(self) + + if self._scrim: + Animation(alpha=0.4, d=self.show_duration).start(self._scrim) + + Clock.schedule_once(open) + + def on_dismiss(self, *args): + """Fired when a dialog closed.""" + + def remove_dialog(*args): + Window.remove_widget(self) + if self._scrim: + Window.remove_widget(self._scrim) + self.dispatch("on_dismiss") + + if self._scrim: + Animation(alpha=0, d=self.hide_duration).start(self._scrim) + + anim = Animation( + opacity=0, + scale_value_y=0, + t=self.hide_transition, + d=self.hide_duration, + ) + anim.bind(on_complete=remove_dialog) + anim.start(self) + + +class MotionTimePickerBehavior(MotionPickerBehavior): + """ + Base class for time picker movement behavior. + + For more information, see in the + :class:`~MotionPickerBehavior` class documentation. + """ + + +class MotionDatePickerBehavior(MotionPickerBehavior): + """ + Base class for date picker movement behavior. + + For more information, see in the + :class:`~MotionPickerBehavior` class documentation. + """ + + +class MotionShackBehavior(MotionBase): """ The base class for the behavior of the movement of snack bars. For more information, see in the - :class:`~MotionBase` class and - :class:`~kivy.uix.behaviors.stencil_behavior.StencilBehavior` class - documentation. + :class:`~MotionBase` class documentation. """ _interval = 0 _height = 0 def on_dismiss(self, *args): - """Called when a snackbar closed.""" + """Fired when a snackbar closed.""" def remove_snackbar(*args): Window.parent.remove_widget(self) @@ -257,7 +468,7 @@ class MotionShackBehavior(StencilBehavior, MotionBase): anim.start(self) def on_open(self, *args): - """Called when a snackbar opened.""" + """Fired when a snackbar opened.""" def open(*args): self._height = self.height @@ -274,9 +485,9 @@ class MotionShackBehavior(StencilBehavior, MotionBase): ) ) anim.start(self) + self.dispatch("on_open") - Clock.schedule_once(open) - self.dispatch("on_open") + Clock.schedule_once(open, 0.2) def _wait_interval(self, interval): self._interval += interval diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/ripple_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/ripple_behavior.py index fddcef7..1d057ea 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/ripple_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/ripple_behavior.py @@ -285,11 +285,18 @@ class CommonRipple: and defaults to `'ripple_func_out'`. """ + ripple_effect = BooleanProperty(True) + """ + Should I use the ripple effect. + + :attr:`ripple_effect` is an :class:`~kivy.properties.BooleanProperty` + and defaults to `True`. + """ + _ripple_rad = NumericProperty() _doing_ripple = BooleanProperty(False) _finishing_ripple = BooleanProperty(False) _fading_out = BooleanProperty(False) - _no_ripple_effect = BooleanProperty(False) _round_rad = ListProperty([0, 0, 0, 0]) def lay_canvas_instructions(self) -> NoReturn: @@ -333,6 +340,8 @@ class CommonRipple: anim.start(self) def anim_complete(self, *args) -> None: + """Fired when the "fade_out" animation complete.""" + self._doing_ripple = False self._finishing_ripple = False self._fading_out = False @@ -378,7 +387,7 @@ class CommonRipple: if self.ripple_color: pass elif hasattr(self, "theme_cls"): - self.ripple_color = self.theme_cls.ripple_color + self.ripple_color = self.theme_cls.rippleColor else: # If no theme, set Gray 300. self.ripple_color = [ @@ -429,7 +438,11 @@ class RectangularRippleBehavior(CommonRipple): """ def lay_canvas_instructions(self) -> None: - if self._no_ripple_effect: + """ + Adds graphic instructions to the canvas to implement ripple animation. + """ + + if not self.ripple_effect: return with self.canvas.after if self.ripple_canvas_after else self.canvas.before: @@ -493,7 +506,7 @@ class CircularRippleBehavior(CommonRipple): """ def lay_canvas_instructions(self) -> None: - if self._no_ripple_effect: + if not self.ripple_effect: return with self.canvas.after if self.ripple_canvas_after else self.canvas.before: diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/state_layer_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/state_layer_behavior.py new file mode 100644 index 0000000..e13aa4a --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/state_layer_behavior.py @@ -0,0 +1,537 @@ +# TODO: Add docs. + +""" +Behaviors/State Layer +===================== + +.. seealso:: + + `Material Design spec, State layers `_ +""" + +from kivy import platform +from kivy.lang import Builder +from kivy.properties import ColorProperty, NumericProperty + +from kivymd.uix.behaviors.focus_behavior import FocusBehavior + + +Builder.load_string( + """ + + canvas.after: + Color + rgba: self.state_layer_color + RoundedRectangle: + group: "State_layer_instruction" + size: self.size + pos: self.pos + radius: self.radius if hasattr(self, "radius") else [0, ] +""", + filename="StateLayerBehavior.kv", +) + +# TODO: Add methods `set_text_color` and `set_icon_color` +# (methods that set the color of text and icons in the state +# `on_enter` and `on_leave` and `pressed`). + + +class StateLayerBehavior(FocusBehavior): + state_layer_color = ColorProperty([0, 0, 0, 0]) + """ + The color of the layer state. + + :attr:`state_layer_color` is an :class:`~kivy.properties.ColorProperty` + and defaults to `[0, 0, 0, 0]`. + """ + + state_hover = NumericProperty(0.08) + """ + The transparency level of the layer as a percentage when hovering. + + :attr:`state_hover` is an :class:`~kivy.properties.NumericProperty` + and defaults to `0.08`. + """ + + state_press = NumericProperty(0.12) + """ + The transparency level of the layer as a percentage when pressed. + + :attr:`state_press` is an :class:`~kivy.properties.NumericProperty` + and defaults to `0.12`. + """ + + state_drag = NumericProperty(0.16) + """ + The transparency level of the layer as a percentage when dragged. + + :attr:`state_drag` is an :class:`~kivy.properties.NumericProperty` + and defaults to `0.16`. + """ + + # The transparency value of the disabled state. + # These values are specified in the M3 specification. + + # ------------------------------------------------------------------------- + # MDIconButton + # ------------------------------------------------------------------------- + + # Filled. + icon_button_filled_opacity_value_disabled_container = NumericProperty(0.12) + icon_button_filled_opacity_value_disabled_icon = NumericProperty(0.38) + + # Tonal. + icon_button_tonal_opacity_value_disabled_container = NumericProperty(0.12) + icon_button_tonal_opacity_value_disabled_icon = NumericProperty(0.38) + + # Outlined. + icon_button_outlined_opacity_value_disabled_container = NumericProperty( + 0.12 + ) + icon_button_outlined_opacity_value_disabled_line = NumericProperty(0.12) + icon_button_outlined_opacity_value_disabled_icon = NumericProperty(0.38) + + # Standard. + icon_button_standard_opacity_value_disabled_icon = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDFabButton + # ------------------------------------------------------------------------- + + fab_button_opacity_value_disabled_container = NumericProperty(0.12) + fab_button_opacity_value_disabled_icon = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDButton + # ------------------------------------------------------------------------- + + # Filled. + button_filled_opacity_value_disabled_container = NumericProperty(0.12) + button_filled_opacity_value_disabled_icon = NumericProperty(0.38) + button_filled_opacity_value_disabled_text = NumericProperty(0.38) + + # Tonal. + button_tonal_opacity_value_disabled_container = NumericProperty(0.12) + button_tonal_opacity_value_disabled_icon = NumericProperty(0.38) + button_tonal_opacity_value_disabled_text = NumericProperty(0.38) + + # Outlined. + button_outlined_opacity_value_disabled_container = NumericProperty(0.12) + button_outlined_opacity_value_disabled_line = NumericProperty(0.12) + button_outlined_opacity_value_disabled_icon = NumericProperty(0.38) + button_outlined_opacity_value_disabled_text = NumericProperty(0.38) + + # Elevated. + button_elevated_opacity_value_disabled_container = NumericProperty(0.12) + button_elevated_opacity_value_disabled_icon = NumericProperty(0.38) + button_elevated_opacity_value_disabled_text = NumericProperty(0.38) + + # Text. + button_text_opacity_value_disabled_icon = NumericProperty(0.38) + button_text_opacity_value_disabled_text = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDLabel + # ------------------------------------------------------------------------- + + label_opacity_value_disabled_text = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDCard + # ------------------------------------------------------------------------- + + card_filled_opacity_value_disabled_state_container = NumericProperty(0.38) + card_outlined_opacity_value_disabled_state_container = NumericProperty(0.12) + card_opacity_value_disabled_state_elevated_container = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDSegmentedButton + # ------------------------------------------------------------------------- + + segmented_button_opacity_value_disabled_container = NumericProperty(0.12) + segmented_button_opacity_value_disabled_container_active = NumericProperty( + 0.38 + ) + segmented_button_opacity_value_disabled_line = NumericProperty(0.12) + segmented_button_opacity_value_disabled_icon = NumericProperty(0.38) + segmented_button_opacity_value_disabled_text = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDChip + # ------------------------------------------------------------------------- + + chip_opacity_value_disabled_container = NumericProperty(0.12) + chip_opacity_value_disabled_text = NumericProperty(0.38) + chip_opacity_value_disabled_icon = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDSwitch + # ------------------------------------------------------------------------- + + switch_opacity_value_disabled_line = NumericProperty(0.12) + switch_opacity_value_disabled_container = NumericProperty(0.12) + switch_thumb_opacity_value_disabled_container = NumericProperty(0.38) + switch_opacity_value_disabled_icon = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDCheckbox + # ------------------------------------------------------------------------- + + checkbox_opacity_value_disabled_container = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # List + # ------------------------------------------------------------------------- + + list_opacity_value_disabled_container = NumericProperty(0.38) + list_opacity_value_disabled_leading_avatar = NumericProperty(0.38) + + # ------------------------------------------------------------------------- + # MDTextField + # ------------------------------------------------------------------------- + + text_field_filled_opacity_value_disabled_state_container = NumericProperty( + 0.18 + ) + text_field_outlined_opacity_value_disabled_state_container = ( + NumericProperty(0) + ) + text_field_opacity_value_disabled_max_length_label = NumericProperty(0.60) + text_field_opacity_value_disabled_helper_text_label = NumericProperty(0.60) + text_field_opacity_value_disabled_hint_text_label = NumericProperty(0.60) + text_field_opacity_value_disabled_leading_icon = NumericProperty(0.60) + text_field_opacity_value_disabled_trailing_icon = NumericProperty(0.60) + text_field_opacity_value_disabled_line = NumericProperty(0.12) + + _state = 0.0 + _bg_color = (0, 0, 0, 0) + _is_already_disabled = False + _shadow_softness = [0, 0] + _elevation_level = 0 + + # def __init__(self, *args, **kwargs): + # super().__init__(*args, **kwargs) + + def set_properties_widget(self) -> None: + """Fired `on_release/on_press/on_enter/on_leave` events.""" + + if not self.disabled: + self._restore_properties() + self._set_state_layer_color() + + def on_disabled(self, instance, value) -> None: + """Fired when the `disabled` value changes.""" + + from kivymd.uix.card import MDCard + from kivymd.uix.button import ( + MDIconButton, + MDButton, + MDFabButton, + MDExtendedFabButton, + ) + from kivymd.uix.segmentedbutton import MDSegmentedButtonItem + from kivymd.uix.segmentedbutton.segmentedbutton import ( + MDSegmentButtonSelectedIcon, + ) + from kivymd.uix.selectioncontrol import MDSwitch + from kivymd.uix.list import BaseListItem + from kivymd.uix.textfield import MDTextField + + if value and not self._is_already_disabled: + self._is_already_disabled = True + if isinstance(self, MDCard): + self.state_layer_color = ( + { + "filled": self.theme_cls.surfaceColor[:-1] + + [ + self.card_filled_opacity_value_disabled_state_container + ], + "outlined": self.theme_cls.outlineColor[:-1] + + [ + self.card_outlined_opacity_value_disabled_state_container + ], + "elevated": self.theme_cls.surfaceVariantColor[:-1] + + [ + self.card_opacity_value_disabled_state_elevated_container + ], + }[self.style] + if not self.md_bg_color_disabled + else self.md_bg_color_disabled + ) + elif isinstance(self, MDIconButton): + self.state_layer_color = ( + { + "tonal": self.theme_cls.onSurfaceColor[:-1] + + [ + self.icon_button_tonal_opacity_value_disabled_container + ], + "filled": self.theme_cls.onSurfaceColor[:-1] + + [ + self.icon_button_filled_opacity_value_disabled_container + ], + "outlined": self.theme_cls.onSurfaceColor[:-1] + + [ + self.icon_button_outlined_opacity_value_disabled_container + ], + "standard": self.theme_cls.transparentColor, + }[self.style] + if not self.md_bg_color_disabled + else self.md_bg_color_disabled + ) + elif isinstance(self, MDButton): + self.state_layer_color = ( + { + "elevated": self.theme_cls.onSurfaceColor[:-1] + + [ + self.button_elevated_opacity_value_disabled_container + ], + "tonal": self.theme_cls.onSurfaceColor[:-1] + + [self.button_tonal_opacity_value_disabled_container], + "filled": self.theme_cls.onSurfaceColor[:-1] + + [self.button_filled_opacity_value_disabled_container], + "outlined": self.theme_cls.onSurfaceColor[:-1] + + [ + self.button_outlined_opacity_value_disabled_container + ], + "text": self.theme_cls.transparentColor, + }[self.style] + if not self.md_bg_color_disabled + else self.md_bg_color_disabled + ) + elif isinstance(self, (MDFabButton, MDExtendedFabButton)): + self.state_layer_color = ( + self.theme_cls.onSurfaceColor[:-1] + + [self.fab_button_opacity_value_disabled_container] + if not self.md_bg_color_disabled + else self.md_bg_color_disabled + ) + elif isinstance(self, MDTextField): + if self.mode == "filled": + self.state_layer_color = self.theme_cls.onSurfaceColor[ + :-1 + ] + [ + self.text_field_filled_opacity_value_disabled_state_container + ] + else: + self.state_layer_color = self.theme_cls.transparentColor + elif isinstance(self.parent, MDSegmentedButtonItem): + self.state_layer_color = ( + self.theme_cls.onSurfaceColor[:-1] + + [self.segmented_button_opacity_value_disabled_container] + if not self.parent.md_bg_color_disabled + else self.parent.md_bg_color_disabled + ) + elif isinstance(self, MDSwitch): + self.state_layer_color = ( + ( + self.theme_cls.surfaceContainerHighestColor + if not self.active + else self.theme_cls.onSurfaceColor + )[:-1] + + [self.switch_opacity_value_disabled_container] + if not self.md_bg_color_disabled + else self.md_bg_color_disabled + ) + elif isinstance(self, BaseListItem): + self.state_layer_color = ( + self.theme_cls.onSurfaceColor[:-1] + + [self.list_opacity_value_disabled_container] + if not self.md_bg_color_disabled + else self.md_bg_color_disabled + ) + elif not value and self._is_already_disabled: + self.state_layer_color = self.theme_cls.transparentColor + self._is_already_disabled = False + + def on_enter(self) -> None: + """Fired when mouse enter the bbox of the widget.""" + + self._state = self.state_hover + self.set_properties_widget() + + def on_leave(self) -> None: + """Fired when the mouse goes outside the widget border.""" + + self._state = 0.0 + self.set_properties_widget() + + def _on_release(self, *args): + """ + Fired when the button is released + (i.e. the touch/click that pressed the button goes away). + """ + + if platform in ["android", "ios"]: + self._state = 0.0 + self.set_properties_widget() + else: + self.on_enter() + + def _on_press(self, *args): + """Fired when the button is pressed.""" + + self._state = self.state_press + self.set_properties_widget() + + def _restore_properties(self): + if self._state == self.state_hover and self.focus_behavior: + if hasattr(self, "elevation_level"): + self._elevation_level = self.elevation_level + if hasattr(self, "shadow_softness"): + self._shadow_softness = self.shadow_softness + if hasattr(self, "md_bg_color"): + self._bg_color = self.md_bg_color + elif not self._state: + if hasattr(self, "elevation_level"): + self.elevation_level = self._elevation_level + if hasattr(self, "shadow_softness"): + self.shadow_softness = self._shadow_softness + if hasattr(self, "bg_color"): + self.bg_color = self._md_bg_color + + # FIXME: For some widgets, the color of the state of its elements is + # ignored. For example, for the `MDSwitch` widget, the color of the status + # of the `Thumb` element and the color of the icon are ignored. + def _get_target_color(self): + from kivymd.uix.card import MDCard + from kivymd.uix.button import ( + MDIconButton, + MDButton, + MDFabButton, + MDExtendedFabButton, + ) + from kivymd.uix.segmentedbutton.segmentedbutton import ( + MDSegmentedButtonContainer, + ) + from kivymd.uix.chip import MDChip + from kivymd.uix.selectioncontrol import MDSwitch, MDCheckbox + from kivymd.uix.list import BaseListItem + from kivymd.uix.textfield import MDTextField + from kivymd.uix.navigationdrawer import MDNavigationDrawerItem + + target_color = None + + if not self.disabled: + self._restore_properties() + + if isinstance(self, MDTextField): + if self.mode == "filled": + target_color = self.theme_cls.onSurfaceColor + else: + target_color = self.theme_cls.transparentColor + elif isinstance(self, (MDCard, BaseListItem)) and not isinstance( + self, MDNavigationDrawerItem + ): + target_color = self.theme_cls.onSurfaceColor + elif isinstance(self, MDNavigationDrawerItem): + target_color = self.theme_cls.onSecondaryContainerColor + elif isinstance(self.parent, MDSegmentedButtonContainer): + target_color = ( + self.theme_cls.onSurfaceColor + if not self.active + else self.theme_cls.onSecondaryContainerColor + ) + elif isinstance(self, MDChip): + # Here, depending on the widget state (focus/pressed...) + # we set the target color of the widget's layer. + # For example: + # + # if self._state == self.state_press: + # target_color = [., ., ., .] + # else: + # ... + if self.type == "assist": + target_color = self.theme_cls.onSurfaceColor + elif self.type in ["filter", "input", "suggestion"]: + target_color = self.theme_cls.onSurfaceVariantColor + elif isinstance(self, MDIconButton): + if self.style == "filled": + target_color = self.theme_cls.onPrimaryColor + elif self.style == "tonal": + target_color = self.theme_cls.onSecondaryContainerColor + elif self.style in ["outlined", "standard"]: + target_color = self.theme_cls.onSurfaceVariantColor + elif isinstance(self, MDButton): + target_color = ( + self.theme_cls.onPrimaryColor + if self.style == "filled" + else self.theme_cls.primaryColor + ) + elif isinstance(self, MDCheckbox): + target_color = ( + self.theme_cls.primaryColor + if self.active + else self.theme_cls.onSurfaceColor + ) + elif isinstance(self, (MDFabButton, MDExtendedFabButton)): + target_color = self.theme_cls.onPrimaryContainerColor + elif isinstance(self, MDSwitch): + target_color = ( + self.theme_cls.primaryColor + if self.active + else self.theme_cls.onSurfaceVariantColor + ) + else: + target_color = self.theme_cls.onSurfaceColor + + return target_color + + def _set_state_layer_color(self): + from kivymd.uix.card import MDCard + from kivymd.uix.button import ( + MDIconButton, + MDButton, + MDFabButton, + MDExtendedFabButton, + ) + from kivymd.uix.segmentedbutton.segmentedbutton import ( + MDSegmentedButtonContainer, + ) + from kivymd.uix.chip import MDChip + from kivymd.uix.selectioncontrol import MDSwitch, MDCheckbox + from kivymd.uix.list import BaseListItem + from kivymd.uix.textfield import MDTextField + from kivymd.uix.tab.tab import MDTabsItemBase + + target_color = self._get_target_color() + if ( + isinstance( + self, + ( + MDCard, + MDTextField, + MDIconButton, + MDButton, + MDFabButton, + MDExtendedFabButton, + MDChip, + MDSwitch, + MDCheckbox, + BaseListItem, + MDTabsItemBase, + ), + ) + or isinstance(self.parent, MDSegmentedButtonContainer) + and target_color + ): + if self._state == self.state_hover and self.focus_behavior: + if ( + not self.focus_color + or self.theme_cls.dynamic_color + and self.theme_focus_color == "Primary" + ): + if ( + isinstance(self, MDTextField) + and self.mode == "outlined" + ): + self.state_layer_color = target_color + else: + self.state_layer_color = target_color[:-1] + [ + self._state + ] + else: + self.state_layer_color = self.focus_color + elif self._state == self.state_press: + self.state_layer_color = target_color[:-1] + [self._state] + elif not self._state: + self.state_layer_color = target_color[:-1] + [self._state] diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/stencil_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/stencil_behavior.py index 4bb5f6d..0c17e74 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/stencil_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/stencil_behavior.py @@ -63,7 +63,7 @@ KivyMD #:import images_path kivymd.images_path - MDCarousel: + Carousel: StencilImage: size_hint: .9, .8 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/toggle_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/toggle_behavior.py index c396a29..df77fed 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/toggle_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/toggle_behavior.py @@ -125,25 +125,16 @@ You can inherit the ``MyToggleButton`` class only from the following classes - :class:`~kivymd.uix.button.MDFillRoundFlatIconButton` """ -__all__ = ("MDToggleButton",) +__all__ = ("MDToggleButtonBehavior",) +from kivy import Logger from kivy.properties import BooleanProperty, ColorProperty from kivy.uix.behaviors import ToggleButtonBehavior -from kivymd.uix.button import ( - ButtonContentsIconText, - MDFillRoundFlatButton, - MDFillRoundFlatIconButton, - MDFlatButton, - MDRaisedButton, - MDRectangleFlatButton, - MDRectangleFlatIconButton, - MDRoundFlatButton, - MDRoundFlatIconButton, -) +from kivymd.uix.button import MDButton, MDIconButton, MDFabButton, BaseButton -class MDToggleButton(ToggleButtonBehavior): +class MDToggleButtonBehavior(ToggleButtonBehavior): background_normal = ColorProperty(None) """ Color of the button in ``rgba`` format for the 'normal' state. @@ -180,38 +171,29 @@ class MDToggleButton(ToggleButtonBehavior): def __init__(self, **kwargs): super().__init__(**kwargs) - classinfo = ( - MDRaisedButton, - MDFlatButton, - MDRectangleFlatButton, - MDRectangleFlatIconButton, - MDRoundFlatButton, - MDRoundFlatIconButton, - MDFillRoundFlatButton, - MDFillRoundFlatIconButton, - ) + classinfo = (MDButton, MDIconButton, MDFabButton) # Do the object inherited from the "supported" buttons? if not issubclass(self.__class__, classinfo): raise ValueError( f"Class {self.__class__} must be inherited from one of the " f"classes in the list {classinfo}" ) + else: + print(666, self.md_bg_color) + # self.theme_bg_color = "Custom" if ( not self.background_normal ): # This means that if the value == [] or None will return True. # If the object inherits from buttons with background: - if isinstance( - self, - ( - MDRaisedButton, - MDFillRoundFlatButton, - MDFillRoundFlatIconButton, - ), - ): + if isinstance(self, BaseButton): + print(111) self.__is_filled = True - self.background_normal = self.theme_cls.primary_color + self.background_normal = ( + "yellow" # self.theme_cls.primary_color + ) # If not background_normal must be the same as the inherited one. else: + print(222) self.background_normal = ( self.md_bg_color[:] if self.md_bg_color else (0, 0, 0, 0) ) @@ -228,25 +210,44 @@ class MDToggleButton(ToggleButtonBehavior): # self.bind(state=self._update_bg) self.fbind("state", self._update_bg) - def _update_bg(self, ins, val): + def _update_bg(self, instance, value): """Updates the color of the background.""" - if val == "down": - self.md_bg_color = self.background_down - if ( - self.__is_filled is False - ): # If the background is transparent, and the button it toggled, - # the font color must be withe [1, 1, 1, 1]. - self.text_color = self.font_color_down + if self.theme_bg_color == "Primary": + self.theme_bg_color = "Custom" + if self.theme_icon_color == "Primary": + self.theme_icon_color = "Custom" + + if value == "down": + if isinstance(self, MDIconButton): + self.md_bg_color = self.theme_cls.primaryColor + self.icon_color = self.theme_cls.onPrimaryColor + + # if ( + # self.__is_filled is False + # ): + # self.text_color = self.font_color_down if self.group: self._release_group(self) else: - self.md_bg_color = self.background_normal - if ( - self.__is_filled is False - ): # If the background is transparent, the font color must be the - # primary color. - self.text_color = self.font_color_normal + if isinstance(self, MDIconButton): + self.md_bg_color = self.theme_cls.surfaceContainerHighestColor + self.icon_color = self.theme_cls.primaryColor - if issubclass(self.__class__, ButtonContentsIconText): - self.icon_color = self.text_color + # if ( + # self.__is_filled is False + # ): + # self.text_color = self.font_color_normal + + # if issubclass(self.__class__, ButtonContentsIconText): + # self.icon_color = self.text_color + + +class MDToggleButton(MDToggleButtonBehavior): + def __init__(self, **kwargs): + super().__init__(**kwargs) + Logger.warning( + f"KivyMD: " + f"The `{self.__class__.__name__}` class has been deprecated. " + f"Use the `MDToggleButtonBehavior` class instead." + ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/touch_behavior.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/touch_behavior.py index 8aca7bf..1f51e68 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/touch_behavior.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/behaviors/touch_behavior.py @@ -16,21 +16,32 @@ Usage .. code-block:: python from kivy.lang import Builder + from kivy.properties import StringProperty from kivymd.app import MDApp from kivymd.uix.behaviors import TouchBehavior - from kivymd.uix.button import MDRaisedButton + from kivymd.uix.button import MDButton KV = ''' - MDScreen: + + style: "elevated" - MyButton: - text: "PRESS ME" + MDButtonText: + text: root.text + + + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + TouchBehaviorButton: + text: "TouchBehavior" pos_hint: {"center_x": .5, "center_y": .5} ''' - class MyButton(MDRaisedButton, TouchBehavior): + class TouchBehaviorButton(MDButton, TouchBehavior): + text = StringProperty() + def on_long_touch(self, *args): print(" event") @@ -41,12 +52,12 @@ Usage print(" event") - class MainApp(MDApp): + class Example(MDApp): def build(self): return Builder.load_string(KV) - MainApp().run() + Example().run() """ __all__ = ("TouchBehavior",) @@ -85,16 +96,18 @@ class TouchBehavior: self.on_triple_tap(touch, *args) def delete_clock(self, widget, touch, *args): + """Removes a key event from `touch.ud`.""" + if self.collide_point(touch.x, touch.y): if "event" in touch.ud: Clock.unschedule(touch.ud["event"]) del touch.ud["event"] def on_long_touch(self, touch, *args): - """Called when the widget is pressed for a long time.""" + """Fired when the widget is pressed for a long time.""" def on_double_tap(self, touch, *args): - """Called by double clicking on the widget.""" + """Fired by double-clicking on the widget.""" def on_triple_tap(self, touch, *args): - """Called by triple clicking on the widget.""" + """Fired by triple clicking on the widget.""" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__init__.py deleted file mode 100644 index d62fda6..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# NOQA F401 -from .bottomnavigation import MDBottomNavigation, MDBottomNavigationItem diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index edb3814..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__pycache__/bottomnavigation.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__pycache__/bottomnavigation.cpython-311.pyc deleted file mode 100644 index 792bc40..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/__pycache__/bottomnavigation.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/bottomnavigation.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/bottomnavigation.kv deleted file mode 100644 index 79f726b..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/bottomnavigation.kv +++ /dev/null @@ -1,118 +0,0 @@ -#:import STANDARD_INCREMENT kivymd.material_resources.STANDARD_INCREMENT - - - - orientation: "vertical" - height: - STANDARD_INCREMENT if app.theme_cls.material_style == "M2" else "80dp" - - ScreenManager: - id: tab_manager - transition: root.transition(duration=root.transition_duration) - on_current: - root.dispatch( \ - "on_switch_tabs", \ - root._get_switchig_tab(self.current), \ - self.current \ - ) - - MDBottomNavigationBar: - id: bottom_panel - size_hint_y: None - radius: root.radius - height: - STANDARD_INCREMENT \ - if app.theme_cls.material_style == "M2" else \ - "80dp" - md_bg_color: - root.theme_cls.bg_dark \ - if not root.panel_color \ - else root.panel_color - - MDBoxLayout: - id: tab_bar - pos_hint: {"center_x": .5, "center_y": .5} - size_hint: None, None - height: - STANDARD_INCREMENT \ - if app.theme_cls.material_style == "M2" else \ - "80dp" - - - - md_bg_color: root.panel_color - on_press: self.tab.dispatch("on_tab_press") - on_release: self.tab.dispatch("on_tab_release") - on_touch_down: self.tab.dispatch("on_tab_touch_down", *args) - on_touch_move: self.tab.dispatch("on_tab_touch_move", *args) - on_touch_up: self.tab.dispatch("on_tab_touch_up", *args) - width: - root.panel.width / len(root.panel.ids.tab_manager.screens) \ - if len(root.panel.ids.tab_manager.screens) != 0 \ - else root.panel.width - padding: - 0, "12dp", 0, "12dp" if app.theme_cls.material_style == "M2" else "16dp" - - RelativeLayout: - id: item_container - - MDIcon: - id: _label_icon - icon: root.tab.icon - height: self.height - badge_icon: root.tab.badge_icon - theme_text_color: "Custom" - text_color: root._text_color_normal - opposite_colors: root.opposite_colors - pos: [self.pos[0], self.pos[1]] - font_size: "24dp" - y: item_container.height - self.height - pos_hint: - {"center_x": .5, "center_y": .5} \ - if not root.panel.use_text else \ - {"center_x": .5, "top": 1} - on_icon: - if self.icon not in md_icons.keys(): \ - self.size_hint = (None, None); \ - self.width = self.font_size; \ - self.height = self.font_size - - canvas.before: - Color: - rgba: - ( \ - ( \ - app.theme_cls.disabled_hint_text_color \ - if not root.selected_color_background else \ - root.selected_color_background \ - ) \ - if root.active else \ - (0, 0, 0, 0) \ - ) \ - if app.theme_cls.material_style == "M3" else \ - (0, 0, 0, 0) - RoundedRectangle: - radius: [16,] - size: root._selected_region_width, dp(32) - pos: - self.center_x - root._selected_region_width / 2, \ - self.center_y - (dp(16)) - - MDLabel: - id: _label - text: root.tab.text - size_hint_x: None - text_size: None, root.height - adaptive_height: True - theme_text_color: "Custom" - text_color: root._text_color_normal - opposite_colors: root.opposite_colors - font_size: root._label_font_size - pos_hint: {"center_x": .5} - y: -dp(4) if app.theme_cls.material_style == "M2" else 0 - font_style: - "Button" if app.theme_cls.material_style == "M2" else "Body2" - - - - md_bg_color: root.theme_cls.bg_normal diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/bottomnavigation.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/bottomnavigation.py deleted file mode 100644 index 9b764d4..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomnavigation/bottomnavigation.py +++ /dev/null @@ -1,880 +0,0 @@ -""" -Components/BottomNavigation -=========================== - -.. seealso:: - - `Material Design 2 spec, Bottom navigation `_ and - `Material Design 3 spec, Bottom navigation `_ - -.. rubric:: Bottom navigation bars allow movement between primary destinations in an app: - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation.png - :align: center - -Usage ------ - -.. code-block:: kv - - - - MDBottomNavigation: - - MDBottomNavigationItem: - name: "screen 1" - - YourContent: - - MDBottomNavigationItem: - name: "screen 2" - - YourContent: - - MDBottomNavigationItem: - name: "screen 3" - - YourContent: - -For ease of understanding, this code works like this: - -.. code-block:: kv - - - - ScreenManager: - - Screen: - name: "screen 1" - - YourContent: - - Screen: - name: "screen 2" - - YourContent: - - Screen: - name: "screen 3" - - YourContent: - -Example -------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - - - class Test(MDApp): - - def build(self): - self.theme_cls.material_style = "M3" - self.theme_cls.theme_style = "Dark" - return Builder.load_string( - ''' - MDScreen: - - MDBottomNavigation: - #panel_color: "#eeeaea" - selected_color_background: "orange" - text_color_active: "lightgrey" - - MDBottomNavigationItem: - name: 'screen 1' - text: 'Mail' - icon: 'gmail' - badge_icon: "numeric-10" - - MDLabel: - text: 'Mail' - halign: 'center' - - MDBottomNavigationItem: - name: 'screen 2' - text: 'Twitter' - icon: 'twitter' - badge_icon: "numeric-5" - - MDLabel: - text: 'Twitter' - halign: 'center' - - MDBottomNavigationItem: - name: 'screen 3' - text: 'LinkedIN' - icon: 'linkedin' - - MDLabel: - text: 'LinkedIN' - halign: 'center' - ''' - ) - - - Test().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem - from kivymd.uix.label import MDLabel - from kivymd.uix.screen import MDScreen - - - class Test(MDApp): - def build(self): - self.theme_cls.material_style = "M3" - self.theme_cls.theme_style = "Dark" - return ( - MDScreen( - MDBottomNavigation( - MDBottomNavigationItem( - MDLabel( - text='Mail', - halign='center', - ), - name='screen 1', - text='Mail', - icon='gmail', - badge_icon="numeric-10", - ), - MDBottomNavigationItem( - MDLabel( - text='Twitter', - halign='center', - ), - name='screen 1', - text='Twitter', - icon='twitter', - badge_icon="numeric-10", - ), - MDBottomNavigationItem( - MDLabel( - text='LinkedIN', - halign='center', - ), - name='screen 1', - text='LinkedIN', - icon='linkedin', - badge_icon="numeric-10", - ), - selected_color_background="orange", - text_color_active="lightgrey", - ) - ) - ) - - - Test().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation.gif - :align: center - -.. rubric:: :class:`~MDBottomNavigationItem` provides the following events for use: - -.. code-block:: python - - __events__ = ( - "on_tab_touch_down", - "on_tab_touch_move", - "on_tab_touch_up", - "on_tab_press", - "on_tab_release", - ) - -.. code-block:: kv - - Root: - - MDBottomNavigation: - - MDBottomNavigationItem: - on_tab_touch_down: print("on_tab_touch_down") - on_tab_touch_move: print("on_tab_touch_move") - on_tab_touch_up: print("on_tab_touch_up") - on_tab_press: print("on_tab_press") - on_tab_release: print("on_tab_release") - - YourContent: - -How to automatically switch a tab? ----------------------------------- - -Use method :attr:`~MDBottomNavigation.switch_tab` which takes as argument -the name of the tab you want to switch to. - -Use custom icon ---------------- - -.. code-block:: kv - - MDBottomNavigation: - - MDBottomNavigationItem: - icon: "icon.png" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-custom-icon.png - :align: center -""" - -__all__ = ( - "TabbedPanelBase", - "MDBottomNavigationItem", - "MDBottomNavigation", - "MDTab", -) - -import os -from typing import Union - -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.core.window.window_sdl2 import WindowSDL -from kivy.lang import Builder -from kivy.metrics import dp, sp -from kivy.properties import ( - BooleanProperty, - ColorProperty, - ListProperty, - NumericProperty, - ObjectProperty, - StringProperty, -) -from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.screenmanager import FadeTransition, ScreenManagerException - -from kivymd import uix_path -from kivymd.material_resources import STANDARD_INCREMENT -from kivymd.theming import ThemableBehavior, ThemeManager -from kivymd.uix.anchorlayout import MDAnchorLayout -from kivymd.uix.behaviors import CommonElevationBehavior, DeclarativeBehavior -from kivymd.uix.behaviors.backgroundcolor_behavior import ( - SpecificBackgroundColorBehavior, -) -from kivymd.uix.floatlayout import MDFloatLayout -from kivymd.uix.screen import MDScreen -from kivymd.utils.set_bars_colors import set_bars_colors - -with open( - os.path.join(uix_path, "bottomnavigation", "bottomnavigation.kv"), - encoding="utf-8", -) as kv_file: - Builder.load_string(kv_file.read()) - - -class MDBottomNavigationHeader(ButtonBehavior, MDAnchorLayout): - """ - Bottom navigation header class. - - For more information, see in the - :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivymd.uix.anchorlayout.MDAnchorLayout` - classes documentation. - """ - - panel_color = ColorProperty([1, 1, 1, 0]) - """ - Panel color of bottom navigation in (r, g, b, a) or string format. - - :attr:`panel_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[1, 1, 1, 0]`. - """ - - tab = ObjectProperty() - """ - :attr:`tab` is an :class:`~MDBottomNavigationItem` - and defaults to `None`. - """ - - panel = ObjectProperty() - """ - :attr:`panel` is an :class:`~MDBottomNavigation` - and defaults to `None`. - """ - - active = BooleanProperty(False) - - text = StringProperty() - """ - :attr:`text` is an :class:`~MDTab.text` - and defaults to `''`. - """ - - text_color_normal = ColorProperty([1, 1, 1, 1]) - """ - Text color in (r, g, b, a) or string format of the label when it is not - selected. - - :attr:`text_color_normal` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[1, 1, 1, 1]`. - """ - - text_color_active = ColorProperty([1, 1, 1, 1]) - """ - Text color in (r, g, b, a) or string format of the label when it is selected. - - :attr:`text_color_active` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[1, 1, 1, 1]`. - """ - - selected_color_background = ColorProperty(None) - """ - The background color in (r, g, b, a) or string format of the highlighted - item when using Material Design v3. - - .. versionadded:: 1.0.0 - - :attr:`selected_color_background` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - opposite_colors = BooleanProperty(True) - - _label = ObjectProperty() - _label_font_size = NumericProperty("12sp") - _text_color_normal = ColorProperty([1, 1, 1, 1]) - _text_color_active = ColorProperty([1, 1, 1, 1]) - _selected_region_width = NumericProperty(dp(64)) - - def __init__(self, panel, tab): - self.panel = panel - self.tab = tab - super().__init__() - self._text_color_normal = ( - self.theme_cls.disabled_hint_text_color - if self.text_color_normal == [1, 1, 1, 1] - else self.text_color_normal - ) - self._label = self.ids._label - self._label_font_size = sp(12) - self.theme_cls.bind(disabled_hint_text_color=self._update_theme_style) - self.active = False - - def on_press(self) -> None: - """Called when clicking on a panel item.""" - - if self.theme_cls.material_style == "M2": - Animation(_label_font_size=sp(14), d=0.1).start(self) - elif self.theme_cls.material_style == "M3": - Animation( - _selected_region_width=dp(64), - t="in_out_sine", - d=0, - ).start(self) - Animation( - _text_color_normal=self.theme_cls.primary_color - if self.text_color_active == [1, 1, 1, 1] - else self.text_color_active, - d=0.1, - ).start(self) - - def _update_theme_style( - self, instance_theme_manager: ThemeManager, color: list - ): - """Called when the application theme style changes (White/Black).""" - - if not self.active: - self._text_color_normal = ( - color - if self.text_color_normal == [1, 1, 1, 1] - else self.text_color_normal - ) - - -class MDTab(MDScreen): - """ - A tab is simply a screen with meta information that defines the content - that goes in the tab header. - - For more information, see in the - :class:`~kivymd.uix.screen.MDScreen` class documentation. - """ - - __events__ = ( - "on_tab_touch_down", - "on_tab_touch_move", - "on_tab_touch_up", - "on_tab_press", - "on_tab_release", - ) - """Events provided.""" - - text = StringProperty() - """ - Tab header text. - - :attr:`text` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - icon = StringProperty("checkbox-blank-circle") - """ - Tab header icon. - - :attr:`icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `'checkbox-blank-circle'`. - """ - - badge_icon = StringProperty() - """ - Tab header badge icon. - - .. versionadded:: 1.0.0 - - :attr:`badge_icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.index = 0 - self.parent_widget = None - self.register_event_type("on_tab_touch_down") - self.register_event_type("on_tab_touch_move") - self.register_event_type("on_tab_touch_up") - self.register_event_type("on_tab_press") - self.register_event_type("on_tab_release") - - def on_tab_touch_down(self, *args): - pass - - def on_tab_touch_move(self, *args): - pass - - def on_tab_touch_up(self, *args): - pass - - def on_tab_press(self, *args): - par = self.parent_widget - if par.previous_tab is not self: - if par.previous_tab.index > self.index: - par.ids.tab_manager.transition.direction = "right" - elif par.previous_tab.index < self.index: - par.ids.tab_manager.transition.direction = "left" - par.ids.tab_manager.current = self.name - par.previous_tab = self - - def on_tab_release(self, *args): - pass - - def __repr__(self): - return f"" - - -class MDBottomNavigationItem(MDTab): - header = ObjectProperty() - """ - :attr:`header` is an :class:`~MDBottomNavigationHeader` - and defaults to `None`. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def animate_header( - self, bottom_navigation_object, bottom_navigation_header_object - ) -> None: - if bottom_navigation_object.use_text: - Animation(_label_font_size=sp(12), d=0.1).start( - bottom_navigation_object.previous_tab.header - ) - Animation( - _selected_region_width=0, - t="in_out_sine", - d=0, - ).start(bottom_navigation_header_object) - Animation( - _text_color_normal=bottom_navigation_header_object.text_color_normal - if bottom_navigation_object.previous_tab.header.text_color_normal - != [1, 1, 1, 1] - else self.theme_cls.disabled_hint_text_color, - d=0.1, - ).start(bottom_navigation_object.previous_tab.header) - bottom_navigation_object.previous_tab.header.active = False - self.header.active = True - - def on_tab_press(self, *args) -> None: - """Called when clicking on a panel item.""" - - bottom_navigation_object = self.parent_widget - bottom_navigation_header_object = ( - bottom_navigation_object.previous_tab.header - ) - - if bottom_navigation_object.previous_tab is not self: - self.animate_header( - bottom_navigation_object, bottom_navigation_header_object - ) - - super().on_tab_press(*args) - - def on_disabled( - self, instance_bottom_navigation_item, disabled_value: bool - ) -> None: - self.header.disabled = disabled_value - - def on_leave(self, *args): - pass - - -class TabbedPanelBase( - ThemableBehavior, SpecificBackgroundColorBehavior, BoxLayout -): - """ - A class that contains all variables a :class:`~kivy.properties.TabPannel` - must have. It is here so I (zingballyhoo) don't get mad about - the :class:`~kivy.properties.TabbedPannels` not being DRY. - - For more information, see in the :class:`~kivymd.theming.ThemableBehavior` - and :class:`~kivymd.uix.behaviors.SpecificBackgroundColorBehavior` - and :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation. - """ - - current = StringProperty(None) - """ - Current tab name. - - :attr:`current` is an :class:`~kivy.properties.StringProperty` - and defaults to `None`. - """ - - previous_tab = ObjectProperty(None, aloownone=True) - """ - :attr:`previous_tab` is an :class:`~MDTab` and defaults to `None`. - """ - - panel_color = ColorProperty(None) - """ - Panel color of bottom navigation. - - :attr:`panel_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - tabs = ListProperty() - - -class MDBottomNavigation(DeclarativeBehavior, TabbedPanelBase): - """ - A bottom navigation that is implemented by delegating all items to a - :class:`~kivy.uix.screenmanager.ScreenManager`. - - For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and - :class:`~TabbedPanelBase` classes documentation. - - :Events: - :attr:`on_switch_tabs` - Called when switching tabs. Returns the object of the tab to be - opened. - - .. versionadded:: 1.0.0 - """ - - transition = ObjectProperty(FadeTransition) - """ - Transition animation of bottom navigation screen manager. - - .. versionadded:: 1.1.0 - - :attr:`transition` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `FadeTransition`. - """ - - transition_duration = NumericProperty(0.2) - """ - Duration animation of bottom navigation screen manager. - - .. versionadded:: 1.1.0 - - :attr:`transition_duration` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - text_color_normal = ColorProperty([1, 1, 1, 1]) - """ - Text color of the label when it is not selected. - - .. code-block:: kv - - MDBottomNavigation: - text_color_normal: 1, 0, 1, 1 - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-text_color_normal.png - - :attr:`text_color_normal` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[1, 1, 1, 1]`. - """ - - text_color_active = ColorProperty([1, 1, 1, 1]) - """ - Text color of the label when it is selected. - - .. code-block:: kv - - MDBottomNavigation: - text_color_active: 0, 0, 0, 1 - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-text_color_active.png - - :attr:`text_color_active` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[1, 1, 1, 1]`. - """ - - use_text = BooleanProperty(True) - """ - Use text for :class:`~MDBottomNavigationItem` or not. - If ``True``, the :class:`~MDBottomNavigation` panel height will be reduced - by the text height. - - .. versionadded:: 1.0.0 - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-use-text.png - :align: center - - :attr:`use_text` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. - """ - - selected_color_background = ColorProperty(None) - """ - The background color of the highlighted item when using Material Design v3. - - .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDBottomNavigation: - selected_color_background: 0, 0, 1, .4 - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation=selected-color-background.png - - :attr:`selected_color_background` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - font_name = StringProperty("Roboto") - """ - Font name of the label. - - .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDBottomNavigation: - font_name: "path/to/font.ttf" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-font-name.png - - :attr:`font_name` is an :class:`~kivy.properties.StringProperty` - and defaults to `'Roboto'`. - """ - - first_widget = ObjectProperty() - """ - :attr:`first_widget` is an :class:`~MDBottomNavigationItem` - and defaults to `None`. - """ - - tab_header = ObjectProperty() - """ - :attr:`tab_header` is an :class:`~MDBottomNavigationHeader` - and defaults to `None`. - """ - - set_bars_color = BooleanProperty(False) - """ - If `True` the background color of the navigation bar will be set - automatically according to the current color of the toolbar. - - .. versionadded:: 1.0.0 - - :attr:`set_bars_color` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - widget_index = NumericProperty(0) - - # Text active color if it is selected. - _active_color = ColorProperty([1, 1, 1, 1]) - - def __init__(self, *args, **kwargs): - self.previous_tab = None - self.register_event_type("on_switch_tabs") - super().__init__(*args, **kwargs) - self.theme_cls.bind(material_style=self.refresh_tabs) - Window.bind(on_resize=self.on_resize) - Clock.schedule_once(lambda x: self.on_resize()) - Clock.schedule_once(self.set_status_bar_color) - - def set_status_bar_color(self, interval: Union[int, float]) -> None: - if self.set_bars_color: - set_bars_colors(self.panel_color, None, self.theme_cls.theme_style) - - def switch_tab(self, name_tab) -> None: - """Switching the tab by name.""" - - if not self.ids.tab_manager.has_screen(name_tab): - raise ScreenManagerException(f"No Screen with name '{name_tab}'.") - self.ids.tab_manager.get_screen(name_tab).dispatch("on_tab_press") - count_index_screen = [ - self.ids.tab_manager.screens.index(screen) - for screen in self.ids.tab_manager.screens - if screen.name == name_tab - ][0] - numbers_screens = list(range(len(self.ids.tab_manager.screens))) - numbers_screens.reverse() - self.ids.tab_bar.children[ - numbers_screens.index(count_index_screen) - ].dispatch("on_press") - - def refresh_tabs(self, *args) -> None: - """Refresh all tabs.""" - - if self.ids: - tab_bar = self.ids.tab_bar - tab_bar.clear_widgets() - tab_manager = self.ids.tab_manager - self._active_color = self.theme_cls.primary_color - - if self.text_color_active != [1, 1, 1, 1]: - self._active_color = self.text_color_active - - for tab in tab_manager.screens: - self.tab_header = MDBottomNavigationHeader(tab=tab, panel=self) - tab.header = self.tab_header - tab_bar.add_widget(self.tab_header) - - if tab is self.first_widget: - self.tab_header._text_color_normal = self._active_color - self.tab_header._label_font_size = sp(14) - self.tab_header.active = True - else: - self.tab_header.ids._label.font_size = sp(12) - self.tab_header._label_font_size = sp(12) - - def on_font_name(self, instance_bottom_navigation, font_name: str) -> None: - for tab in self.ids.tab_bar.children: - tab.ids._label.font_name = font_name - - def on_selected_color_background( - self, instance_bottom_navigation, color: list - ) -> None: - def on_selected_color_background(*args): - for tab in self.ids.tab_bar.children: - tab.selected_color_background = color - - Clock.schedule_once(on_selected_color_background) - - def on_use_text( - self, instance_bottom_navigation, use_text_value: bool - ) -> None: - if not use_text_value: - for instance_bottom_navigation_header in self.ids.tab_bar.children: - instance_bottom_navigation_header.ids.item_container.remove_widget( - instance_bottom_navigation_header.ids._label - ) - if self.theme_cls.material_style == "M2": - height = dp(42) - else: - height = dp(80) - self.height = height - self.ids.bottom_panel.height = height - self.ids.tab_bar.height = height - else: - if self.theme_cls.material_style == "M2": - height = STANDARD_INCREMENT - else: - height = dp(80) - self.height = height - self.ids.bottom_panel.height = height - self.ids.tab_bar.height = height - - def on_text_color_normal( - self, instance_bottom_navigation, color: list - ) -> None: - MDBottomNavigationHeader.text_color_normal = color - for tab in self.ids.tab_bar.children: - if not tab.active: - tab._text_color_normal = color - - def on_text_color_active( - self, instance_bottom_navigation, color: list - ) -> None: - def on_text_color_active(*args): - MDBottomNavigationHeader.text_color_active = color - self.text_color_active = color - for tab in self.ids.tab_bar.children: - tab.text_color_active = color - if tab.active: - tab._text_color_normal = color - - Clock.schedule_once(on_text_color_active) - - def on_switch_tabs(self, bottom_navigation_item, name_tab: str) -> None: - """ - Called when switching tabs. Returns the object of the tab to be opened. - """ - - def on_size(self, *args) -> None: - self.on_resize() - - def on_resize( - self, - instance: Union[WindowSDL, None] = None, - width: Union[int, None] = None, - do_again: bool = True, - ) -> None: - """Called when the application window is resized.""" - - full_width = 0 - for tab in self.ids.tab_manager.screens: - full_width += tab.header.width - tab.header.text_color_normal = self.text_color_normal - self.ids.tab_bar.width = full_width - if do_again: - Clock.schedule_once(lambda x: self.on_resize(do_again=False), 0.1) - - def add_widget(self, widget, **kwargs): - if isinstance(widget, MDBottomNavigationItem): - self.widget_index += 1 - widget.index = self.widget_index - widget.parent_widget = self - self.ids.tab_manager.add_widget(widget) - if self.widget_index == 1: - self.previous_tab = widget - self.first_widget = widget - self.refresh_tabs() - else: - super().add_widget(widget) - - def remove_widget(self, widget): - if isinstance(widget, MDBottomNavigationItem): - self.ids.tab_manager.remove_widget(widget) - self.refresh_tabs() - else: - super().remove_widget(widget) - - def _get_switchig_tab(self, name_tab: str) -> MDBottomNavigationItem: - bottom_navigation_item = None - for bottom_navigation_header_instance in self.ids.tab_bar.children: - if bottom_navigation_header_instance.tab.name == name_tab: - bottom_navigation_item = bottom_navigation_header_instance.tab - break - return bottom_navigation_item - - -class MDBottomNavigationBar(CommonElevationBehavior, MDFloatLayout): - pass diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__init__.py index dec1c23..6f49d65 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__init__.py @@ -1,11 +1,7 @@ # NOQA F401 from .bottomsheet import ( MDBottomSheet, - MDBottomSheetContent, MDBottomSheetDragHandle, MDBottomSheetDragHandleButton, MDBottomSheetDragHandleTitle, - MDCustomBottomSheet, - MDGridBottomSheet, - MDListBottomSheet, ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc index 5b98c82..7f3e9ac 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc index efd4718..4235cc7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/__pycache__/bottomsheet.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.kv index 6d63e1c..1b22bfd 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.kv @@ -1,6 +1,4 @@ - - size_hint_y: None - height: self.minimum_height +#:import Window kivy.core.window.Window @@ -10,13 +8,19 @@ padding: "16dp", "8dp", "16dp", "16dp" BottomSheetDragHandle: - md_bg_color: - app.theme_cls.disabled_hint_text_color \ - if not root.drag_handle_color else \ - root.drag_handle_color + canvas: + Color: + rgba: + app.theme_cls.disabled_hint_text_color \ + if not root.drag_handle_color else \ + root.drag_handle_color + SmoothRoundedRectangle: + pos: self.pos + size: self.size + radius: [dp(4), ] + size_hint: None, None size: "32dp", "4dp" - radius: 4 pos_hint: {"center_x": .5} BottomSheetDragHandleContainer: @@ -27,16 +31,14 @@ orientation: "vertical" - md_bg_color: root.bg_color if root.bg_color else app.theme_cls.bg_darkest - radius: 16, 16, 0, 0 + radius: "16dp", "16dp", 0, 0 padding: 0, "8dp", 0, 0 + -x: 0 + width: Window.width if Window.width <= dp(640) else dp(640) + pos_hint: {"center_x": .5} + y: self.height * (self.open_progress - 1) - MDBoxLayout: + BoxLayout: id: drag_handle_container size_hint_y: None height: self.minimum_height - - MDBoxLayout: - id: container - size_hint_y: None - height: self.minimum_height \ No newline at end of file diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.py index 4961ff0..afe6a66 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/bottomsheet/bottomsheet.py @@ -16,11 +16,16 @@ Usage .. code-block:: kv - MDScreen: + Root: - [ Content screen ] + MDNavigationLayout: + + MDScreenManager: + + [...] + + MDBottomSheet: - MDBottomSheet: The bottom sheet has two types: @@ -28,6 +33,7 @@ The bottom sheet has two types: - Modal_ .. Standard: + Standard -------- @@ -39,150 +45,14 @@ frequently scrolled or panned. Use a standard bottom sheet to display content that complements the screen’s primary content, such as an audio player in a music app. -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-standard.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-standard.gif :align: center Standard bottom sheets are elevated above the main UI region so their visibility is not affected by panning or scrolling. -Standard bottom sheet example ------------------------------ - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - - KV = ''' - MDScreen: - - MDBoxLayout: - orientation: "vertical" - padding: "12dp" - adaptive_height: True - pos_hint: {"top": 1} - - MDSmartTile: - id: smart_tile - source: "https://picsum.photos/id/70/3011/2000" - radius: 16 - box_radius: [0, 0, 16, 16] - size_hint_y: None - height: "240dp" - on_release: - bottom_sheet.open() \\ - if bottom_sheet.state == "close" else \\ - bottom_sheet.dismiss() - - MDLabel: - bold: True - color: 1, 1, 1, 1 - text: - "Tap to open the bottom sheet" \\ - if bottom_sheet.state == "close" else \\ - "Tap to close the bottom sheet" - - MDBottomSheet: - id: bottom_sheet - type: "standard" - bg_color: "grey" - default_opening_height: smart_tile.y - dp(12) - size_hint_y: None - height: root.height - (smart_tile.height + dp(24)) - ''' - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivy.clock import Clock - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.bottomsheet import MDBottomSheet - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.imagelist import MDSmartTile - from kivymd.uix.label import MDLabel - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return MDScreen( - MDBoxLayout( - MDSmartTile( - MDLabel( - id="tile_label", - text="Tap to open the bottom sheet", - bold=True, - color=(1, 1, 1, 1), - ), - id="smart_tile", - source="https://picsum.photos/id/70/3011/2000", - radius=16, - box_radius=[0, 0, 16, 16], - size_hint_y=None, - height="240dp", - ), - id="box", - orientation="vertical", - padding="12dp", - pos_hint={"top": 1}, - adaptive_height=True, - ), - MDBottomSheet( - id="bottom_sheet", - size_hint_y=None, - type="standard", - bg_color="grey", - ), - ) - - def open_bottom_sheet(self, *args): - bottom_sheet = self.root.ids.bottom_sheet - smart_tile = self.root.ids.box.ids.smart_tile - tile_label = smart_tile.ids.tile_label - bottom_sheet.open() if bottom_sheet.state == "close" else bottom_sheet.dismiss() - tile_label.text = ( - "Tap to open the bottom sheet" - if bottom_sheet.state == "close" - else "Tap to close the bottom sheet" - ) - - def on_start(self): - def on_start(*args): - bottom_sheet = self.root.ids.bottom_sheet - smart_tile = self.root.ids.box.ids.smart_tile - bottom_sheet.default_opening_height = smart_tile.y - dp(12) - bottom_sheet.height = self.root.height - ( - smart_tile.height + dp(24) - ) - smart_tile.bind(on_release=lambda x: self.open_bottom_sheet()) - - Clock.schedule_once(on_start, 1.2) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-standard-example.gif - :align: center - .. Modal: + Modal ----- @@ -191,129 +61,7 @@ appear in front of app content, disabling all other app functionality when they appear, and remaining on screen until confirmed, dismissed, or a required action has been taken. -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-modal.png - :align: center - -Modal bottom sheet example --------------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - - KV = ''' - MDScreen: - - MDBoxLayout: - orientation: "vertical" - padding: "12dp" - adaptive_height: True - pos_hint: {"top": 1} - - MDSmartTile: - id: smart_tile - source: "https://picsum.photos/id/70/3011/2000" - radius: 16 - box_radius: [0, 0, 16, 16] - size_hint_y: None - height: "240dp" - on_release: bottom_sheet.open() - - MDLabel: - bold: True - color: 1, 1, 1, 1 - text: "Tap to open the modal bottom sheet" - - MDBottomSheet: - id: bottom_sheet - bg_color: "grey" - default_opening_height: smart_tile.y - dp(12) - size_hint_y: None - height: root.height - (smart_tile.height + dp(24)) - ''' - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivy.clock import Clock - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.bottomsheet import MDBottomSheet - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.imagelist import MDSmartTile - from kivymd.uix.label import MDLabel - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return MDScreen( - MDBoxLayout( - MDSmartTile( - MDLabel( - id="tile_label", - text="Tap to open the modal bottom sheet", - bold=True, - color=(1, 1, 1, 1), - ), - id="smart_tile", - source="https://picsum.photos/id/70/3011/2000", - radius=16, - box_radius=[0, 0, 16, 16], - size_hint_y=None, - height="240dp", - ), - id="box", - orientation="vertical", - padding="12dp", - pos_hint={"top": 1}, - adaptive_height=True, - ), - MDBottomSheet( - id="bottom_sheet", - size_hint_y=None, - bg_color="grey", - ), - ) - - def open_bottom_sheet(self, *args): - bottom_sheet = self.root.ids.bottom_sheet - bottom_sheet.open() - - def on_start(self): - def on_start(*args): - bottom_sheet = self.root.ids.bottom_sheet - smart_tile = self.root.ids.box.ids.smart_tile - bottom_sheet.default_opening_height = smart_tile.y - dp(12) - bottom_sheet.height = self.root.height - ( - smart_tile.height + dp(24) - ) - smart_tile.bind(on_release=lambda x: self.open_bottom_sheet()) - - Clock.schedule_once(on_start, 1.2) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-modal-example.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-modal.gif :align: center Tapping the scrim dismisses a modal bottom sheet. @@ -321,41 +69,6 @@ Tapping the scrim dismisses a modal bottom sheet. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-modal-tapping.png :align: center -Custom positioning ------------------- - -The optional drag handle provides an affordance for custom sheet height, -or for a quick toggle through preset heights. - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-drag-handle.png - :align: center - -.. code-block:: kv - - MDBottomSheet: - - MDBottomSheetDragHandle: - -By default, when you drag and then release the drag handle, the bottom sheet -will be closed or expand to the full screen, depending on whether you released -the drag handle closer to the top or to the bottom of the screen: - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-drag-handle.gif - :align: center - -In order to manually adjust the height of the bottom sheet with the drag handle, -set the `auto_positioning` parameter to `False`: - -.. code-block:: kv - - MDBottomSheet: - auto_positioning: False - - MDBottomSheetDragHandle: - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-drag-handle-auto-positioning.gif - :align: center - Add elements to :class:`~MDBottomSheetDragHandleTitle` class ------------------------------------------------------------ @@ -368,7 +81,6 @@ Add elements to :class:`~MDBottomSheetDragHandleTitle` class MDBottomSheetDragHandleTitle: text: "MDBottomSheet" adaptive_height: True - font_style: "H6" pos_hint: {"center_y": .5} MDBottomSheetDragHandleButton: @@ -377,36 +89,6 @@ Add elements to :class:`~MDBottomSheetDragHandleTitle` class .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-drag-handle-elements.png :align: center -Add custom content to :class:`~MDBottomSheet` class ---------------------------------------------------- - -To add custom content to the bottom sheet, use the -:class:`~MDBottomSheetContent` class: - -.. code-block:: kv - - MDBottomSheet: - bg_color: "darkgrey" - type: "standard" - max_opening_height: self.height - default_opening_height: self.max_opening_height - adaptive_height: True - - MDBottomSheetDragHandle: - drag_handle_color: "grey" - - MDBottomSheetContent: - padding: "16dp" - - MDLabel: - text: "Content" - halign: "center" - font_style: "H5" - adaptive_height: True - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-content.png - :align: center - A practical example with standard bottom sheet ---------------------------------------------- @@ -414,6 +96,8 @@ A practical example with standard bottom sheet .. code-block:: python + import asynckivy + from kivy.lang import Builder from kivy.properties import StringProperty, ObjectProperty, BooleanProperty from kivy_garden.mapview import MapView @@ -421,11 +105,10 @@ A practical example with standard bottom sheet from kivymd.app import MDApp from kivymd.uix.behaviors import TouchBehavior from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.utils import asynckivy KV = ''' #:import MapSource kivy_garden.mapview.MapSource - #:import asynckivy kivymd.utils.asynckivy + #:import asynckivy asynckivy @@ -436,14 +119,14 @@ A practical example with standard bottom sheet MDIconButton: id: icon icon: root.icon - md_bg_color: "#EDF1F9" if not root.selected else app.theme_cls.primary_color + theme_bg_color: "Custom" + md_bg_color: "#EDF1F9" if not root.selected else app.theme_cls.primaryColor pos_hint: {"center_x": .5} theme_icon_color: "Custom" icon_color: "white" if root.selected else "black" on_release: app.set_active_element(root, root.title.lower()) MDLabel: - font_size: "14sp" text: root.title pos_hint: {"center_x": .5} halign: "center" @@ -452,41 +135,41 @@ A practical example with standard bottom sheet MDScreen: - CustomMapView: - bottom_sheet: bottom_sheet - map_source: MapSource(url=app.map_sources[app.current_map]) - lat: 46.5124 - lon: 47.9812 - zoom: 12 + MDNavigationLayout: - MDBottomSheet: - id: bottom_sheet - elevation: 2 - shadow_softness: 6 - bg_color: "white" - type: "standard" - max_opening_height: self.height - default_opening_height: self.max_opening_height - adaptive_height: True - on_open: asynckivy.start(app.generate_content()) + MDScreenManager: - MDBottomSheetDragHandle: - drag_handle_color: "grey" + MDScreen: - MDBottomSheetDragHandleTitle: - text: "Select type map" - adaptive_height: True - bold: True - pos_hint: {"center_y": .5} + CustomMapView: + bottom_sheet: bottom_sheet + map_source: MapSource(url=app.map_sources[app.current_map]) + lat: 46.5124 + lon: 47.9812 + zoom: 12 - MDBottomSheetDragHandleButton: - icon: "close" - _no_ripple_effect: True - on_release: bottom_sheet.dismiss() + MDBottomSheet: + id: bottom_sheet + sheet_type: "standard" + size_hint_y: None + height: "150dp" + on_open: asynckivy.start(app.generate_content()) - MDBottomSheetContent: - id: content_container - padding: 0, 0, 0, "16dp" + MDBottomSheetDragHandle: + drag_handle_color: "grey" + + MDBottomSheetDragHandleTitle: + text: "Select type map" + pos_hint: {"center_y": .5} + + MDBottomSheetDragHandleButton: + icon: "close" + ripple_effect: False + on_release: bottom_sheet.set_state("toggle") + + BoxLayout: + id: content_container + padding: 0, 0, 0, "16dp" ''' @@ -501,7 +184,7 @@ A practical example with standard bottom sheet def on_double_tap(self, touch, *args): if self.bottom_sheet: - self.bottom_sheet.open() + self.bottom_sheet.set_state("toggle") class Example(MDApp): @@ -543,17 +226,62 @@ A practical example with standard bottom sheet Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-sheet-real-example.gif - :align: center +API break +========= +1.2.0 version +------------- + +.. code-block:: kv + + Root: + + MDBottomSheet: + + # Optional. + MDBottomSheetDragHandle: + + # Optional. + MDBottomSheetDragHandleTitle: + + # Optional. + MDBottomSheetDragHandleButton: + + MDBottomSheetContent: + [...] + +2.0.0 version +------------- + +.. code-block:: kv + + Root: + + MDNavigationLayout: + + MDScreenManager: + + # Your screen. + MDScreen: + + MDBottomSheet: + + # Optional. + MDBottomSheetDragHandle: + + # Optional. + MDBottomSheetDragHandleTitle: + + # Optional. + MDBottomSheetDragHandleButton: + icon: "close" + + # Your content. + BoxLayout: """ __all__ = ( - "MDCustomBottomSheet", - "MDGridBottomSheet", - "MDListBottomSheet", "MDBottomSheet", - "MDBottomSheetContent", "MDBottomSheetDragHandle", "MDBottomSheetDragHandleTitle", "MDBottomSheetDragHandleButton", @@ -561,71 +289,38 @@ __all__ = ( import os -from kivy import Logger -from kivy.animation import Animation -from kivy.clock import Clock -from kivy.core.window import Window from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ( - BooleanProperty, - ColorProperty, - NumericProperty, - ObjectProperty, - OptionProperty, - StringProperty, -) -from kivy.uix.screenmanager import Screen +from kivy.properties import ColorProperty, OptionProperty +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.widget import Widget from kivymd import uix_path -from kivymd.uix.behaviors import CommonElevationBehavior, TouchBehavior -from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.button import MDIconButton from kivymd.uix.label import MDLabel -from kivymd.uix.screen import MDScreen -from kivymd.uix.widget import MDWidget +from kivymd.uix.navigationdrawer import MDNavigationDrawer with open( os.path.join(uix_path, "bottomsheet", "bottomsheet.kv"), encoding="utf-8", ) as kv_file: - Builder.load_string(kv_file.read()) + Builder.load_string(kv_file.read(), filename="MDBottomSheet.kv") -class BottomSheetDragHandle(MDWidget): +class BottomSheetDragHandle(Widget): pass -class BottomSheetDragHandleContainer(MDBoxLayout): +class BottomSheetDragHandleContainer(BoxLayout): pass -class BottomSheetScrimLayer(MDWidget): - """ - Implements a transparency layer to shade the parent widget - on which the bottom sheet is displayed. - """ - - -class MDBottomSheetContent(MDBoxLayout): - """ - Implements a container for custom content for the :class:`~MDBottomSheet` - class - - For more information, see in the - :class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation. - - .. versionadded:: 1.2.0 - """ - - class MDBottomSheetDragHandleButton(MDIconButton): """ Implements a close button (or other functionality) for the :class:`~MDBottomSheetDragHandle` container. For more information, see in the - :class:`~kivymd.uix.button.MDIconButton` class documentation. + :class:`~kivymd.uix.button.button.MDIconButton` class documentation. .. versionadded:: 1.2.0 """ @@ -636,20 +331,20 @@ class MDBottomSheetDragHandleTitle(MDLabel): Implements a header for the :class:`~MDBottomSheetDragHandle` container. For more information, see in the - :class:`~kivymd.uix.label.MDLabel` class documentation. + :class:`~kivymd.uix.label.label.MDLabel` class documentation. .. versionadded:: 1.2.0 """ -class MDBottomSheetDragHandle(MDBoxLayout): +class MDBottomSheetDragHandle(BoxLayout): """ Implements a container that can place the header of the bottom sheet and the close button. Also implements the event of dragging the bottom sheet on the parent screen. For more information, see in the - :class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation. + :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. .. versionadded:: 1.2.0 """ @@ -685,479 +380,69 @@ class MDBottomSheetDragHandle(MDBoxLayout): return super().add_widget(widget) -class MDBottomSheet(MDBoxLayout, CommonElevationBehavior, TouchBehavior): +class MDBottomSheet(MDNavigationDrawer): """ Bottom sheet class. For more information, see in the - :class:`~kivymd.uix.boxlayout.MDBoxLayout` and - :class:`~kivymd.uix.behaviors.touch_behavior.CommonElevationBehavior` and - :class:`~kivymd.uix.behaviors.touch_behavior.TouchBehavior` - classes documentation. - - :Events: - `on_open` - Event when opening the bottom sheet. - `on_close` - Event when closing the bottom sheet. - `on_progress` - Bottom sheet opening/closing progress event. + :class:`~kivymd.uix.navigationdrawer.navigationdrawer.MDNavigationDrawer` + class documentation. """ - auto_dismiss = BooleanProperty(True) + sheet_type = OptionProperty("modal", options=("standard", "modal")) """ - This property determines if the view is automatically - dismissed when the user clicks outside it. + Type of sheet. - .. versionadded:: 1.2.0 + Standard bottom sheets co-exist with the screen’s main UI region and allow + for simultaneously viewing and interacting with both regions, especially + when the main UI region is frequently scrolled or panned. Use a standard + bottom sheet to display content that complements the screen’s primary + content, such as an audio player in a music app. - :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. + Like dialogs, modal bottom sheets appear in front of app content, + disabling all other app functionality when they appear, and remaining on + screen until confirmed, dismissed, or a required action has been taken. + + .. versionchanged:: 2.0.0 + + Rename from `type` to `sheet_type`. + + :attr:`sheet_type` is a :class:`~kivy.properties.OptionProperty` + and defaults to `'modal'`. """ - type = OptionProperty("modal", options=["modal", "standard"]) - """ - Type sheet. There are two types of bottom sheets: standard and modal. - Available options are: `'modal'`, `'standard'`. + def on_sheet_type(self, instance, value) -> None: + """Fired when the :attr:`sheet_type` value changes.""" - .. versionadded:: 1.2.0 - - :attr:`type` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'modal`. - """ - - auto_positioning = BooleanProperty(True) - """ - Close or expand the bottom menu automatically when you release the - drag handle. - - .. versionadded:: 1.2.0 - - :attr:`auto_positioning` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. - """ - - max_opening_height = NumericProperty(None, allownone=True) - """ - The maximum height a that the bottom sheet can be opened using the - drag handle. - - .. versionadded:: 1.2.0 - - .. code-block:: kv - - MDBottomSheet: - max_opening_height: "300dp" - - MDBottomSheetDragHandle: - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottomsheet-max-opening-height.gif - :align: center - - :attr:`max_opening_height` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `None`. - """ - - opening_transition = StringProperty("out_cubic") - """ - The name of the animation transition type to use when animating to - the :attr:`state` `'open'`. - - .. versionadded:: 1.2.0 - - :attr:`opening_transition` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_cubic'`. - """ - - closing_transition = StringProperty("out_sine") - """The name of the animation transition type to use when animating to - the :attr:`state` 'close'. - - .. versionadded:: 1.2.0 - - :attr:`closing_transition` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_sine'`. - """ - - default_opening_height = NumericProperty(dp(200)) - """ - Default opening height of the bottom sheet. - - .. versionadded:: 1.2.0 - - :attr:`default_opening_height` is an :class:`~kivy.properties.NumericProperty` - and defaults to `dp(100)`. - """ - - duration_opening = NumericProperty(0.15) - """ - The duration of the bottom sheet opening animation. - - :attr:`duration_opening` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0.15`. - """ - - duration_closing = NumericProperty(0.15) - """ - The duration of the bottom sheet dialog closing animation. - - :attr:`duration_closing` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0.15`. - """ - - animation = BooleanProperty(True) - """ - Whether to use animation for opening and closing of the bottom sheet - or not. - - :attr:`animation` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `True`. - """ - - state = OptionProperty("close", options=["close", "open"]) - """ - Menu state. Available options are: `'close'`, `'open'`. - - .. versionadded:: 1.2.0 - - :attr:`state` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'close'`. - """ - - scrim_layer_color = ColorProperty([0, 0, 0, 1]) - """ - Color for scrim in (r, g, b, a) or string format. - - .. versionadded:: 1.2.0 - - :attr:`scrim_layer_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 1]`. - """ - - bg_color = ColorProperty(None) - """ - Background color of bottom sheet in (r, g, b, a) or string format. - - :attr:`bg_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - radius_from = OptionProperty( - None, - options=[ - "top_left", - "top_right", - "top", - "bottom_right", - "bottom_left", - "bottom", - ], - allownone=True, - deprecated=True, - ) - """ - Sets which corners to cut from the dialog. Available options are: - `"top_left"`, `"top_right"`, `"top"`, `"bottom_right"`, `"bottom_left"`, - `"bottom"`. - - .. deprecated:: 1.2.0 - Use :attr:`radius` instead. - - :attr:`radius_from` is an :class:`~kivy.properties.OptionProperty` - and defaults to `None`. - """ - - value_transparent = ColorProperty([0, 0, 0, 0.8], deprecated=True) - """ - Background color in (r, g, b, a) or string format transparency value when - opening a dialog. - - .. deprecated:: 1.2.0 - - :attr:`value_transparent` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 0.8]`. - """ - - _diff_between_touch_height_sheet = 0 - _alpha_channel_value = 0 - # Menu state: - # - value 'down' - menu is captured; - # - value 'none' - menu is not captured; - _state = OptionProperty("none", options=["none", "down"]) - # There was a touch to the bottom sheet. - _touch_sheet = False - # kivymd.uix.bottomsheet.bottomsheet.BottomSheetScrimLayer object. - _scrim_layer = ObjectProperty(None, allownone=True) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.y = -Window.height # start bottom sheet position - Clock.schedule_once(self.check_parent) - Clock.schedule_once(self.check_max_opening_height) - Clock.schedule_once(self.add_scrim_layer) - self.register_event_type("on_open") - self.register_event_type("on_close") - self.register_event_type("on_progress") - - def on_progress(self, *args) -> None: - """Bottom sheet opening/closing progress event.""" - - def on_open(self, *args) -> None: - """Event when opening the bottom sheet.""" - - def on_close(self, *args) -> None: - """Event when closing the bottom sheet.""" - - def on_long_touch(self, touch, *args): - if self.ids.drag_handle_container.collide_point(touch.x, touch.y): - self._state = "down" - - def on_touch_down(self, touch): - if self.type == "standard": - super().on_touch_down(touch) - - if self.collide_point(touch.x, touch.y): - self._touch_sheet = not self._touch_sheet - if self.type == "standard": - return True - elif self.type == "modal": - return super().on_touch_down(touch) - - def on_touch_up(self, touch): - self._diff_between_touch_height_sheet = 0 - self._alpha_channel_value = 0 - - if self.collide_point(touch.x, touch.y): - self._touch_sheet = not self._touch_sheet - if self.auto_positioning: - if self._state == "down": - self._set_state(touch.y) - else: - if self._state == "down": - self._touch_sheet = not self._touch_sheet - self._set_state(touch.y) - - def on_touch_move(self, touch): - if self._state == "down": - if not self._diff_between_touch_height_sheet: - self._diff_between_touch_height_sheet = ( - abs(self.y) if self.y else self.height - ) - touch.y - - # FIXME: the behavior of the drag handle looks strange: - # sometimes the bottom sheet is dragged as needed, and sometimes - # it's position does not correspond to the cursor coordinates. - y = -( - (self.height - touch.y) - - 0 # self._diff_between_touch_height_sheet - ) - - if y > 0: - self.y = 0 - return - if self.max_opening_height and touch.y > self.max_opening_height: - self.y = -(self.height - self.max_opening_height) - return - - self.y = y - - if self._scrim_layer and self.type == "modal": - if not self._alpha_channel_value: - self._alpha_channel_value = ( - self._scrim_layer.md_bg_color[-1] - touch.psy - ) - - self._scrim_layer.md_bg_color = self._scrim_layer.md_bg_color[ - :-1 - ] + [touch.psy + self._alpha_channel_value] - - # - # if self.radius == [0.0, 0.0, 0.0, 0.0]: - # self.radius = [16, 16, 0, 0] - - return super().on_touch_move(touch) - - def on_type(self, *args) -> None: - self.add_scrim_layer() - - def add_scrim_layer(self, *args) -> None: - """ - Adds a scrim layer to the parent widget on which the bottom sheet - will be displayed. - """ - - if not self._scrim_layer and self.type == "modal": - self._scrim_layer = BottomSheetScrimLayer() - self.parent.add_widget(self._scrim_layer, index=1) - self._scrim_layer.bind(on_touch_down=self._on_touch_down_layer) - if self._scrim_layer and self.type == "standard": - self.parent.remove_widget(self._scrim_layer) - self._scrim_layer = None - - def check_max_opening_height(self, *args) -> None: - if ( - self.max_opening_height - and self.max_opening_height < self.default_opening_height - ): - raise ValueError( - "The value of `max_opening_height` cannot be less " - "than the value of `default_opening_height`" - ) - - def check_parent(self, *args) -> None: - """ - Checks the type of parent widget to which the bottom sheet - will be added. - """ - - if not issubclass(self.parent.__class__, Screen): - raise TypeError( - f"The bottom sheet can only be added to the {Screen} " - f"or {MDScreen} widgets." - ) - - def dismiss(self, *args) -> None: - """Dismiss of bottom sheet.""" - - anim = Animation( - y=-self.height, - d=self.duration_closing if self.animation else 0, - t=self.closing_transition, - ) - anim.bind( - on_complete=lambda x, y: self.dispatch("on_close"), - on_progress=lambda x, y, z: self.dispatch("on_progress", z), - ) - anim.start(self) - - # Animation( - # radius=[16, 16, 0, 0], - # d=self.duration_closing if self.animation else 0, - # ).start(self) - - if self.type == "modal": - Animation( - md_bg_color=self.scrim_layer_color[:-1] + [0], - d=self.duration_closing if self.animation else 0, - ).start(self._scrim_layer) - - self.state = "close" - - def expand(self) -> None: - """Expand of bottom sheet.""" - - Animation( - y=0 - if not self.max_opening_height - else -(self.height - self.default_opening_height), - d=self.duration_opening if self.animation else 0, - t=self.opening_transition, - ).start(self) - - # Animation( - # radius=[0, 0, 0, 0], - # d=self.duration_opening if self.animation else 0, - # ).start(self) - - def open(self, *args) -> None: - """Opening of bottom sheet.""" - - anim = Animation( - y=-(self.height - self.default_opening_height), - d=self.duration_opening if self.animation else 0, - t=self.opening_transition, - ) - anim.bind( - on_complete=lambda x, y: self.dispatch("on_open"), - on_progress=lambda x, y, z: self.dispatch("on_progress", z), - ) - anim.start(self) - - if self.type == "modal": - alpha_channel_value = 100 / self.parent.height - Animation( - md_bg_color=self.scrim_layer_color[:-1] + [alpha_channel_value], - d=self.duration_opening if self.animation else 0, - ).start(self._scrim_layer) - - self.state = "open" - - def clear_content(self) -> None: - """Removes custom content from the bottom sheet.""" - - self.ids.container.clear_widgets() + self.drawer_type = value def add_widget(self, widget, *args, **kwargs): if isinstance(widget, MDBottomSheetDragHandle): self.ids.drag_handle_container.add_widget(widget) return - elif isinstance(widget, MDBottomSheetContent): - self.ids.container.add_widget(widget) - return return super().add_widget(widget) - def _set_state(self, y): - self._state = "none" - if y < self.height / 2: - self.dismiss() - elif y > self.height / 2: - self.expand() + def on_touch_move(self, touch): + if self.enable_swiping: + if self.status == "closed": + if ( + self.get_dist_from_side(touch.oy) <= self.swipe_edge_width + and abs(touch.y - touch.oy) > self.swipe_distance + ): + self.status = "opening_with_swipe" + elif self.status == "opened": + if abs(touch.y - touch.oy) > self.swipe_distance: + self.status = "closing_with_swipe" - def _on_touch_down_layer(self, instance, touch): - if instance.collide_point(touch.x, touch.y): - if self._touch_sheet: - return True - - if self.state == "open" and not self.auto_dismiss: + if self.status in ("opening_with_swipe", "closing_with_swipe"): + self.open_progress = max( + min( + self.open_progress + + (touch.dy if self.anchor == "left" else -touch.dy) + / self.height, + 1, + ), + 0, + ) return True - elif self.state == "open" and self.auto_dismiss: - self.dismiss() - return True - - -class MDCustomBottomSheet(MDBottomSheet): - """ - .. deprecated:: 1.2.0 - Use :class:`~kivymd.uix.bottomsheet.bottomsheet.MDBottomSheet` - class instead. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - Logger.warning( - "KivyMD: " - "The `MDCustomBottomSheet` class has been deprecated. " - "Use the `MDBottomSheet` class instead." - ) - - -class MDListBottomSheet(MDBottomSheet): - """ - .. deprecated:: 1.2.0 - Use :class:`~kivymd.uix.bottomsheet.bottomsheet.MDBottomSheet` - class instead. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - Logger.warning( - "KivyMD: " - "The `MDListBottomSheet` class has been deprecated. " - "Use the `MDBottomSheet` class instead." - ) - - -class MDGridBottomSheet(MDBottomSheet): - """ - .. deprecated:: 1.2.0 - Use :class:`~kivymd.uix.bottomsheet.bottomsheet.MDBottomSheet` - class instead. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - Logger.warning( - "KivyMD: " - "The `MDGridBottomSheet` class has been deprecated. " - "Use the `MDBottomSheet` class instead." - ) + return super().on_touch_move(touch) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/boxlayout.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/boxlayout.py index c5f3e75..2c12326 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/boxlayout.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/boxlayout.py @@ -16,7 +16,7 @@ BoxLayout canvas: Color: - rgba: app.theme_cls.primary_color + rgba: app.theme_cls.primaryColor Rectangle: pos: self.pos size: self.size @@ -28,7 +28,7 @@ MDBoxLayout MDBoxLayout: adaptive_height: True - md_bg_color: app.theme_cls.primary_color + md_bg_color: app.theme_cls.primaryColor Available options are: ---------------------- @@ -38,6 +38,7 @@ Available options are: - adaptive_size_ .. adaptive_height: + adaptive_height --------------- @@ -53,6 +54,7 @@ Equivalent height: self.minimum_height .. adaptive_width: + adaptive_width -------------- @@ -68,6 +70,7 @@ Equivalent height: self.minimum_width .. adaptive_size: + adaptive_size ------------- @@ -89,15 +92,24 @@ from kivy.uix.boxlayout import BoxLayout from kivymd.theming import ThemableBehavior from kivymd.uix import MDAdaptiveWidget -from kivymd.uix.behaviors import DeclarativeBehavior +from kivymd.uix.behaviors import DeclarativeBehavior, BackgroundColorBehavior class MDBoxLayout( - DeclarativeBehavior, ThemableBehavior, BoxLayout, MDAdaptiveWidget + DeclarativeBehavior, + ThemableBehavior, + BackgroundColorBehavior, + BoxLayout, + MDAdaptiveWidget, ): """ Box layout class. - For more information, see in the - :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. + For more information see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` and + :class:`~kivymd.uix.MDAdaptiveWidget` + classes documentation. """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__init__.py index b833a4c..b908f1f 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__init__.py @@ -1,17 +1,13 @@ # NOQA F401 from .button import ( - BaseButton, - ButtonContentsIconText, - MDFillRoundFlatButton, - MDFillRoundFlatIconButton, - MDFlatButton, - MDFloatingActionButton, - MDFloatingActionButtonSpeedDial, + MDButton, + MDButtonIcon, + MDButtonText, MDIconButton, - MDRaisedButton, - MDRectangleFlatButton, - MDRectangleFlatIconButton, - MDRoundFlatButton, - MDRoundFlatIconButton, - MDTextButton, + MDFabButton, + BaseButton, + BaseFabButton, + MDExtendedFabButton, + MDExtendedFabButtonIcon, + MDExtendedFabButtonText, ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/__init__.cpython-311.pyc index 74853bd..a83ac73 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/button.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/button.cpython-311.pyc index 4ce7547..2b3d451 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/button.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/__pycache__/button.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.kv index 77f7d09..908f1fd 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.kv @@ -1,225 +1,391 @@ - - canvas: - Clear - Color: - group: "bg-color" - rgba: - self._md_bg_color \ - if not self.disabled else \ - self._md_bg_color_disabled - RoundedRectangle: - size: self.size - pos: self.pos - source: self.source if hasattr(self, "source") else "" - radius: [root._radius, ] - Color: - group: "outline-color" - rgba: - root._line_color \ - if not root.disabled else \ - (root._line_color_disabled or self._disabled_color) - Line: - width: root.line_width - rounded_rectangle: - ( \ - self.x, self.y, self.width, self.height, \ - root._radius, root._radius, root._radius, root._radius, \ - self.height \ - ) - + size_hint: None, None - anchor_x: root.halign - anchor_y: root.valign - _round_rad: [self._radius] * 4 - - - - lbl_txt: lbl_txt - width: - max( \ - root._min_width, \ - root.padding[0] + lbl_txt.texture_size[0] + root.padding[2] \ + text_size: self.size + halign: "center" + valign: "center" + size: + { \ + "standard": ("56dp", "56dp"), \ + "small": ("40dp", "40dp"), \ + "large": ("96dp", "96dp"), \ + }[self.style] + radius: + { \ + "standard": [dp(16), ], \ + "small": [dp(12), ], \ + "large": [dp(28), ], \ + }[self.style] + shadow_radius: + { \ + "standard": [dp(14), ], \ + "small": [dp(10), ], \ + "large": [dp(26), ], \ + }[self.style] + shadow_offset: 0, -1 + elevation_level: + { \ + "standard": 1, \ + "small": 1, \ + "large": 1, \ + }[self.style] + shadow_color: + ( \ + self.theme_cls.shadowColor[:-1] + [.5] \ + if self.theme_shadow_color == "Primary" else \ + self.shadow_color \ + ) \ + if not self.disabled else self.theme_cls.transparentColor + icon_color: + { \ + "surface": self.theme_cls.onPrimaryContainerColor, \ + "secondary": self.theme_cls.onSecondaryContainerColor, \ + "tertiary": self.theme_cls.onTertiaryContainerColor \ + }[self.color_map] \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color \ + if self.icon_color else \ + self.theme_cls.transparentColor \ ) - size_hint_min_x: - max( \ - root._min_width, \ - root.padding[0] + lbl_txt.texture_size[0] + root.padding[2] \ - ) - height: - max( \ - root._min_height, \ - root.padding[1] + lbl_txt.texture_size[1] + root.padding[3] \ - ) - size_hint_min_y: - max( \ - root._min_height, \ - root.padding[1] + lbl_txt.texture_size[1] + root.padding[3] \ - ) - - MDLabel: - id: lbl_txt - text: root.text - font_size: root.font_size - font_style: root.font_style - halign: 'center' - valign: 'middle' - adaptive_size: True - -text_size: None, None - theme_text_color: root._theme_text_color - text_color: root._text_color - markup: True - disabled: root.disabled - opposite_colors: root.opposite_colors - font_name: root.font_name if root.font_name else self.font_name - - - - lbl_ic: lbl_ic - size: "48dp", "48dp" - padding: "12dp" if root.icon in md_icons else (0, 0, 0, 0) - # Backwards compatibility. - theme_icon_color: root.theme_icon_color or root.theme_text_color - - MDIcon: - id: lbl_ic - icon: root.icon - font_size: root.icon_size if root.icon_size else self.font_size - font_name: root.font_name if root.font_name else self.font_name - opposite_colors: root.opposite_colors - text_color: - # FIXME: ValueError: None is not allowed for MDIcon.text_color. - # This is only a temporary fix and does not fix the cause of the error. - (root._icon_color if root._icon_color else root.theme_cls.text_color) \ - if not root.disabled else \ - root.theme_cls.disabled_hint_text_color \ - if not root.disabled_color else \ - root.disabled_color - # Fix https://github.com/kivymd/KivyMD/issues/1448 - # TODO: Perhaps this change may affect other widgets. - # You need to create tests. - # on_icon: - # if self.icon not in md_icons.keys(): self.size_hint = (1, 1) - theme_text_color: root._theme_icon_color - - - - lbl_txt: lbl_txt - lbl_ic: lbl_ic - - width: - max( \ - root._min_width, \ - root.padding[0] \ - + lbl_ic.texture_size[0] \ - + box.spacing \ - + lbl_txt.texture_size[0] \ - + root.padding[2] \ - ) - size_hint_min_x: - max( \ - root._min_width, \ - root.padding[0] \ - + lbl_ic.texture_size[0] \ - + box.spacing \ - + lbl_txt.texture_size[0] \ - + root.padding[2] \ - ) - height: - max( \ - root._min_height, \ - root.padding[1] \ - + max(lbl_ic.texture_size[1], lbl_txt.texture_size[1]) \ - + root.padding[3] \ - ) - size_hint_min_y: - max( \ - root._min_height, \ - root.padding[1] \ - + max(lbl_ic.texture_size[1], lbl_txt.texture_size[1]) \ - + root.padding[3] \ - ) - - MDBoxLayout: - id: box - adaptive_size: True - padding: 0 - spacing: "8dp" - - MDIcon: - id: lbl_ic - size_hint_x: None - pos_hint: {"center_y": .5} - icon: root.icon - opposite_colors: root.opposite_colors - font_size: - root.icon_size \ - if root.icon_size else \ - (18 / 14 * lbl_txt.font_size) - text_color: - root._icon_color \ - if not root.disabled else \ - root.theme_cls.disabled_hint_text_color - theme_text_color: root._theme_icon_color - - MDLabel: - id: lbl_txt - adaptive_size: True - -text_size: None, None - pos_hint: {"center_y": .5} - halign: 'center' - valign: 'middle' - text: root.text - font_size: root.font_size - font_style: root.font_style - font_name: root.font_name if root.font_name else self.font_name - theme_text_color: root._theme_text_color - text_color: root._text_color - markup: True - disabled: root.disabled - opposite_colors: root.opposite_colors - - - - adaptive_size: True - color: root.theme_cls.primary_color if not root.color else root.color - opacity: 1 - - - - theme_text_color: "Custom" - md_bg_color: self.theme_cls.primary_color + disabled_color: + self.theme_cls.onSurfaceColor[:-1] + \ + [self.fab_button_opacity_value_disabled_icon] \ + if not self.icon_color_disabled else self.icon_color_disabled + theme_font_size: "Custom" + font_size: + { \ + "standard": "24sp", \ + "small": "24sp", \ + "large": "36sp", \ + }[root.style] canvas.before: Color: rgba: - self.theme_cls.primary_color \ - if not self._bg_color else \ - self._bg_color - RoundedRectangle: - pos: - (self.x - self._canvas_width + dp(1.5)) + self._padding_right / 2, \ - self.y - self._padding_right / 2 + dp(1.5) - size: - self.width + self._canvas_width - dp(3), \ - self.height + self._padding_right - dp(3) - radius: [self.height / 2] - - - - theme_text_color: "Custom" - md_bg_color: self.theme_cls.primary_color - - - - padding_x: "8dp" - padding_y: "8dp" - adaptive_size: True - theme_text_color: "Custom" - - canvas.before: - Color: - rgba: self.bg_color - RoundedRectangle: + { \ + "surface": self.theme_cls.surfaceColor, \ + "secondary": self.theme_cls.secondaryColor, \ + "tertiary": self.theme_cls.tertiaryColor \ + }[self.color_map] \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color + SmoothRoundedRectangle: size: self.size pos: self.pos radius: self.radius + + + + x: "16dp" + icon_color: + ( \ + { \ + "surface": self.theme_cls.onPrimaryContainerColor, \ + "secondary": self.theme_cls.onSecondaryContainerColor, \ + "tertiary": self.theme_cls.onTertiaryContainerColor \ + }[self.parent.color_map] \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color \ + if self.icon_color else self.theme_cls.transparentColor \ + ) \ + ) \ + if self.parent else self.theme_cls.transparentColor + disabled_color: + self.theme_cls.onSurfaceColor[:-1] + \ + [self.fab_button_opacity_value_disabled_icon] \ + if not self.icon_color_disabled else self.icon_color_disabled + pos_hint: {"center_y": .5} + + + + adaptive_width: True + text_color: + ( \ + { \ + "surface": self.theme_cls.onPrimaryContainerColor, \ + "secondary": self.theme_cls.onSecondaryContainerColor, \ + "tertiary": self.theme_cls.onTertiaryContainerColor \ + }[self.parent.color_map] \ + if self.theme_text_color == "Primary" else self.text_color \ + ) \ + if self.parent else self.text_color + disabled_color: + ( \ + self.theme_cls.onSurfaceColor[:-1] + \ + [self.fab_button_opacity_value_disabled_icon] \ + if not self.parent.icon_color_disabled else \ + self.parent.icon_color_disabled \ + ) \ + if self.parent else self.theme_cls.transparentColor + pos_hint: {"center_y": .5} + + + + size_hint: None, None + size: "56dp", "56dp" + radius: [dp(16), ] + shadow_radius: [dp(14), ] + shadow_offset: 0, -1 + # shadow_softness: 2 + elevation_level: 1 + shadow_color: + ( \ + self.theme_cls.shadowColor \ + if self.theme_shadow_color == "Primary" else \ + self.shadow_color \ + ) \ + if not self.disabled else self.theme_cls.transparentColor + theme_font_size: "Custom" + font_size: "24sp" + + canvas.before: + Color: + rgba: + { \ + "standard": self.theme_cls.surfaceContainerColor \ + if self.color_map == "surface" else \ + { \ + "secondary": self.theme_cls.secondaryContainerColor, \ + "tertiary": self.theme_cls.tertiaryContainerColor \ + }[self.color_map], \ + "small": self.theme_cls.surfaceContainerHighColor \ + if self.color_map == "surface" else \ + { \ + "secondary": self.theme_cls.secondaryContainerColor, \ + "tertiary": self.theme_cls.tertiaryColor \ + }[self.color_map], \ + "large": self.theme_cls.surfaceContainerColor \ + if self.color_map == "surface" else \ + { \ + "secondary": self.theme_cls.secondaryContainerColor, \ + "tertiary": self.theme_cls.tertiaryColor \ + }[self.color_map], \ + }[self.style] \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color + SmoothRoundedRectangle: + size: self.size + pos: 0, 0 + radius: self.radius + + + + canvas.before: + Color: + group: "md-icon-button-bg-color" + rgba: + ( \ + { \ + "standard": self.theme_cls.transparentColor, \ + "outlined": self.theme_cls.transparentColor, \ + "tonal": self.theme_cls.secondaryContainerColor, \ + "filled": self.theme_cls.primaryColor, \ + }[self.style] \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color \ + ) \ + if not self.disabled else \ + ( \ + ( \ + { \ + "standard": self.theme_cls.transparentColor, \ + "outlined": self.theme_cls.transparentColor, \ + "tonal": self.theme_cls.onSurfaceColor[:-1] \ + + [self.icon_button_tonal_opacity_value_disabled_container], \ + "filled": self.theme_cls.onSurfaceColor[:-1] \ + + [self.icon_button_filled_opacity_value_disabled_container], \ + }[self.style] \ + ) \ + if not self.md_bg_color_disabled else self.md_bg_color_disabled \ + ) + SmoothRoundedRectangle: + size: self.size + pos: self.pos + radius: self.radius + + radius: [self.height / 2,] + halign: "center" + valign: "center" + size_hint: None, None + size: dp(40), dp(40) + text_size: self.size + line_color: + ( \ + ( \ + self.theme_cls.outlineColor \ + if self.theme_line_color == "Primary" else \ + ( \ + self._line_color \ + if self._line_color else \ + self.line_color \ + ) \ + ) \ + if not self.disabled else \ + self.theme_cls.onSurfaceColor[:-1] + \ + [self.icon_button_outlined_opacity_value_disabled_line] \ + ) \ + if self.style == "outlined" else self.theme_cls.transparentColor + icon_color: + ( \ + { \ + "standard": self.theme_cls.primaryColor, \ + "tonal": self.theme_cls.onSecondaryContainerColor, \ + "filled": self.theme_cls.onPrimaryColor, \ + "outlined": self.theme_cls.onSurfaceVariantColor, \ + }[self.style] \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color \ + if self.icon_color else self.theme_cls.transparentColor \ + ) \ + ) + disabled_color: + { \ + "standard": self.theme_cls.onSurfaceColor[:-1] + \ + [self.icon_button_standard_opacity_value_disabled_icon], \ + "tonal": self.theme_cls.onSurfaceColor[:-1] + \ + [self.icon_button_tonal_opacity_value_disabled_icon], \ + "filled": self.theme_cls.onSurfaceColor[:-1] + \ + [self.icon_button_filled_opacity_value_disabled_icon], \ + "outlined": self.theme_cls.onSurfaceColor[:-1] + \ + [self.icon_button_outlined_opacity_value_disabled_icon], \ + }[self.style] \ + if not self.icon_color_disabled else self.icon_color_disabled + + + + md_bg_color: + { \ + "elevated": self.theme_cls.surfaceContainerLowColor, \ + "filled": self.theme_cls.primaryColor, \ + "tonal": self.theme_cls.secondaryContainerColor, \ + "outlined": self.theme_cls.transparentColor, \ + "text": self.theme_cls.transparentColor, \ + }[self.style] \ + if self.theme_bg_color == "Primary" else self.md_bg_color + line_color: + ( \ + ( \ + self.theme_cls.outlineColor \ + if not self.disabled else \ + self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_outlined_opacity_value_disabled_line] \ + ) \ + if self.style == "outlined" else \ + self.theme_cls.transparentColor \ + ) \ + if self.theme_line_color == "Primary" else self.line_color + size_hint_x: None if self.theme_width == "Primary" else self.size_hint_x + size_hint_y: None if self.theme_height == "Primary" else self.size_hint_y + height: "40dp" + elevation: self.elevation_levels[self.elevation_level] + shadow_color: + ( \ + ( \ + self.theme_cls.shadowColor[:-1] + [.5] \ + if self.theme_shadow_color == "Primary" else \ + self.shadow_color \ + ) \ + if self.style not in ["outlined", "text"] else \ + self.theme_cls.transparentColor \ + ) \ + if not self.disabled else self.theme_cls.transparentColor + shadow_radius: self.radius + elevation_level: + { \ + "elevated": 1, \ + "filled": 0, \ + "tonal": 0, \ + "outlined": 0, \ + "text": 0, \ + }[self.style] + shadow_offset: [0, -1] if self.style == "elevated" else [0, 0] + + + + adaptive_size: True + pos_hint: {"center_y": .5} + font_style: "Label" + role: "large" + markup: True + disabled: self._button.disabled if self._button else False + text_color: + ( \ + ( \ + ( \ + { \ + "elevated": self.theme_cls.primaryColor, \ + "filled": self.theme_cls.onPrimaryColor, \ + "tonal": self.theme_cls.onSecondaryContainerColor, \ + "outlined": self.theme_cls.primaryColor, \ + "text": self.theme_cls.primaryColor, \ + }[self._button.style] \ + ) \ + if self._button else self.theme_cls.transparentColor \ + ) \ + if self.theme_text_color == "Primary" else self.text_color \ + ) + disabled_color: + ( \ + { \ + "elevated": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_elevated_opacity_value_disabled_text], \ + "filled": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_filled_opacity_value_disabled_text], \ + "tonal": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_tonal_opacity_value_disabled_text], \ + "outlined": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_outlined_opacity_value_disabled_text], \ + "text": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_text_opacity_value_disabled_text], \ + }[self._button.style] \ + ) \ + if self._button else self.theme_cls.transparentColor + + + + size_hint: None, None + size: "18dp", "18dp" + theme_font_size: "Custom" + font_size: "20sp" + x: "16dp" + pos_hint: {"center_y": .5} + icon_color: + ( \ + ( \ + ( \ + { \ + "elevated": self.theme_cls.primaryColor, \ + "filled": self.theme_cls.onPrimaryColor, \ + "tonal": self.theme_cls.onSecondaryContainerColor, \ + "outlined": self.theme_cls.primaryColor, \ + "text": self.theme_cls.primaryColor, \ + }[self._button.style] \ + ) \ + if self._button else self.theme_cls.transparentColor \ + ) \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color \ + if self.icon_color else \ + self.theme_cls.transparentColor \ + ) \ + ) + disabled_color: + ( \ + { \ + "elevated": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_elevated_opacity_value_disabled_icon], \ + "filled": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_filled_opacity_value_disabled_icon], \ + "tonal": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_tonal_opacity_value_disabled_icon], \ + "outlined": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_outlined_opacity_value_disabled_icon], \ + "text": self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_text_opacity_value_disabled_icon], \ + }[self._button.style] \ + if not self.icon_color_disabled else self.icon_color_disabled \ + ) \ + if self._button else self.theme_cls.transparentColor diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.py index 5750a33..bac35d8 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/button/button.py @@ -4,34 +4,52 @@ Components/Button .. seealso:: - `Material Design spec, Buttons `_ - - `Material Design spec, Buttons: floating action button `_ + `Material Design spec, Buttons `_ .. rubric:: Buttons allow users to take actions, and make choices, - with a single tap. + with a single tap. When choosing the right button for an action, consider + the level of emphasis each button type provides. + +KivyMD provides the following button classes for use: .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/buttons.png :align: center -`KivyMD` provides the following button classes for use: +1. Elevated button +2. Filled button +3. Filled tonal button +4. Outlined button +5. Text button +6. Icon button +7. Segmented button +8. Floating action button (FAB) +9. Extended FAB -- MDIconButton_ -- MDFloatingActionButton_ -- MDFlatButton_ -- MDRaisedButton_ -- MDRectangleFlatButton_ -- MDRectangleFlatIconButton_ -- MDRoundFlatButton_ -- MDRoundFlatIconButton_ -- MDFillRoundFlatButton_ -- MDFillRoundFlatIconButton_ -- MDTextButton_ -- MDFloatingActionButtonSpeedDial_ +Common buttons +============== -.. MDIconButton: -MDIconButton ------------- +.. rubric:: Buttons help people take action, such as sending an email, sharing + a document, or liking a comment. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/common-buttons.png + :align: center + +1. Elevated button +2. Filled button +3. Filled tonal button +4. Outlined button +5. Text button + +Elevated_ +Filled_ +Tonal_ +Outlined_ +Text_ + +.. Elevated: + +Elevated +-------- .. tabs:: @@ -45,17 +63,23 @@ MDIconButton KV = ''' MDScreen: + md_bg_color: app.theme_cls.surfaceColor - MDIconButton: - icon: "language-python" + MDButton: + style: "elevated" pos_hint: {"center_x": .5, "center_y": .5} + + MDButtonIcon: + icon: "plus" + + MDButtonText: + text: "Elevated" ''' class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" + self.theme_cls.primary_palette = "Green" return Builder.load_string(KV) @@ -66,343 +90,442 @@ MDIconButton .. code-block:: python from kivymd.app import MDApp - from kivymd.uix.button import MDIconButton + from kivymd.uix.button import MDButton, MDButtonIcon, MDButtonText from kivymd.uix.screen import MDScreen class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" + self.theme_cls.primary_palette = "Green" return ( MDScreen( - MDIconButton( - icon="language-python", + MDButton( + MDButtonIcon( + icon="plus", + ), + MDButtonText( + text="Elevated", + ), + style="elevated", pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) + ), + md_bg_color=self.theme_cls.surfaceColor, ) ) Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon-button.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/elevated-button.gif :align: center -The :class:`~MDIconButton.icon` parameter must have the name of the icon -from ``kivymd/icon_definitions.py`` file. - -You can also use custom icons: +Common buttons can contain an icon or be without an icon: .. code-block:: kv - MDIconButton: - icon: "kivymd/images/logo/kivymd-icon-256.png" + MDButton: + style: "elevated" + text: "Elevated" -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon-custom-button.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/elevated-without-icon-button.png :align: center -By default, :class:`~MDIconButton` button has a size ``(dp(48), dp (48))``. -Use :class:`~BaseButton.icon_size` attribute to resize the button: +.. Filled: + +Filled +------ .. code-block:: kv - MDIconButton: - icon: "android" - icon_size: "64sp" + MDButton: + style: "filled" -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon-button-user-font-size.png + MDButtonText: + text: "Filled" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/filled-button.gif :align: center -By default, the color of :class:`~MDIconButton` -(depending on the style of the application) is black or white. -You can change the color of :class:`~MDIconButton` as the text color -of :class:`~kivymd.uix.label.MDLabel`, substituting ``theme_icon_color`` for -``theme_text_color`` and ``icon_color`` for ``text_color``. +.. Tonal: + +Tonal +----- .. code-block:: kv - MDIconButton: - icon: "android" - theme_icon_color: "Custom" - icon_color: app.theme_cls.primary_color + MDButton: + style: "tonal" -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon-button-theme-text-color.png + MDButtonText: + text: "Tonal" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tonal-button.gif :align: center -.. MDFloatingActionButton: -MDFloatingActionButton ----------------------- +.. Outlined: -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-floating-action-button.png - :align: center - -The above parameters for :class:`~MDIconButton` apply -to :class:`~MDFloatingActionButton`. - -To change :class:`~MDFloatingActionButton` background, use the -``md_bg_color`` parameter: +Outlined +-------- .. code-block:: kv - MDFloatingActionButton: - icon: "android" - md_bg_color: app.theme_cls.primary_color + MDButton: + style: "outlined" -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-floating-action-button-md-bg-color.png + MDButtonText: + text: "Outlined" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/outlined-button.gif :align: center -Material design style 3 +.. Text: + +Text +---- + +.. code-block:: kv + + MDButton: + style: "text" + + MDButtonText: + text: "Text" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-button.gif + :align: center + +Customization of buttons +======================== + +Text positioning and button size +-------------------------------- + +.. code-block:: kv + + MDButton: + style: "tonal" + theme_width: "Custom" + height: "56dp" + size_hint_x: .5 + + MDButtonIcon: + x: text.x - (self.width + dp(10)) + icon: "plus" + + MDButtonText: + id: text + text: "Tonal" + pos_hint: {"center_x": .5, "center_y": .5} + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/positioning-size-button.png + :align: center + +Font of the button text ----------------------- +.. code-block:: kv + + MDButton: + style: "filled" + + MDButtonIcon: + icon: "plus" + + MDButtonText: + text: "Filled" + font_style: "Title" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-style-button-text.png + :align: center + +.. code-block:: kv + + MDButton: + style: "elevated" + + MDButtonText: + text: "Elevated" + theme_font_name: "Custom" + font_name: "path/to/font.ttf" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-name-button-text.png + :align: center + +Custom button color +------------------- + +.. code-block:: kv + + MDButton: + style: "elevated" + theme_shadow_color: "Custom" + shadow_color: "red" + + MDButtonIcon: + icon: "plus" + theme_icon_color: "Custom" + icon_color: "green" + + MDButtonText: + text: "Elevated" + theme_text_color: "Custom" + text_color: "red" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/custom-color-button.png + :align: center + +Icon buttons +============ + +.. rubric:: Use icon buttons when a compact button is required, such as in a + toolbar or image list. There are two types of icon buttons: standard and + contained. + +.. seealso:: + + `Material Design spec, Icon buttons `_ + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-buttons.png + :align: center + +1. Standard icon button +2. Contained icon button (including filled, filled tonal, and outlined styles) + +StandardIcon_ +FilledIcon_ +TonalIcon_ +OutlinedIcon_ + +.. StandardIcon: + +StandardIcon +------------ + +.. code-block:: kv + + MDIconButton: + icon: "heart-outline" + style: "standard" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-standard.gif + :align: center + +.. FilledIcon: + +FilledIcon +---------- + +.. code-block:: kv + + MDIconButton: + icon: "heart-outline" + style: "filled" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-filled.gif + :align: center + +.. TonalIcon: + +TonalIcon +--------- + +.. code-block:: kv + + MDIconButton: + icon: "heart-outline" + style: "tonal" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-tonal.gif + :align: center + +.. OutlinedIcon: + +OutlinedIcon +------------ + +.. code-block:: kv + + MDIconButton: + icon: "heart-outline" + style: "outlined" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-outlined.gif + :align: center + +Custom icon size +---------------- + +.. code-block:: kv + + MDIconButton: + icon: "heart-outline" + style: "tonal" + theme_font_size: "Custom" + font_size: "48sp" + radius: [self.height / 2, ] + size_hint: None, None + size: "84dp", "84dp" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-size.png + :align: center + +Custom button color +------------------- + +.. code-block:: kv + + MDIconButton: + icon: "heart-outline" + style: "tonal" + theme_bg_color: "Custom" + md_bg_color: "brown" + theme_icon_color: "Custom" + icon_color: "white" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-color.png + :align: center + +FAB buttons +=========== + +.. rubric:: The FAB represents the most important action on a screen. + It puts key actions within reach. + +.. seealso:: + + `Material Design spec, FAB buttons `_ + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-buttons.png + :align: center + +1. Standard FAB +2. Small FAB +3. Large FAB + +There are three sizes of floating action buttons: FAB, small FAB, and large FAB: + +Standard_ +Small_ +Large_ + +.. Standard: + +Standard +-------- + +.. code-block:: kv + + MDFabButton: + icon: "pencil-outline" + style: "standard" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-standard.gif + :align: center + +.. Small: + +Small +----- + +.. code-block:: kv + + MDFabButton: + icon: "pencil-outline" + style: "small" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-small.png + :align: center + +.. Large: + +Large +----- + +.. code-block:: kv + + MDFabButton: + icon: "pencil-outline" + style: "large" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-large.gif + :align: center + +Additional color mappings +------------------------- + +FABs can use other combinations of container and icon colors. The color +mappings below provide the same legibility and functionality as the default, +so the color mapping you use depends on style alone. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-color-mapping.png + :align: center + +1. Surface +2. Secondary +3. Tertiary + .. code-block:: python from kivy.lang import Builder from kivymd.app import MDApp - from kivymd.uix.button import MDFloatingActionButton + from kivymd.uix.button import MDFabButton KV = ''' MDScreen: - md_bg_color: "#f7f2fa" + md_bg_color: app.theme_cls.surfaceColor MDBoxLayout: id: box - spacing: "56dp" adaptive_size: True + spacing: "32dp" pos_hint: {"center_x": .5, "center_y": .5} ''' class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - self.theme_cls.material_style = "M3" + self.theme_cls.primary_palette = "Green" return Builder.load_string(KV) def on_start(self): - data = { - "standard": {"md_bg_color": "#fefbff", "text_color": "#6851a5"}, - "small": {"md_bg_color": "#e9dff7", "text_color": "#211c29"}, - "large": {"md_bg_color": "#f8d7e3", "text_color": "#311021"}, + styles = { + "standard": "surface", + "small": "secondary", + "large": "tertiary", } - for type_button in data.keys(): + for style in styles.keys(): self.root.ids.box.add_widget( - MDFloatingActionButton( - icon="pencil", - type=type_button, - theme_icon_color="Custom", - md_bg_color=data[type_button]["md_bg_color"], - icon_color=data[type_button]["text_color"], + MDFabButton( + style=style, icon="pencil-outline", color_map=styles[style] ) ) Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-floating-action-button-m3.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-color-mapping.png :align: center -.. MDFlatButton: -MDFlatButton ------------- +Extended FAB +============ -To change the text color of: class:`~MDFlatButton` use the ``text_color`` parameter: +.. rubric:: Extended floating action buttons (extended FABs) help people take + primary actions. They're wider than FABs to accommodate a text label and + larger target area. -.. code-block:: kv +.. seealso:: - MDFlatButton: - text: "MDFlatButton" - theme_text_color: "Custom" - text_color: "orange" + `Material Design spec, FAB extended buttons `_ -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-flat-button-text-color.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/extended-fab-button.png :align: center -Or use markup: +1. Extended FAB with both icon and label text +2. Extended FAB without icon -.. code-block:: kv - - MDFlatButton: - text: "[color=#00ffcc]MDFlatButton[/color]" - -To specify the font size and font name, use the parameters as in the usual -`Kivy` buttons: - -.. code-block:: kv - - MDFlatButton: - text: "MDFlatButton" - font_size: "18sp" - font_name: "path/to/font" - -.. MDRaisedButton: -MDRaisedButton --------------- - -This button is similar to the :class:`~MDFlatButton` button except that you -can set the background color for :class:`~MDRaisedButton`: - -.. code-block:: kv - - MDRaisedButton: - text: "MDRaisedButton" - md_bg_color: "red" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-raised-button.png - :align: center - -.. MDRectangleFlatButton: -MDRectangleFlatButton ---------------------- - -.. code-block:: kv - - MDRectangleFlatButton: - text: "MDRectangleFlatButton" - theme_text_color: "Custom" - text_color: "white" - line_color: "red" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-rectangle-flat-button-md-bg-color.png - :align: center - -.. MDRectangleFlatIconButton: -MDRectangleFlatIconButton -------------------------- - -Button parameters :class:`~MDRectangleFlatIconButton` are the same as -button :class:`~MDRectangleFlatButton`, with the addition of the -``theme_icon_color`` and ``icon_color`` parameters as for :class:`~MDIconButton`. - -.. code-block:: kv - - MDRectangleFlatIconButton: - icon: "android" - text: "MDRectangleFlatIconButton" - theme_text_color: "Custom" - text_color: "white" - line_color: "red" - theme_icon_color: "Custom" - icon_color: "orange" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-rectangle-flat-icon-button-custom.png - :align: center - -Without border --------------- - -.. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.screen import MDScreen - from kivymd.uix.button import MDRectangleFlatIconButton - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return ( - MDScreen( - MDRectangleFlatIconButton( - text="MDRectangleFlatIconButton", - icon="language-python", - line_color=(0, 0, 0, 0), - pos_hint={"center_x": .5, "center_y": .5}, - ) - ) - ) - - - Example().run() - -.. code-block:: kv - - MDRectangleFlatIconButton: - text: "MDRectangleFlatIconButton" - icon: "language-python" - line_color: 0, 0, 0, 0 - pos_hint: {"center_x": .5, "center_y": .5} - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-rectangle-flat-icon-button-without-border.png - :align: center - -.. MDRoundFlatButton: -MDRoundFlatButton ------------------ - -.. code-block:: kv - - MDRoundFlatButton: - text: "MDRoundFlatButton" - text_color: "white" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-round-flat-button-text-color.png - :align: center - -.. MDRoundFlatIconButton: -MDRoundFlatIconButton ---------------------- - -Button parameters :class:`~MDRoundFlatIconButton` are the same as -button :class:`~MDRoundFlatButton`, with the addition of the -``theme_icon_color`` and ``icon_color`` parameters as for :class:`~MDIconButton`: - -.. code-block:: kv - - MDRoundFlatIconButton: - text: "MDRoundFlatIconButton" - icon: "android" - text_color: "white" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-round-flat-icon-button.png - :align: center - -.. MDFillRoundFlatButton: -MDFillRoundFlatButton ---------------------- - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-fill-round-flat-button.png - :align: center - -Button parameters :class:`~MDFillRoundFlatButton` are the same as -button :class:`~MDRaisedButton`. - -.. MDFillRoundFlatIconButton: -MDFillRoundFlatIconButton -------------------------- - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-fill-round-flat-icon-button.png - :align: center - -Button parameters :class:`~MDFillRoundFlatIconButton` are the same as -button :class:`~MDRaisedButton`, with the addition of the -``theme_icon_color`` and ``icon_color`` parameters as for :class:`~MDIconButton`. - -.. note:: Notice that the width of the :class:`~MDFillRoundFlatIconButton` - button matches the size of the button text. - -.. MDTextButton: -MDTextButton ------------- - -.. code-block:: kv - - MDTextButton: - text: "MDTextButton" - custom_color: "white" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-text-button.png - :align: center - -.. MDFloatingActionButtonSpeedDial: -MDFloatingActionButtonSpeedDial -------------------------------- - -.. Note:: See the full list of arguments in the class - :class:`~MDFloatingActionButtonSpeedDial`. +With icon +--------- .. code-block:: python @@ -412,291 +535,173 @@ MDFloatingActionButtonSpeedDial KV = ''' MDScreen: + md_bg_color: app.theme_cls.surfaceColor + on_touch_down: + if not btn.collide_point(*args[1].pos): \\ + btn.fab_state = "expand" \\ + if btn.fab_state == "collapse" else "collapse" - MDFloatingActionButtonSpeedDial: - data: app.data - root_button_anim: True + MDExtendedFabButton: + id: btn + pos_hint: {"center_x": .5, "center_y": .5} + + MDExtendedFabButtonIcon: + icon: "pencil-outline" + + MDExtendedFabButtonText: + text: "Compose" ''' class Example(MDApp): - data = { - 'Python': 'language-python', - 'PHP': 'language-php', - 'C++': 'language-cpp', - } - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" + self.theme_cls.primary_palette = "Green" return Builder.load_string(KV) Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/extended-fab-button-icon.gif :align: center -Or without KV Language: - -.. tabs:: - - .. tab:: Imperative python style - - .. code-block:: python - - from kivymd.uix.screen import MDScreen - from kivymd.app import MDApp - from kivymd.uix.button import MDFloatingActionButtonSpeedDial - - - class Example(MDApp): - data = { - 'Python': 'language-python', - 'PHP': 'language-php', - 'C++': 'language-cpp', - } - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - screen = MDScreen() - speed_dial = MDFloatingActionButtonSpeedDial() - speed_dial.data = self.data - speed_dial.root_button_anim = True - screen.add_widget(speed_dial) - return screen - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.uix.screen import MDScreen - from kivymd.app import MDApp - from kivymd.uix.button import MDFloatingActionButtonSpeedDial - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return ( - MDScreen( - MDFloatingActionButtonSpeedDial( - data={ - 'Python': 'language-python', - 'PHP': 'language-php', - 'C++': 'language-cpp', - }, - root_button_anim=True, - ) - ) - ) - - - Example().run() - -You can use various types of animation of labels for buttons on the stack: +Without icon +------------ .. code-block:: kv - MDFloatingActionButtonSpeedDial: - hint_animation: True + MDExtendedFabButton: + fab_state: "expand" -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-hint.gif + MDExtendedFabButtonText: + text: "Compose" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/extended-fab-button-without-icon.png :align: center -You can set your color values for background, text of buttons etc: +API break +========= + +1.2.0 version +------------- .. code-block:: kv - MDFloatingActionButtonSpeedDial: - hint_animation: True - bg_hint_color: app.theme_cls.primary_dark + MDFloatingActionButton: + icon: "plus" -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-hint-color.png - :align: center +.. code-block:: kv -Binds to individual buttons ---------------------------- + MDRoundFlatButton: + text: "Outlined" -.. tabs:: +.. code-block:: kv - .. tab:: Declarative KV style + MDRoundFlatIconButton: + text: "Outlined with icon" + icon: "plus" - .. code-block:: python +.. code-block:: kv - from kivy.lang import Builder - from kivy.properties import DictProperty + MDFillRoundFlatButton + text: "Filled" - from kivymd.app import MDApp +.. code-block:: kv - KV = ''' - MDScreen: + MDFillRoundFlatIconButton + text: "Filled with icon" + icon: "plus" - MDFloatingActionButtonSpeedDial: - id: speed_dial - data: app.data - root_button_anim: True - hint_animation: True - ''' +2.0.0 version +------------- +.. note:: `MDFloatingActionButtonSpeedDial` type buttons were removed + in version `2.0.0`. - class Example(MDApp): - data = DictProperty() +.. code-block:: kv - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - self.data = { - 'Python': 'language-python', - 'JS': [ - 'language-javascript', - "on_press", lambda x: print("pressed JS"), - "on_release", lambda x: print( - "stack_buttons", - self.root.ids.speed_dial.stack_buttons - ) - ], - 'PHP': [ - 'language-php', - "on_press", lambda x: print("pressed PHP"), - "on_release", self.callback - ], - 'C++': [ - 'language-cpp', - "on_press", lambda x: print("pressed C++"), - "on_release", lambda x: self.callback() - ], - } - return Builder.load_string(KV) + MDFabButton: + icon: "plus" - def callback(self, *args): - print(args) +.. code-block:: kv + MDButton: + style: "outlined" - Example().run() + MDButtonText: + text: "Outlined" - .. tab:: Declarative python style +.. code-block:: kv - .. code-block:: python + MDButton: + style: "outlined" - from kivymd.app import MDApp - from kivymd.uix.button import MDFloatingActionButtonSpeedDial - from kivymd.uix.screen import MDScreen + MDButtonIcon: + icon: "plus" + MDButtonText: + text: "Outlined with icon" - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return ( - MDScreen( - MDFloatingActionButtonSpeedDial( - id="speed_dial", - hint_animation=True, - root_button_anim=True, - ) - ) - ) +.. code-block:: kv - def on_start(self): - data = { - "Python": "language-python", - "JS": [ - "language-javascript", - "on_press", lambda x: print("pressed JS"), - "on_release", lambda x: print( - "stack_buttons", - self.root.ids.speed_dial.stack_buttons - ) - ], - "PHP": [ - "language-php", - "on_press", lambda x: print("pressed PHP"), - "on_release", self.callback - ], - "C++": [ - "language-cpp", - "on_press", lambda x: print("pressed C++"), - "on_release", lambda x: self.callback() - ], - } - self.root.ids.speed_dial.data = data + MDButton: + style: "filled" - def callback(self, *args): - print(args) + MDButtonText: + text: "Filled" +.. code-block:: kv - Example().run() + MDButton: + style: "filled" + + MDButtonIcon: + icon: "plus" + + MDButtonText: + text: "Filled" """ from __future__ import annotations __all__ = ( - "BaseButton", "MDIconButton", - "MDFloatingActionButton", - "MDFlatButton", - "MDRaisedButton", - "MDRectangleFlatButton", - "MDRectangleFlatIconButton", - "MDRoundFlatButton", - "MDRoundFlatIconButton", - "MDFillRoundFlatButton", - "MDFillRoundFlatIconButton", - "MDTextButton", - "MDFloatingActionButtonSpeedDial", + "MDButtonText", + "MDButtonIcon", + "MDFabButton", + "MDExtendedFabButton", + "MDExtendedFabButtonIcon", + "MDExtendedFabButtonText", + "MDButton", + "BaseButton", + "BaseFabButton", ) import os -from typing import Union -from kivy.animation import Animation from kivy.clock import Clock -from kivy.core.window import Window from kivy.lang import Builder -from kivy.metrics import dp, sp +from kivy.metrics import dp from kivy.properties import ( - BooleanProperty, - BoundedNumericProperty, ColorProperty, - DictProperty, NumericProperty, - ObjectProperty, OptionProperty, - StringProperty, VariableListProperty, + ObjectProperty, DictProperty, ) -from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.floatlayout import FloatLayout -from kivy.weakproxy import WeakProxy +from kivy.uix.relativelayout import RelativeLayout +from kivymd.uix.label import MDIcon, MDLabel from kivymd import uix_path -from kivymd.color_definitions import text_colors -from kivymd.font_definitions import theme_font_styles -from kivymd.material_resources import ( - FLOATING_ACTION_BUTTON_M2_ELEVATION, - FLOATING_ACTION_BUTTON_M2_OFFSET, - FLOATING_ACTION_BUTTON_M3_ELEVATION, - FLOATING_ACTION_BUTTON_M3_OFFSET, - FLOATING_ACTION_BUTTON_M3_SOFTNESS, - RAISED_BUTTON_OFFSET, - RAISED_BUTTON_SOFTNESS, -) from kivymd.theming import ThemableBehavior from kivymd.uix.behaviors import ( CommonElevationBehavior, DeclarativeBehavior, RectangularRippleBehavior, - RotateBehavior, + BackgroundColorBehavior, ) -from kivymd.uix.label import MDLabel -from kivymd.uix.tooltip import MDTooltip +from kivymd.uix.behaviors.motion_behavior import MotionExtendedFabButtonBehavior +from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior with open( os.path.join(uix_path, "button", "button.kv"), encoding="utf-8" @@ -704,192 +709,137 @@ with open( Builder.load_string(kv_file.read()) -theme_text_color_options = ( - "Primary", - "Secondary", - "Hint", - "Error", - "Custom", - "ContrastParentBackground", -) +class BaseFabButton: + """ + Implements the basic properties for the + :class:`~MDExtendedFabButton` and :class:`~MDFabButton` classes. + + .. versionadded:: 2.0.0 + """ + + elevation_levels = DictProperty( + { + 0: 0, + 1: dp(4), + 2: dp(8), + 3: dp(12), + 4: dp(16), + 5: dp(18), + } + ) + """ + Elevation is measured as the distance between components along the z-axis + in density-independent pixels (dps). + + .. versionadded:: 1.2.0 + + :attr:`elevation_levels` is an :class:`~kivy.properties.DictProperty` + and defaults to `{0: dp(0), 1: dp(4), 2: dp(8), 3: dp(12), 4: dp(16), 5: dp(18)}`. + """ + + color_map = OptionProperty( + "surface", options=("surface", "secondary", "tertiary") + ) + """ + Additional color mappings. + + Available options are: 'surface', 'secondary', 'tertiary'. + + :attr:`color_map` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'secondary'`. + """ + + icon_color_disabled = ColorProperty(None) + """ + The icon color in (r, g, b, a) or string format of the list item when + the widget item is disabled. + + :attr:`icon_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + style = OptionProperty("standard", options=("standard", "small", "large")) + """ + Button type. + + Available options are: 'standard', 'small', 'large'. + + :attr:`style` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'standard'`. + """ + + fab_state = OptionProperty("collapse", options=("collapse", "expand")) + """ + The state of the button. + + Available options are: 'collapse' or 'expand'. + + :attr:`fab_state` is an :class:`~kivy.properties.OptionProperty` + and defaults to "collapse". + """ + + md_bg_color_disabled = ColorProperty(None) + """ + The background color in (r, g, b, a) or string format of the list item when + the list button is disabled. + + :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + radius = VariableListProperty( + [ + dp(16), + ], + length=4, + ) + """ + Canvas radius. + + :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` + and defaults to `[dp(16), dp(16), dp(16), dp(16)]`. + """ class BaseButton( DeclarativeBehavior, + BackgroundColorBehavior, RectangularRippleBehavior, - ThemableBehavior, ButtonBehavior, - AnchorLayout, + ThemableBehavior, + StateLayerBehavior, ): """ - Base class for all buttons. + Base button class. For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and - :class:`~kivymd.uix.behaviors.RectangularRippleBehavior` and - :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivy.uix.anchorlayout.AnchorLayout` + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.state_layer_behavior.StateLayerBehavior` classes documentation. """ - padding = VariableListProperty([dp(16), dp(8), dp(16), dp(8)]) + elevation_levels = DictProperty( + { + 0: 0, + 1: dp(4), + 2: dp(8), + 3: dp(12), + 4: dp(16), + 5: dp(18), + } + ) """ - Padding between the widget box and its children, in pixels: - [padding_left, padding_top, padding_right, padding_bottom]. + Elevation is measured as the distance between components along the z-axis + in density-independent pixels (dps). - padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. + .. versionadded:: 1.2.0 - .. versionadded:: 1.0.0 - - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` - and defaults to [16dp, 8dp, 16dp, 8dp]. - """ - - halign = OptionProperty("center", options=("left", "center", "right")) - """ - Horizontal anchor. - - .. versionadded:: 1.0.0 - - :attr:`anchor_x` is an :class:`~kivy.properties.OptionProperty` - and defaults to 'center'. It accepts values of 'left', 'center' or 'right'. - """ - - valign = OptionProperty("center", options=("top", "center", "bottom")) - """ - Vertical anchor. - - .. versionadded:: 1.0.0 - - :attr:`anchor_y` is an :class:`~kivy.properties.OptionProperty` - and defaults to 'center'. It accepts values of 'top', 'center' or 'bottom'. - """ - - text = StringProperty("") - """ - Button text. - - :attr:`text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - icon = StringProperty("") - """ - Button icon. - - :attr:`icon` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - font_style = OptionProperty("Body1", options=theme_font_styles) - """ - Button text font style. - - Available vanilla font_style are: `'H1'`, `'H2'`, `'H3'`, `'H4'`, `'H5'`, - `'H6'`, `'Subtitle1'`, `'Subtitle2'`, `'Body1'`, `'Body2'`, `'Button'`, - `'Caption'`, `'Overline'`, `'Icon'`. - - :attr:`font_style` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Body1'`. - """ - - theme_text_color = OptionProperty(None, options=theme_text_color_options) - """ - Button text type. Available options are: (`"Primary"`, `"Secondary"`, - `"Hint"`, `"Error"`, `"Custom"`, `"ContrastParentBackground"`). - - :attr:`theme_text_color` is an :class:`~kivy.properties.OptionProperty` - and defaults to `None` (set by button class). - """ - - theme_icon_color = OptionProperty(None, options=theme_text_color_options) - """ - Button icon type. Available options are: (`"Primary"`, `"Secondary"`, - `"Hint"`, `"Error"`, `"Custom"`, `"ContrastParentBackground"`). - - .. versionadded:: 1.0.0 - - :attr:`theme_icon_color` is an :class:`~kivy.properties.OptionProperty` - and defaults to `None` (set by button subclass). - """ - - text_color = ColorProperty(None) - """ - Button text color in (r, g, b, a) or string format. - - :attr:`text_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - icon_color = ColorProperty(None) - """ - Button icon color in (r, g, b, a) or string format. - - :attr:`icon_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - font_name = StringProperty() - """ - Button text font name. - - :attr:`font_name` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - font_size = NumericProperty("14sp") - """ - Button text font size. - - :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` - and defaults to `14sp`. - """ - - icon_size = NumericProperty() - """ - Icon font size. - Use this parameter as the font size, that is, in sp units. - - .. versionadded:: 1.0.0 - - :attr:`icon_size` is a :class:`~kivy.properties.NumericProperty` - and defaults to `None`. - """ - - line_width = NumericProperty(1) - """ - Line width for button border. - - :attr:`line_width` is a :class:`~kivy.properties.NumericProperty` - and defaults to `1`. - """ - - line_color = ColorProperty(None) - """ - Line color in (r, g, b, a) or string format for button border. - - :attr:`line_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - line_color_disabled = ColorProperty(None) - """ - Disabled line color in (r, g, b, a) or string format for button border. - - .. versionadded:: 1.0.0 - - :attr:`line_color_disabled` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - md_bg_color = ColorProperty(None) - """ - Button background color in (r, g, b, a) or string format. - - :attr:`md_bg_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. + :attr:`elevation_levels` is an :class:`~kivy.properties.DictProperty` + and defaults to `{0: dp(0), 1: dp(4), 2: dp(8), 3: dp(12), 4: dp(16), 5: dp(18)}`. """ md_bg_color_disabled = ColorProperty(None) @@ -901,1467 +851,439 @@ class BaseButton( and defaults to `None`. """ - disabled_color = ColorProperty(None) + shadow_radius = VariableListProperty([0, 0, 0, 0]) """ - The color of the text and icon when the button is disabled, - in (r, g, b, a) or string format. + Button shadow radius. - .. versionadded:: 1.0.0 + :attr:`shadow_radius` is an :class:`~kivy.properties.VariableListProperty` + and defaults to `[0, 0, 0, 0]`. + """ - :attr:`disabled_color` is a :class:`~kivy.properties.ColorProperty` + md_bg_color = ColorProperty(None) + """ + Button background color in (r, g, b, a) or string format. + + :attr:`md_bg_color` is a :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ - rounded_button = BooleanProperty(False) + line_color = ColorProperty(None) """ - Should the button have fully rounded corners (e.g. like M3 buttons)? + Outlined color. - .. versionadded:: 1.0.0 - - :attr:`rounded_button` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. + :attr:`line_color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. """ - # Note - _radius must be > 0 to avoid rendering issues. - _radius = BoundedNumericProperty(dp(4), min=0.0999, errorvalue=0.1) - # Properties used for rendering. - _disabled_color = ColorProperty([0.0, 0.0, 0.0, 0.0]) - _md_bg_color = ColorProperty([0.0, 0.0, 0.0, 0.0]) - _md_bg_color_disabled = ColorProperty([0.0, 0.0, 0.0, 0.0]) - _line_color = ColorProperty([0.0, 0.0, 0.0, 0.0]) - _line_color_disabled = ColorProperty([0.0, 0.0, 0.0, 0.0]) - _theme_text_color = OptionProperty(None, options=theme_text_color_options) - _theme_icon_color = OptionProperty(None, options=theme_text_color_options) - _text_color = ColorProperty(None) - _icon_color = ColorProperty(None) + line_width = NumericProperty(1) + """ + Line width for button border. - # Defaults which can be overridden in subclasses - _min_width = NumericProperty(dp(64)) - _min_height = NumericProperty(dp(36)) + :attr:`line_width` is a :class:`~kivy.properties.NumericProperty` + and defaults to `1`. + """ - # Default colors - set to None to use primary theme colors - _default_md_bg_color = [0.0, 0.0, 0.0, 0.0] - _default_md_bg_color_disabled = [0.0, 0.0, 0.0, 0.0] - _default_line_color = [0.0, 0.0, 0.0, 0.0] - _default_line_color_disabled = [0.0, 0.0, 0.0, 0.0] - _default_theme_text_color = StringProperty("Primary") - _default_theme_icon_color = StringProperty("Primary") - _default_text_color = ColorProperty(None) - _default_icon_color = ColorProperty(None) + def on_press(self, *args) -> None: + """Fired when the button is pressed.""" - _animation_fade_bg = ObjectProperty(None, allownone=True) + self._on_press(args) + + def on_release(self, *args) -> None: + """ + Fired when the button is released + (i.e. the touch/click that pressed the button goes away). + """ + + self._on_release(args) + + +class MDButton(BaseButton, CommonElevationBehavior, RelativeLayout): + """ + Base class for all buttons. + + .. versionadded:: 2.2.0 + + For more information, see in the + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~BaseButton` and + :class:`~kivy.uix.relativelayout.RelativeLayout` + classes documentation. + """ + + style = OptionProperty( + "elevated", options=("elevated", "filled", "tonal", "outlined", "text") + ) + """ + Button type. + + Available options are: 'filled', 'elevated', 'outlined', 'tonal', 'text'. + + :attr:`style` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'elevated'`. + """ + + radius = VariableListProperty( + [ + dp(20), + ] + ) + """ + Button radius. + + :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` + and defaults to `[dp(20), dp(20), dp(20), dp(20)]`. + """ + + # kivymd.uix.button.button.MDButtonIcon object. + _button_icon = ObjectProperty() + # kivymd.uix.button.button.MDButtonText object. + _button_text = ObjectProperty() + + _icon_left_pad = dp(16) + _spacing_between_icon_text = dp(10) + _text_right_pad = dp(24) + _text_left_pad = dp(24) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.theme_cls.bind( - primary_palette=self.set_all_colors, - theme_style=self.set_all_colors, - ) - self.bind( - md_bg_color=self.set_button_colors, - md_bg_color_disabled=self.set_button_colors, - line_color=self.set_button_colors, - line_color_disabled=self.set_button_colors, - theme_text_color=self.set_text_color, - text_color=self.set_text_color, - theme_icon_color=self.set_icon_color, - icon_color=self.set_icon_color, - disabled_color=self.set_disabled_color, - rounded_button=self.set_radius, - height=self.set_radius, - ) - Clock.schedule_once(self.set_all_colors) - Clock.schedule_once(self.set_radius) + Clock.schedule_once(self.adjust_width, 0.2) + Clock.schedule_once(self.adjust_pos, 0.2) - def set_disabled_color(self, *args): - """ - Sets the color for the icon, text and line of the button when button - is disabled. - """ + def adjust_pos(self, *args) -> None: + """Adjusts the pos of the button according to the content.""" - if self.disabled: - disabled_color = ( - self.disabled_color - if self.disabled_color - else self.theme_cls.disabled_hint_text_color + if self._button_icon and self._button_text: + self._button_text.x = ( + self._button_icon.x + + self._spacing_between_icon_text + + self._icon_left_pad + + dp(2) ) - self._disabled_color = disabled_color - # Button icon color. - if "lbl_ic" in self.ids: - self.ids.lbl_ic.disabled_color = disabled_color - # Button text color. - if "lbl_txt" in self.ids: - self.ids.lbl_txt.disabled_color = disabled_color - else: - self._disabled_color = self._line_color + elif not self._button_icon and self._button_text: + self._button_text.x = self._text_left_pad - def set_all_colors(self, *args) -> None: - """Set all button colours.""" + def adjust_width(self, *args) -> None: + """Adjusts the width of the button according to the content.""" - self.set_button_colors() - self.set_text_color() - self.set_icon_color() - - def set_button_colors(self, *args) -> None: - """Set all button colours (except text/icons).""" - - # Set main color - _md_bg_color = ( - self.md_bg_color - or self._default_md_bg_color - or self.theme_cls.primary_color - ) - - # Set disabled color - _md_bg_color_disabled = ( - self.md_bg_color_disabled - or ( - [sum(self.md_bg_color[0:3]) / 3.0] * 3 - + [0.38 if self.theme_cls.theme_style == "Light" else 0.5] - if self.md_bg_color - else None - ) - or self._default_md_bg_color_disabled - or self.theme_cls.disabled_primary_color - ) - - # Set line color - _line_color = ( - self.line_color - or self._default_line_color - or self.theme_cls.primary_color - ) - - # Set disabled line color - _line_color_disabled = ( - self.line_color_disabled - or ( - [sum(self.line_color[0:3]) / 3.0] * 3 - + [0.38 if self.theme_cls.theme_style == "Light" else 0.5] - if self.line_color - else None - ) - or self._default_line_color_disabled - or self.theme_cls.disabled_primary_color - ) - - if self.theme_cls.theme_style_switch_animation: - Animation( - _md_bg_color=_md_bg_color, - _md_bg_color_disabled=_md_bg_color_disabled, - _line_color=_line_color, - _line_color_disabled=_line_color_disabled, - d=self.theme_cls.theme_style_switch_animation_duration, - t="linear", - ).start(self) - else: - self._md_bg_color = _md_bg_color - self._md_bg_color_disabled = _md_bg_color_disabled - self._line_color = _line_color - self._line_color_disabled = _line_color_disabled - - def set_text_color(self, *args) -> None: - """ - Set _theme_text_color and _text_color based on defaults and options. - """ - - self._theme_text_color = ( - self.theme_text_color or self._default_theme_text_color - ) - if self._default_text_color == "PrimaryHue": - default_text_color = text_colors[self.theme_cls.primary_palette][ - self.theme_cls.primary_hue - ] - elif self._default_text_color == "Primary": - default_text_color = self.theme_cls.primary_color - else: - default_text_color = self.theme_cls.text_color - self._text_color = self.text_color or default_text_color - - def set_icon_color(self, *args) -> None: - """ - Set _theme_icon_color and _icon_color based on defaults and options. - """ - - self._theme_icon_color = ( - (self.theme_icon_color or self._default_theme_icon_color) - if not self.disabled - else "Custom" - ) - if self._default_icon_color == "PrimaryHue": - default_icon_color = text_colors[self.theme_cls.primary_palette][ - self.theme_cls.primary_hue - ] - elif self._default_icon_color == "Primary": - default_icon_color = self.theme_cls.primary_color - else: - default_icon_color = self.theme_cls.text_color - self._icon_color = self.icon_color or default_icon_color - - def set_radius(self, *args) -> None: - """ - Set the radius, if we are a rounded button, based on the - current height. - """ - - if self.rounded_button: - self._radius = self.height / 2 - - # Touch events that cause transparent buttons to fade to background - def on_touch_down(self, touch): - """ - Animates fade to background on press, for buttons with no - background color. - """ - - if touch.is_mouse_scrolling: - return False - elif not self.collide_point(touch.x, touch.y): - return False - elif self in touch.ud: - return False - elif self.disabled: - return False - else: - if self._md_bg_color[3] == 0.0: - self._animation_fade_bg = Animation( - duration=0.5, _md_bg_color=[0.0, 0.0, 0.0, 0.1] + if self._button_icon and self._button_text: + if self.theme_width == "Primary": + self.width = ( + self._button_icon.texture_size[0] + + self._button_text.texture_size[0] + + self._icon_left_pad + + self._spacing_between_icon_text + + self._text_right_pad + ) + elif not self._button_icon and self._button_text: + if self.theme_width == "Primary": + self.width = ( + self._button_text.texture_size[0] + + self._text_left_pad + + self._text_right_pad + ) + elif self._button_icon and not self._button_text: + if self.theme_width == "Primary": + self.width = ( + dp(48) + + self._button_icon.texture_size[0] + - self._spacing_between_icon_text ) - self._animation_fade_bg.start(self) - return super().on_touch_down(touch) - def on_touch_up(self, touch): - """Animates return to original background on touch release.""" - - if not self.disabled and self._animation_fade_bg: - self._animation_fade_bg.stop_property(self, "_md_bg_color") - self._animation_fade_bg = None - md_bg_color = ( - self.md_bg_color - or self._default_md_bg_color - or self.theme_cls.primary_color + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDButtonText): + self._button_text = widget + widget.bind( + text=lambda x, y: Clock.schedule_once(self.adjust_width, 0.2) ) - Animation(duration=0.05, _md_bg_color=md_bg_color).start(self) - return super().on_touch_up(touch) + widget._button = self + elif isinstance(widget, MDButtonIcon): + self._button_icon = widget + widget._button = self + if isinstance(widget, (MDButtonIcon, MDButtonText)): + return super().add_widget(widget) - def on_disabled(self, instance_button, disabled_value: bool) -> None: - if hasattr(super(), "on_disabled"): - if self.disabled is True: - Animation.cancel_all(self, "elevation") - super().on_disabled(instance_button, disabled_value) - Clock.schedule_once(self.set_disabled_color) + def set_properties_widget(self) -> None: + """Fired `on_release/on_press/on_enter/on_leave` events.""" + + super().set_properties_widget() + + if ( + self._state == self.state_hover + and self.focus_behavior + or self._state == self.state_press + ): + self._elevation_level = ( + 1 + if self.theme_elevation_level == "Primary" + else self.elevation_level + ) + self._shadow_softness = ( + 0 + if self.theme_shadow_softness == "Primary" + else self.shadow_softness + ) + + if not self.disabled: + if self._state == self.state_hover and self.focus_behavior: + if self.style == "elevated": + self.elevation_level = 2 + self.shadow_softness = 2 + elif self._state == self.state_press: + if self.style == "elevated": + self.elevation_level = 2 + self.shadow_softness = 2 + elif not self._state: + if self.style == "elevated": + self.elevation_level = 1 + self.shadow_softness = 0 -class ButtonElevationBehaviour(CommonElevationBehavior): +class MDButtonText(MDLabel): """ - Implements elevation behavior as well as the recommended down/disabled - colors for raised buttons. - - The minimum elevation for any raised button is `'1dp'`, - by default, set to `'2dp'`. - - The `_elevation_raised` is automatically computed and is set to - `self.elevation + 6` each time `self.elevation` is updated. - """ - - _elevation_raised = NumericProperty() - _anim_raised = ObjectProperty(None, allownone=True) - _default_elevation = 2 - - def __init__(self, **kwargs): - super().__init__(**kwargs) - if self.elevation == 0: - self.elevation = self._default_elevation - if hasattr(self, "radius"): - self.bind(_radius=self.setter("radius")) - Clock.schedule_once(self.create_anim_raised) - self.on_disabled(self, self.disabled) - - def create_anim_raised(self, *args) -> None: - if self.elevation: - self._elevation_raised = self.elevation - self._anim_raised = Animation(elevation=self.elevation + 1, d=0.15) - - def on_touch_down(self, touch): - if not self.disabled: - if touch.is_mouse_scrolling: - return False - if not self.collide_point(touch.x, touch.y): - return False - if self in touch.ud: - return False - if self._anim_raised and self.elevation: - self._anim_raised.start(self) - return super().on_touch_down(touch) - - def on_touch_up(self, touch): - if not self.disabled: - if self in touch.ud: - self.stop_elevation_anim() - return super().on_touch_up(touch) - return super().on_touch_up(touch) - - def stop_elevation_anim(self): - Animation.cancel_all(self, "elevation") - if self._anim_raised and self.elevation: - self.elevation = self._elevation_raised - - -class ButtonContentsText: - """Contents for :class:`~BaseButton` class consisting of a single label.""" - - -class ButtonContentsIcon: - """ - Contents for a round BaseButton consisting of an :class:`~MDIcon` class. - """ - - _min_width = NumericProperty(0) - - def on_text_color(self, instance_button, color: list) -> None: - """ - Set icon_color equal to text_color. - For backwards compatibility - can use text_color instead - of icon_color. - """ - - if color: - self.icon_color = color - - -class ButtonContentsIconText: - """ - Contents for :class:`~BaseButton` class consisting of a - :class:`~kivy.uix.boxlayout.BoxLayout` with an icon and a label. - """ - - padding = VariableListProperty([dp(12), dp(8), dp(16), dp(8)]) - """ - Padding between the widget box and its children, in pixels: - [padding_left, padding_top, padding_right, padding_bottom]. - - padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. - - .. versionadded:: 1.0.0 - - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` - and defaults to [12dp, 8dp, 16dp, 8dp]. - """ - - -# Old MD Button classes - - -class OldButtonIconMixin: - """Backwards-compatibility for icons.""" - - icon = StringProperty("android") - - def on_icon_color(self, instance_button, color: list) -> None: - """ - If we are setting an icon color, set theme_icon_color to Custom. - For backwards compatibility (before theme_icon_color existed). - """ - - if color and (self.theme_text_color == "Custom"): - self.theme_icon_color = "Custom" - - -class MDFlatButton(BaseButton, ButtonContentsText): - """ - A flat rectangular button with (by default) no border or background. - Text is the default text color. + The class implements the text for the :class:`~MDButton` class. For more information, see in the - :class:`~BaseButton` and :class:`~ButtonContentsText` + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + """ + + # kivymd.uix.button.button.MDButton object. + _button = ObjectProperty() + + +class MDButtonIcon(MDIcon): + """ + The class implements an icon for the :class:`~MDButton` class. + + For more information, see in the + :class:`~kivymd.uix.label.label.MDIcon` class documentation. + """ + + # kivymd.uix.button.button.MDButton object. + _button = ObjectProperty() + + +class MDIconButton(RectangularRippleBehavior, ButtonBehavior, MDIcon): + """ + Base class for icon buttons. + + For more information, see in the + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and + :class:`~kivy.uix.label.label.MDIcon` classes documentation. """ - padding = VariableListProperty([dp(8), dp(8), dp(8), dp(8)]) + style = OptionProperty( + "standard", options=("standard", "filled", "tonal", "outlined") + ) """ - Padding between the widget box and its children, in pixels: - [padding_left, padding_top, padding_right, padding_bottom]. + Button type. - padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. + .. versionadded:: 2.0.0 - .. versionadded:: 1.0.0 + Available options are: 'standard', 'filled', 'tonal', 'outlined'. - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` - and defaults to [8dp, 8dp, 8dp, 8dp]. - """ - - -class MDRaisedButton(BaseButton, ButtonElevationBehaviour, ButtonContentsText): - """ - A flat button with (by default) a primary color fill and matching - color text. - - For more information, see in the - :class:`~BaseButton` and - :class:`~ButtonElevationBehaviour` and - :class:`~ButtonContentsText` - classes documentation. - """ - - # FIXME: Move the underlying attributes to the :class:`~BaseButton` class. - # This applies to all classes of buttons that have similar attributes. - _default_md_bg_color = None - _default_md_bg_color_disabled = None - _default_theme_text_color = "Custom" - _default_text_color = "PrimaryHue" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.shadow_softness = RAISED_BUTTON_SOFTNESS - self.shadow_offset = RAISED_BUTTON_OFFSET - # self.shadow_radius = self._radius * 2 - - -class MDRectangleFlatButton(BaseButton, ButtonContentsText): - """ - A flat button with (by default) a primary color border and primary - color text. - - For more information, see in the - :class:`~BaseButton` and :class:`~ButtonContentsText` - classes documentation. - """ - - _default_line_color = None - _default_line_color_disabled = None - _default_theme_text_color = "Custom" - _default_text_color = "Primary" - - -class MDRectangleFlatIconButton( - BaseButton, OldButtonIconMixin, ButtonContentsIconText -): - """ - A flat button with (by default) a primary color border, primary color text - and a primary color icon on the left. - - For more information, see in the - :class:`~BaseButton` and - :class:`~OldButtonIconMixin` and - :class:`~ButtonContentsIconText` - classes documentation. - """ - - _default_line_color = None - _default_line_color_disabled = None - _default_theme_text_color = "Custom" - _default_theme_icon_color = "Custom" - _default_text_color = "Primary" - _default_icon_color = "Primary" - - -class MDRoundFlatButton(BaseButton, ButtonContentsText): - """ - A flat button with (by default) fully rounded corners, a primary - color border and primary color text. - - For more information, see in the - :class:`~BaseButton` and :class:`~ButtonContentsText` - classes documentation. - """ - - _default_line_color = None - _default_line_color_disabled = None - _default_theme_text_color = "Custom" - _default_text_color = "Primary" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.rounded_button = True - - -class MDRoundFlatIconButton( - BaseButton, OldButtonIconMixin, ButtonContentsIconText -): - """ - A flat button with (by default) rounded corners, a primary color border, - primary color text and a primary color icon on the left. - - For more information, see in the - :class:`~BaseButton` and - :class:`~OldButtonIconMixin` and - :class:`~ButtonContentsIconText` - classes documentation. - """ - - _default_line_color = None - _default_line_color_disabled = None - _default_theme_text_color = "Custom" - _default_theme_icon_color = "Custom" - _default_text_color = "Primary" - _default_icon_color = "Primary" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.rounded_button = True - - -class MDFillRoundFlatButton(BaseButton, ButtonContentsText): - """ - A flat button with (by default) rounded corners, a primary color fill - and primary color text. - - For more information, see in the - :class:`~BaseButton` and :class:`~ButtonContentsText` - classes documentation. - """ - - _default_md_bg_color = None - _default_md_bg_color_disabled = None - _default_theme_text_color = "Custom" - _default_text_color = "PrimaryHue" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.rounded_button = True - - -class MDFillRoundFlatIconButton( - BaseButton, OldButtonIconMixin, ButtonContentsIconText -): - """ - A flat button with (by default) rounded corners, a primary color fill, - primary color text and a primary color icon on the left. - - For more information, see in the - :class:`~BaseButton` and - :class:`~OldButtonIconMixin` and - :class:`~ButtonContentsIconText` - classes documentation. - """ - - _default_md_bg_color = None - _default_md_bg_color_disabled = None - _default_theme_text_color = "Custom" - _default_theme_icon_color = "Custom" - _default_text_color = "PrimaryHue" - _default_icon_color = "PrimaryHue" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.rounded_button = True - - -class MDIconButton(BaseButton, OldButtonIconMixin, ButtonContentsIcon): - """ - A simple rounded icon button. - - For more information, see in the - :class:`~BaseButton` and - :class:`~OldButtonIconMixin` and - :class:`~ButtonContentsIcon` classes documentation. - """ - - icon = StringProperty("checkbox-blank-circle") - """ - Button icon. - - :attr:`icon` is a :class:`~kivy.properties.StringProperty` - and defaults to `'checkbox-blank-circle'`. - """ - - _min_width = NumericProperty(0) - _default_icon_pad = max(dp(48) - sp(24), 0) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.rounded_button = True - # FIXME: GraphicException: Invalid width value, must be > 0 - self.line_width = 0.001 - Clock.schedule_once(self.set_size) - - def set_size(self, interval: Union[int, float]) -> None: - """ - Sets the icon width/height based on the current `icon_size` - attribute, or the default value if it is zero. The icon size - is set to `(48, 48)` for an icon with the default font_size 24sp. - """ - diameter = self._default_icon_pad + (self.icon_size or sp(24)) - self.width = diameter - self.height = diameter - - -class MDFloatingActionButton( - BaseButton, OldButtonIconMixin, ButtonElevationBehaviour, ButtonContentsIcon -): - """ - Implementation - `FAB `_ - button. - - For more information, see in the - :class:`~BaseButton` and - :class:`~OldButtonIconMixin` and - :class:`~ButtonElevationBehaviour` and - :class:`~ButtonContentsIcon` classes documentation. - """ - - type = OptionProperty("standard", options=["small", "large", "standard"]) - """ - Type of M3 button. - - .. versionadded:: 1.0.0 - - Available options are: 'small', 'large', 'standard'. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-floating-action-button-types.png - :align: center - - :attr:`type` is an :class:`~kivy.properties.OptionProperty` + :attr:`style` is an :class:`~kivy.properties.OptionProperty` and defaults to `'standard'`. """ - _default_md_bg_color = None - _default_md_bg_color_disabled = None - _default_theme_icon_color = "Custom" - _default_icon_color = "PrimaryHue" + md_bg_color_disabled = ColorProperty(None) + """ + The background color in (r, g, b, a) or string format of the list item when + the list button is disabled. + + :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + _line_color = ColorProperty(None) + + def on_line_color(self, instance, value) -> None: + """Fired when the values of :attr:`line_color` change.""" + + if not self.disabled and self.theme_line_color == "Custom": + self._line_color = value + + +class MDFabButton( + BaseFabButton, + CommonElevationBehavior, + RectangularRippleBehavior, + ButtonBehavior, + MDIcon, +): + """ + Base class for FAB buttons. + + For more information, see in the + :class:`~BaseFabButton` and + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and + :class:`~kivymd.uix.label.label.MDIcon` + classes documentation. + """ + + def on_press(self, *args) -> None: + """Fired when the button is pressed.""" + + self._on_press(args) + + def on_release(self, *args) -> None: + """ + Fired when the button is released + (i.e. the touch/click that pressed the button goes away). + """ + + self._on_release(args) + + def set_properties_widget(self) -> None: + """Fired `on_release/on_press/on_enter/on_leave` events.""" + + super().set_properties_widget() + + if ( + self._state == self.state_hover + and self.focus_behavior + or self._state == self.state_press + ): + self._elevation_level = ( + 1 + if self.theme_elevation_level == "Primary" + else self.elevation_level + ) + self._shadow_softness = ( + 0 + if self.theme_shadow_softness == "Primary" + else self.shadow_softness + ) + + if not self.disabled: + if ( + self._state == self.state_hover and self.focus_behavior + ): + self.elevation_level = 1 + self.shadow_softness = 0 + elif self._state == self.state_press: + self.elevation_level = 2 + self.shadow_softness = 2 + elif not self._state: + self.elevation_level = 1 + self.shadow_softness = 0 + + +class MDExtendedFabButtonIcon(MDIcon): + """ + Implements an icon for the :class:`~MDExtendedFabButton` class. + + .. versionadded:: 2.0.0 + """ + + +class MDExtendedFabButtonText(MDLabel): + """ + Implements the text for the class :class:`~MDExtendedFabButton` class. + + .. versionadded:: 2.0.0 + """ + + +class MDExtendedFabButton( + DeclarativeBehavior, + ThemableBehavior, + MotionExtendedFabButtonBehavior, + CommonElevationBehavior, + StateLayerBehavior, + BaseFabButton, + ButtonBehavior, + RelativeLayout, +): + """ + Base class for Extended FAB buttons. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.motion_behavior.MotionExtendedFabButtonBehavior` and + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivymd.uix.behaviors.state_layer_behavior.StateLayerBehavior` and + :class:`~BaseFabButton` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and + :class:`~kivy.uix.relativelayout.RelativeLayout` + classes documentation. + + :Events: + `on_collapse` + Fired when the button is collapsed. + `on_expand` + Fired when the button is expanded. + """ + + elevation_levels = DictProperty( + { + 0: 0, + 1: dp(4), + 2: dp(8), + 3: dp(12), + 4: dp(16), + 5: dp(18), + } + ) + """ + Elevation is measured as the distance between components along the z-axis + in density-independent pixels (dps). + + .. versionadded:: 1.2.0 + + :attr:`elevation_levels` is an :class:`~kivy.properties.DictProperty` + and defaults to `{0: dp(0), 1: dp(4), 2: dp(8), 3: dp(12), 4: dp(16), 5: dp(18)}`. + """ + + _icon = ObjectProperty() + _label = ObjectProperty() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - # FIXME: GraphicException: Invalid width value, must be > 0 - self.line_width = 0.001 - self.theme_cls.bind(material_style=self.set_size_and_radius) - Clock.schedule_once(self.set_size) - Clock.schedule_once(self.set__radius) - Clock.schedule_once(self.set_font_size) - - def set_font_size(self, *args) -> None: - if self.theme_cls.material_style == "M3": - if self.type == "large": - self.icon_size = "36sp" - else: - self.icon_size = 0 - - def set__radius(self, *args) -> None: - if self.theme_cls.material_style == "M2": - self.shadow_radius = self.height / 2 - self.elevation = FLOATING_ACTION_BUTTON_M2_ELEVATION - self.shadow_offset = FLOATING_ACTION_BUTTON_M2_OFFSET - self.rounded_button = True - else: - self.shadow_softness = FLOATING_ACTION_BUTTON_M3_SOFTNESS - self.shadow_offset = FLOATING_ACTION_BUTTON_M3_OFFSET - self.elevation = FLOATING_ACTION_BUTTON_M3_ELEVATION - self.rounded_button = False - - if self.type == "small": - self._radius = dp(12) - elif self.type == "standard": - self._radius = dp(16) - elif self.type == "large": - self._radius = dp(28) - - self.shadow_radius = self._radius - - def set_size_and_radius(self, *args) -> None: - self.set_size(args) - self.set__radius(args) - - def set_size(self, *args) -> None: - if self.theme_cls.material_style == "M2": - self.size = dp(56), dp(56) - else: - if self.type == "small": - self.size = dp(40), dp(40) - elif self.type == "standard": - self.size = dp(56), dp(56) - elif self.type == "large": - self.size = dp(96), dp(96) - - def on_type(self, instance_md_floating_action_button, type: str) -> None: - self.set_size() - self.set_font_size() - - -class MDTextButton(ButtonBehavior, MDLabel): - """ - Text button class. - - For more information, see in the - :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivymd.uix.label.MDLabel` classes documentation. - """ - - color = ColorProperty(None) - """ - Button color in (r, g, b, a) or string format. - - :attr:`color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - color_disabled = ColorProperty(None) - """ - Button color disabled in (r, g, b, a) or string format. - - :attr:`color_disabled` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - _color = ColorProperty(None) # last current button text color - - def animation_label(self) -> None: - def set_default_state_label(*args): - Animation(opacity=1, d=0.1, t="in_out_cubic").start(self) - - anim = Animation(opacity=0.5, d=0.2, t="in_out_cubic") - anim.bind(on_complete=set_default_state_label) - anim.start(self) - - def on_press(self, *args): - self.animation_label() - return super().on_press(*args) - - def on_disabled(self, instance_button, disabled_value) -> None: - if disabled_value: - if not self.color_disabled: - self.color_disabled = self.theme_cls.disabled_hint_text_color - self._color = self.color - self.text_color = self.color_disabled - else: - self.text_color = self._color - - -# SpeedDial classes - - -class BaseFloatingBottomButton(MDFloatingActionButton, MDTooltip): - _canvas_width = NumericProperty(0) - _padding_right = NumericProperty(0) - _bg_color = ColorProperty(None) - - def set_size(self, interval: Union[int, float]) -> None: - self.width = "46dp" - self.height = "46dp" - - -class MDFloatingBottomButton(BaseFloatingBottomButton): - _bg_color = ColorProperty(None) - - -class MDFloatingRootButton(RotateBehavior, MDFloatingActionButton): - rotate_value_angle = NumericProperty(0) - - -class MDFloatingLabel(MDLabel): - bg_color = ColorProperty([0, 0, 0, 0]) - - -class MDFloatingActionButtonSpeedDial( - DeclarativeBehavior, ThemableBehavior, FloatLayout -): - """ - For more information, see in the - :class:`~kivy.uix.floatlayout.FloatLayout` class documentation. - - For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and - :class:`~kivymd.theming.ThemableBehavior` and - :class:`~kivy.uix.floatlayout.FloatLayout` - lasses documentation. - - :Events: - :attr:`on_open` - Called when a stack is opened. - :attr:`on_close` - Called when a stack is closed. - :attr:`on_press_stack_button` - Called at the on_press event for the stack button. - :attr:`on_release_stack_button` - Called at the on_press event for the stack button. - """ - - icon = StringProperty("plus") - """ - Root button icon name. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - icon: "pencil" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-icon.png - :align: center - - :attr:`icon` is a :class:`~kivy.properties.StringProperty` - and defaults to `'plus'`. - """ - - anchor = OptionProperty("right", option=["right"]) - """ - Stack anchor. Available options are: `'right'`. - - :attr:`anchor` is a :class:`~kivy.properties.OptionProperty` - and defaults to `'right'`. - """ - - label_text_color = ColorProperty(None) - """ - Color of floating text labels in (r, g, b, a) or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - label_text_color: "orange" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-label-text-color.png - :align: center - - :attr:`label_text_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - label_bg_color = ColorProperty([0, 0, 0, 0]) - """ - Background color of floating text labels in (r, g, b, a) or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - label_text_color: "black" - label_bg_color: "orange" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-label-bg-color.png - :align: center - - :attr:`label_bg_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 0]`. - """ - - label_radius = VariableListProperty([0], length=4) - """ - The radius of the background of floating text labels. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - label_text_color: "black" - label_bg_color: "orange" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-label-radius.png - :align: center - - :attr:`label_radius` is a :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 0]`. - """ - - data = DictProperty() - """ - Must be a dictionary. - - .. code-block:: python - - { - 'name-icon': 'Text label', - ..., - ..., - } - """ - - right_pad = BooleanProperty(False) - """ - If `True`, the background for the floating text label will increase by the - number of pixels specified in the :attr:`~right_pad_value` parameter. - - Works only if the :attr:`~hint_animation` parameter is set to `True`. - - .. rubric:: False - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - hint_animation: True - right_pad: False - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-right-pad.gif - :align: center - - .. rubric:: True - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - hint_animation: True - right_pad: True - right_pad_value: "10dp" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-right-pad-true.gif - :align: center - - :attr:`right_pad` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - right_pad_value = NumericProperty(0) - """ - See :attr:`~right_pad` parameter for more information. - - :attr:`right_pad_value` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0`. - """ - - root_button_anim = BooleanProperty(False) - """ - If ``True`` then the root button will rotate 45 degrees when the stack - is opened. - - :attr:`root_button_anim` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - opening_transition = StringProperty("out_cubic") - """ - The name of the stack opening animation type. - - :attr:`opening_transition` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_cubic'`. - """ - - closing_transition = StringProperty("out_cubic") - """ - The name of the stack closing animation type. - - :attr:`closing_transition` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_cubic'`. - """ - - opening_transition_button_rotation = StringProperty("out_cubic") - """ - The name of the animation type to rotate the root button when opening the - stack. - - :attr:`opening_transition_button_rotation` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_cubic'`. - """ - - closing_transition_button_rotation = StringProperty("out_cubic") - """ - The name of the animation type to rotate the root button when closing the - stack. - - :attr:`closing_transition_button_rotation` is a :class:`~kivy.properties.StringProperty` - and defaults to `'out_cubic'`. - """ - - opening_time = NumericProperty(0.5) - """ - Time required for the stack to go to: attr:`state` `'open'`. - - :attr:`opening_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - closing_time = NumericProperty(0.2) - """ - Time required for the stack to go to: attr:`state` `'close'`. - - :attr:`closing_time` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - opening_time_button_rotation = NumericProperty(0.2) - """ - Time required to rotate the root button 45 degrees during the stack - opening animation. - - :attr:`opening_time_button_rotation` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - closing_time_button_rotation = NumericProperty(0.2) - """ - Time required to rotate the root button 0 degrees during the stack - closing animation. - - :attr:`closing_time_button_rotation` is a :class:`~kivy.properties.NumericProperty` - and defaults to `0.2`. - """ - - state = OptionProperty("close", options=("close", "open")) - """ - Indicates whether the stack is closed or open. - Available options are: `'close'`, `'open'`. - - :attr:`state` is a :class:`~kivy.properties.OptionProperty` - and defaults to `'close'`. - """ - - bg_color_root_button = ColorProperty(None) - """ - Background color of root button in (r, g, b, a) or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - bg_color_root_button: "red" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-bg-color-root-button.png - :align: center - - :attr:`bg_color_root_button` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - bg_color_stack_button = ColorProperty(None) - """ - Background color of the stack buttons in (r, g, b, a) or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - bg_color_root_button: "red" - bg_color_stack_button: "red" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-bg-color-stack-button.png - :align: center - - :attr:`bg_color_stack_button` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - color_icon_stack_button = ColorProperty(None) - """ - The color icon of the stack buttons in (r, g, b, a) or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - bg_color_root_button: "red" - bg_color_stack_button: "red" - color_icon_stack_button: "white" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-color-icon-stack-button.png - :align: center - - :attr:`color_icon_stack_button` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - color_icon_root_button = ColorProperty(None) - """ - The color icon of the root button in (r, g, b, a) or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - bg_color_root_button: "red" - bg_color_stack_button: "red" - color_icon_stack_button: "white" - color_icon_root_button: self.color_icon_stack_button - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-color-icon-root-button.png - :align: center - - :attr:`color_icon_root_button` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - bg_hint_color = ColorProperty(None) - """ - Background color for the floating text of the buttons in (r, g, b, a) - or string format. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - bg_hint_color: "red" - hint_animation: True - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDFloatingActionButtonSpeedDial-bg-hint-color.png - :align: center - - :attr:`bg_hint_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - hint_animation = BooleanProperty(False) - """ - Whether to use button extension animation to display floating text. - - :attr:`hint_animation` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - stack_buttons = DictProperty() - - _label_pos_y_set = False - _anim_buttons_data = {} - _anim_labels_data = {} - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.register_event_type("on_open") - self.register_event_type("on_close") - self.register_event_type("on_press_stack_button") - self.register_event_type("on_release_stack_button") - Window.bind(on_resize=self._update_pos_buttons) - - def on_open(self, *args): - """Called when a stack is opened.""" - - def on_close(self, *args): - """Called when a stack is closed.""" - - def on_leave(self, instance_button: MDFloatingBottomButton) -> None: - """Called when the mouse cursor goes outside the button of stack.""" - - if self.state == "open": - for widget in self.children: - if isinstance(widget, MDFloatingLabel) and self.hint_animation: - Animation.cancel_all(widget) - for item in self.data.items(): - if widget.text in item: - Animation( - _canvas_width=0, - _padding_right=0, - d=self.opening_time, - t=self.opening_transition, - _elevation=0, - ).start(instance_button) - Animation( - opacity=0, d=0.1, t=self.opening_transition - ).start(widget) - - def on_enter(self, instance_button: MDFloatingBottomButton) -> None: - """Called when the mouse cursor is over a button from the stack.""" - - if self.state == "open": - for widget in self.children: - if isinstance(widget, MDFloatingLabel) and self.hint_animation: - Animation.cancel_all(widget) - for item in self.data.items(): - if widget.text in item: - Animation( - _canvas_width=widget.width + dp(24), - _padding_right=self.right_pad_value - if self.right_pad - else 0, - d=self.opening_time, - t=self.opening_transition, - ).start(instance_button) - if ( - instance_button.icon - == self.data[f"{widget.text}"] - or instance_button.icon - == self.data[f"{widget.text}"][0] - ): - Animation( - opacity=1, - d=self.opening_time, - t=self.opening_transition, - ).start(widget) - else: - Animation( - opacity=0, d=0.1, t=self.opening_transition - ).start(widget) - - def on_data(self, instance_speed_dial, data: dict) -> None: - """Creates a stack of buttons.""" - - def on_data(*args): - # Bottom buttons. - for name, parameters in data.items(): - name_icon = ( - parameters if (type(parameters) is str) else parameters[0] - ) - - bottom_button = MDFloatingBottomButton( - icon=name_icon, - on_enter=self.on_enter, - on_leave=self.on_leave, - opacity=0, - ) - bottom_button.bind( - on_press=lambda x: self.dispatch("on_press_stack_button"), - on_release=lambda x: self.dispatch( - "on_release_stack_button" - ), - ) - - if "on_press" in parameters: - callback = parameters[parameters.index("on_press") + 1] - bottom_button.bind(on_press=callback) - - if "on_release" in parameters: - callback = parameters[parameters.index("on_release") + 1] - bottom_button.bind(on_release=callback) - - self.set_pos_bottom_buttons(bottom_button) - self.add_widget(bottom_button) - self.stack_buttons[name] = WeakProxy(bottom_button) - # Labels. - floating_text = name - if floating_text: - label = MDFloatingLabel(text=floating_text, opacity=0) - label.bg_color = self.label_bg_color - label.radius = self.label_radius - label.text_color = ( - self.label_text_color - if self.label_text_color - else self.theme_cls.text_color - ) - self.add_widget(label) - # Top root button. - root_button = MDFloatingRootButton(on_release=self.open_stack) - root_button.icon = self.icon - self.set_pos_root_button(root_button) - self.add_widget(root_button) - - self.clear_widgets() - self.stack_buttons = {} - self._anim_buttons_data = {} - self._anim_labels_data = {} - self._label_pos_y_set = False - Clock.schedule_once(on_data) - - def on_icon(self, instance_speed_dial, name_icon: str) -> None: - self._set_button_property(MDFloatingRootButton, "icon", name_icon) - - def on_label_text_color( - self, instance_speed_dial, color: list | str - ) -> None: - for widget in self.children: - if isinstance(widget, MDFloatingLabel): - widget.text_color = color - - def on_color_icon_stack_button( - self, instance_speed_dial, color: list - ) -> None: - self._set_button_property(MDFloatingBottomButton, "icon_color", color) - - def on_hint_animation(self, instance_speed_dial, value: bool) -> None: - for widget in self.children: - if isinstance(widget, MDFloatingLabel): - widget.md_bg_color = (0, 0, 0, 0) - - def on_bg_hint_color(self, instance_speed_dial, color: list) -> None: - setattr(MDFloatingBottomButton, "_bg_color", color) - - def on_color_icon_root_button( - self, instance_speed_dial, color: list - ) -> None: - self._set_button_property(MDFloatingRootButton, "icon_color", color) - - def on_bg_color_stack_button( - self, instance_speed_dial, color: list - ) -> None: - self._set_button_property(MDFloatingBottomButton, "md_bg_color", color) - - def on_bg_color_root_button(self, instance_speed_dial, color: list) -> None: - self._set_button_property(MDFloatingRootButton, "md_bg_color", color) - - def on_press_stack_button(self, *args) -> None: - """ - Called at the on_press event for the stack button. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - on_press_stack_button: print(*args) - - .. versionadded:: 1.1.0 - """ - - def on_release_stack_button(self, *args) -> None: - """ - Called at the on_release event for the stack button. - - .. code-block:: kv - - MDFloatingActionButtonSpeedDial: - on_release_stack_button: print(*args) - - .. versionadded:: 1.1.0 - """ - - def set_pos_labels(self, instance_floating_label: MDFloatingLabel) -> None: - """ - Sets the position of the floating labels. - Called when the application's root window is resized. - """ - - if self.anchor == "right": - instance_floating_label.x = ( - Window.width - instance_floating_label.width - dp(86) - ) - - def set_pos_root_button( - self, instance_floating_root_button: MDFloatingRootButton - ) -> None: - """ - Sets the position of the root button. - Called when the application's root window is resized. - """ - - def set_pos_root_button(*args): - if self.anchor == "right": - instance_floating_root_button.y = dp(20) - instance_floating_root_button.x = self.parent.width - ( - dp(56) + dp(20) - ) - - Clock.schedule_once(set_pos_root_button) - - def set_pos_bottom_buttons( - self, instance_floating_bottom_button: MDFloatingBottomButton - ) -> None: - """ - Sets the position of the bottom buttons in a stack. - Called when the application's root window is resized. - """ - - if self.anchor == "right": - if self.state != "open": - instance_floating_bottom_button.y = ( - instance_floating_bottom_button.height / 2 - ) - instance_floating_bottom_button.x = Window.width - ( - instance_floating_bottom_button.height - + instance_floating_bottom_button.width / 2 - ) - - def open_stack( - self, instance_floating_root_button: MDFloatingRootButton - ) -> None: - """Opens a button stack.""" - - for widget in self.children: - if isinstance(widget, MDFloatingLabel): - Animation.cancel_all(widget) - - if self.state != "open": - y = 0 - label_position = dp(54) - anim_buttons_data = {} - anim_labels_data = {} - - for widget in self.children: - if isinstance(widget, MDFloatingBottomButton): - # Sets new button positions. - y += dp(56) - widget.y = widget.y * 2 + y - if not self._anim_buttons_data: - anim_buttons_data[widget] = Animation( - opacity=1, - d=self.opening_time, - t=self.opening_transition, - ) - elif isinstance(widget, MDFloatingLabel): - # Sets new labels positions. - label_position += dp(56) - # Sets the position of signatures only once. - if not self._label_pos_y_set: - widget.y = widget.y * 2 + label_position - widget.x = Window.width - widget.width - dp(86) - if not self._anim_labels_data: - anim_labels_data[widget] = Animation( - opacity=1, d=self.opening_time - ) - elif ( - isinstance(widget, MDFloatingRootButton) - and self.root_button_anim - ): - # Rotates the root button 45 degrees. - Animation( - rotate_value_angle=-45, - d=self.opening_time_button_rotation, - t=self.opening_transition_button_rotation, - ).start(widget) - - if anim_buttons_data: - self._anim_buttons_data = anim_buttons_data - if anim_labels_data and not self.hint_animation: - self._anim_labels_data = anim_labels_data - - self.state = "open" - self.dispatch("on_open") - self.do_animation_open_stack(self._anim_buttons_data) - self.do_animation_open_stack(self._anim_labels_data) - if not self._label_pos_y_set: - self._label_pos_y_set = True - else: - self.close_stack() - - def do_animation_open_stack(self, anim_data: dict) -> None: - """ - :param anim_data: - { - : - , - : - , - ..., - } - """ - - def on_progress(animation, widget, value): - if value >= 0.1: - animation_open_stack() - - def animation_open_stack(*args): - try: - widget = next(widgets_list) - animation = anim_data[widget] - animation.bind(on_progress=on_progress) - animation.start(widget) - except StopIteration: - pass - - widgets_list = iter(list(anim_data.keys())) - animation_open_stack() - - def close_stack(self): - """Closes the button stack.""" - - for widget in self.children: - if isinstance(widget, MDFloatingBottomButton): - Animation( - y=widget.height / 2, - d=self.closing_time, - t=self.closing_transition, - opacity=0, - ).start(widget) - elif isinstance(widget, MDFloatingLabel): - if widget.opacity > 0: - Animation(opacity=0, d=0.1).start(widget) - elif ( - isinstance(widget, MDFloatingRootButton) - and self.root_button_anim - ): - Animation( - rotate_value_angle=0, - d=self.closing_time_button_rotation, - t=self.closing_transition_button_rotation, - ).start(widget) - self.state = "close" - self.dispatch("on_close") - - def _update_pos_buttons(self, instance, width, height): - # Updates button positions when resizing screen. - for widget in self.children: - if isinstance(widget, MDFloatingBottomButton): - self.set_pos_bottom_buttons(widget) - elif isinstance(widget, MDFloatingRootButton): - self.set_pos_root_button(widget) - elif isinstance(widget, MDFloatingLabel): - self.set_pos_labels(widget) - - def _set_button_property( - self, instance, property_name: str, property_value: str | list - ): - def set_count_widget(*args): - if self.children: - for widget in self.children: - if isinstance(widget, instance): - setattr(instance, property_name, property_value) - Clock.unschedule(set_count_widget) - break - - Clock.schedule_interval(set_count_widget, 0) + self.register_event_type("on_collapse") + self.register_event_type("on_expand") + Clock.schedule_once(self._set_text_pos, 0.5) + + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDExtendedFabButtonIcon): + self._icon = widget + elif isinstance(widget, MDExtendedFabButtonText): + self._label = widget + widget.opacity = 0 + + return super().add_widget(widget) + + def on_collapse(self, *args): + """Fired when the button is collapsed.""" + + def on_expand(self, *args): + """Fired when the button is expanded.""" + + def on_fab_state(self, instance, state: str) -> None: + """Fired when the :attr:`fab_state` value changes.""" + + if state == "expand": + Clock.schedule_once(self.expand) + Clock.schedule_once(lambda x: self.dispatch("on_expand")) + elif state == "collapse": + Clock.schedule_once(self.collapse) + Clock.schedule_once(lambda x: self.dispatch("on_collapse")) + + def on__x(self, instance, value) -> None: + self._label.x = ( + self._icon.x + self._icon.texture_size[0] + dp(24) - value + ) + + def _set_text_pos(self, *args): + if self._icon and self._label: + self._label.x = self._icon.x + self._icon.texture_size[0] + dp(24) + elif not self._icon and self._label: + self._label.opacity = 1 + self.width = self._label.texture_size[0] + dp(32) + self._label.pos_hint = {"center_x": 0.5} diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__init__.py index 7577fc9..9bcb032 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__init__.py @@ -4,5 +4,4 @@ from .card import ( MDCardSwipe, MDCardSwipeFrontBox, MDCardSwipeLayerBox, - MDSeparator, ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/__init__.cpython-311.pyc index f46eaa7..b62f8c4 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/card.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/card.cpython-311.pyc index f112a5a..326f147 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/card.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/__pycache__/card.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.kv index 7ed37bd..26d2a37 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.kv @@ -1,9 +1,95 @@ : - md_bg_color: app.theme_cls.divider_color - - - md_bg_color: - self.theme_cls.divider_color \ - if not root.color \ - else root.color + app.theme_cls.secondaryContainerColor \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color + + + + shadow_radius: [(self.radius[0] / 2) + dp(2), ] + shadow_color: + { \ + "filled": self.theme_cls.transparentColor, \ + "outlined": self.theme_cls.transparentColor, \ + "elevated": self.theme_cls.shadowColor \ + if self.theme_shadow_color == "Primary" else \ + self.shadow_color, \ + }[self.style] \ + if not self.disabled else \ + { \ + "filled": self.theme_cls.transparentColor, \ + "outlined": self.theme_cls.transparentColor, \ + "elevated": self.theme_cls.shadowColor[:-1] + [.5] \ + if self.theme_shadow_color == "Primary" else \ + self.shadow_color[:-1] + [.5], + }[self.style] + shadow_offset: + ( \ + { \ + "filled": [0, 0], \ + "outlined": [0, 0], \ + "elevated": [0, -2], \ + }[self.style] \ + if not self.disabled else \ + { \ + "filled": [0, 0], \ + "outlined": [0, 0], \ + "elevated": [0, -2], \ + }[self.style] \ + ) \ + if self.theme_shadow_offset == "Primary" else self.shadow_offset + shadow_softness: + ( \ + { \ + "filled": 0, \ + "outlined": 0, \ + "elevated": dp(4), \ + }[self.style] \ + if not self.disabled else \ + { \ + "filled": 0, \ + "outlined": 0, \ + "elevated": dp(4), \ + }[self.style] \ + ) \ + if self.theme_shadow_softness == "Primary" else self.shadow_softness + elevation_level: + ( \ + ( \ + { \ + "filled": 0, \ + "outlined": 0, \ + "elevated": self.elevation_level if self.elevation_level else 1, \ + }[self.style] \ + ) \ + if self.theme_elevation_level == "Primary" else self.elevation_level \ + ) \ + if not self.disabled else \ + { \ + "filled": 1, \ + "outlined": 0, \ + "elevated": self.elevation_level if self.elevation_level else 1, \ + }[self.style] + elevation: self.elevation_levels[self.elevation_level] + line_color: + (\ + ( \ + self.theme_cls.outlineColor \ + if not self.disabled else \ + self.theme_cls.onSurfaceColor[:-1] + \ + [self.button_outlined_opacity_value_disabled_line] \ + ) \ + if self.style == "outlined" else \ + self.theme_cls.transparentColor \ + ) \ + if self.theme_line_color == "Primary" else self.line_color + md_bg_color: + ( \ + { \ + "filled": app.theme_cls.surfaceContainerHighestColor, \ + "outlined": app.theme_cls.surfaceColor, \ + "elevated": app.theme_cls.surfaceContainerLowColor, \ + }[self.style] \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color \ + ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.py index 7e0bdf9..5ecfc8f 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/card/card.py @@ -4,8 +4,7 @@ Components/Card .. seealso:: - `Material Design spec, Cards `_ and - `Material Design 3 spec, Cards `_ + `Material Design 3 spec, Cards `_ .. rubric:: Cards contain content and actions about a single subject. @@ -23,11 +22,21 @@ Components/Card :class:`~MDCard` class. .. MDCard: + MDCard ------ -An example of the implementation of a card in the style of material design version 3 ------------------------------------------------------------------------------------- +There are three types of cards: elevated, filled, and outlined: + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/available-cards.png + :align: center + +1. Elevated card +2. Filled card +3. Outlined card + +Example +------- .. tabs:: @@ -42,10 +51,10 @@ An example of the implementation of a card in the style of material design versi from kivymd.uix.card import MDCard KV = ''' - - padding: 4 + + padding: "4dp" size_hint: None, None - size: "200dp", "100dp" + size: "240dp", "100dp" MDRelativeLayout: @@ -54,7 +63,6 @@ An example of the implementation of a card in the style of material design versi pos_hint: {"top": 1, "right": 1} MDLabel: - id: label text: root.text adaptive_size: True color: "grey" @@ -63,39 +71,31 @@ An example of the implementation of a card in the style of material design versi MDScreen: + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.backgroundColor MDBoxLayout: id: box adaptive_size: True - spacing: "56dp" + spacing: "12dp" pos_hint: {"center_x": .5, "center_y": .5} ''' - class MD3Card(MDCard): - '''Implements a material design v3 card.''' + class MyCard(MDCard): + '''Implements a material card.''' text = StringProperty() class Example(MDApp): def build(self): - self.theme_cls.material_style = "M3" return Builder.load_string(KV) def on_start(self): - styles = { - "elevated": "#f6eeee", "filled": "#f4dedc", "outlined": "#f8f5f4" - } - for style in styles.keys(): + for style in ("elevated", "filled", "outlined"): self.root.ids.box.add_widget( - MD3Card( - line_color=(0.2, 0.2, 0.2, 0.8), - style=style, - text=style.capitalize(), - md_bg_color=styles[style], - shadow_offset=(0, -1), - ) + MyCard(style=style, text=style.capitalize()) ) @@ -114,31 +114,29 @@ An example of the implementation of a card in the style of material design versi from kivymd.uix.screen import MDScreen - class MD3Card(MDCard): - '''Implements a material design v3 card.''' + class MyCard(MDCard): + '''Implements a material card.''' class Example(MDApp): def build(self): - self.theme_cls.material_style = "M3" return ( MDScreen( MDBoxLayout( id="box", adaptive_size=True, - spacing="56dp", + spacing="12dp", pos_hint={"center_x": 0.5, "center_y": 0.5}, - ) + ), + theme_bg_color="Custom", + md_bg_color=self.theme_cls.backgroundColor, ) ) def on_start(self): - styles = { - "elevated": "#f6eeee", "filled": "#f4dedc", "outlined": "#f8f5f4" - } - for style in styles.keys(): + for style in ("elevated", "filled", "outlined"): self.root.ids.box.add_widget( - MD3Card( + MyCard( MDRelativeLayout( MDIconButton( icon="dots-vertical", @@ -147,25 +145,118 @@ An example of the implementation of a card in the style of material design versi MDLabel( text=style.capitalize(), adaptive_size=True, - color="grey", pos=("12dp", "12dp"), ), ), - line_color=(0.2, 0.2, 0.2, 0.8), style=style, - text=style.capitalize(), - md_bg_color=styles[style], - shadow_offset=(0, -1), + padding="4dp", + size_hint=(None, None), + size=("240dp", "100dp"), + ripple_behavior=True, ) ) Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/cards-m3.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-usage.png + :align: center + +Elevated +-------- + +.. code-block:: kv + + MDCard + style: "elevated" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-elevated.png + :align: center + +Filled +------ + +.. code-block:: kv + + MDCard + style: "filled" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-filled.png + :align: center + +Outlined +-------- + +.. code-block:: kv + + MDCard + style: "outlined" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-outlined.png + :align: center + + +Customization of card +===================== + +.. code-block:: kv + + from kivy.lang import Builder + + from kivymd.app import MDApp + + KV = ''' + MDScreen: + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.backgroundColor + + MDCard: + style: "elevated" + pos_hint: {"center_x": .5, "center_y": .5} + padding: "4dp" + size_hint: None, None + size: "240dp", "100dp" + # Sets custom properties. + theme_shadow_color: "Custom" + shadow_color: "green" + theme_bg_color: "Custom" + md_bg_color: "white" + md_bg_color_disabled: "grey" + theme_shadow_offset: "Custom" + shadow_offset: (1, -2) + theme_shadow_softness: "Custom" + shadow_softness: 1 + theme_elevation_level: "Custom" + elevation_level: 2 + + MDRelativeLayout: + + MDIconButton: + icon: "dots-vertical" + pos_hint: {"top": 1, "right": 1} + + MDLabel: + text: "Elevated" + adaptive_size: True + color: "grey" + pos: "12dp", "12dp" + bold: True + ''' + + + class Example(MDApp): + def build(self): + self.theme_cls.primary_palette = "Green" + return Builder.load_string(KV) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-customization.png :align: center .. MDCardSwipe: + MDCardSwipe ----------- @@ -196,8 +287,8 @@ that inherits from the :class:`~MDCardSwipe` class: .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sceleton-mdcard-swiper.png :align: center -End full code -------------- +Example +------- .. tabs:: @@ -212,16 +303,20 @@ End full code from kivymd.uix.card import MDCardSwipe KV = ''' - + : size_hint_y: None height: content.height MDCardSwipeLayerBox: - # Content under the card. + padding: "8dp" + + MDIconButton: + icon: "trash-can" + pos_hint: {"center_y": .5} + on_release: app.remove_item(root) MDCardSwipeFrontBox: - # Content of card. OneLineListItem: id: content text: root.text @@ -230,39 +325,34 @@ End full code MDScreen: - MDBoxLayout: - orientation: "vertical" + MDScrollView: - MDTopAppBar: - elevation: 4 - title: "MDCardSwipe" - - MDScrollView: - scroll_timeout : 100 - - MDList: - id: md_list - padding: 0 + MDList: + id: md_list + padding: 0 ''' class SwipeToDeleteItem(MDCardSwipe): - '''Card with `swipe-to-delete` behavior.''' - text = StringProperty() class Example(MDApp): - def build(self): + def __init__(self, **kwargs): + super().__init__(**kwargs) self.theme_cls.theme_style = "Dark" self.theme_cls.primary_palette = "Orange" - return Builder.load_string(KV) + self.screen = Builder.load_string(KV) + + def build(self): + return self.screen + + def remove_item(self, instance): + self.screen.ids.md_list.remove_widget(instance) def on_start(self): - '''Creates a list of cards.''' - for i in range(20): - self.root.ids.md_list.add_widget( + self.screen.ids.md_list.add_widget( SwipeToDeleteItem(text=f"One-line item {i}") ) @@ -274,14 +364,12 @@ End full code .. code-block:: python from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.card import ( MDCardSwipe, MDCardSwipeLayerBox, MDCardSwipeFrontBox ) from kivymd.uix.list import MDList, OneLineListItem from kivymd.uix.screen import MDScreen from kivymd.uix.scrollview import MDScrollView - from kivymd.uix.toolbar import MDTopAppBar class Example(MDApp): @@ -290,20 +378,13 @@ End full code self.theme_cls.primary_palette = "Orange" return ( MDScreen( - MDBoxLayout( - MDTopAppBar( - elevation=4, - title="MDCardSwipe", + MDScrollView( + MDList( + id="md_list", + padding=0, ), - MDScrollView( - MDList( - id="md_list", - ), - id="scroll", - scroll_timeout=100, - ), - id="box", - orientation="vertical", + id="scroll", + scroll_timeout=100, ), ) ) @@ -312,7 +393,7 @@ End full code '''Creates a list of cards.''' for i in range(20): - self.root.ids.box.ids.scroll.ids.md_list.add_widget( + self.root.ids.scroll.ids.md_list.add_widget( MDCardSwipe( MDCardSwipeLayerBox(), MDCardSwipeFrontBox( @@ -323,7 +404,7 @@ End full code ) ), size_hint_y=None, - height="52dp", + height="48dp", ) ) @@ -355,19 +436,11 @@ Swipe behavior # By default, the parameter is "hand" - type_swipe: "hand" + type_swipe: "hand" # "auto" .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hand-mdcard-swipe.gif :align: center -.. code-block:: kv - - : - type_swipe: "auto" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/auto-mdcard-swipe.gif - :align: center - Removing an item using the ``type_swipe = "auto"`` parameter ------------------------------------------------------------ @@ -410,9 +483,10 @@ You can use this event to remove items from a list: def on_swipe_complete(self, instance): self.root.ids.box.ids.scroll.ids.md_list.remove_widget(instance) -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/autodelete-mdcard-swipe.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/auto-mdcard-swipe.gif :align: center + Add content to the bottom layer of the card ------------------------------------------- @@ -431,256 +505,20 @@ use the :class:`~MDCardSwipeLayerBox` class. pos_hint: {"center_y": .5} on_release: app.remove_item(root) -End full code -------------- - -.. tabs:: - - .. tab:: Declarative KV styles - - .. code-block:: python - - from kivy.lang import Builder - from kivy.properties import StringProperty - - from kivymd.app import MDApp - from kivymd.uix.card import MDCardSwipe - - KV = ''' - : - size_hint_y: None - height: content.height - - MDCardSwipeLayerBox: - padding: "8dp" - - MDIconButton: - icon: "trash-can" - pos_hint: {"center_y": .5} - on_release: app.remove_item(root) - - MDCardSwipeFrontBox: - - OneLineListItem: - id: content - text: root.text - _no_ripple_effect: True - - - MDScreen: - - MDBoxLayout: - orientation: "vertical" - - MDTopAppBar: - elevation: 4 - title: "MDCardSwipe" - - MDScrollView: - - MDList: - id: md_list - padding: 0 - ''' - - - class SwipeToDeleteItem(MDCardSwipe): - text = StringProperty() - - - class Example(MDApp): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - self.screen = Builder.load_string(KV) - - def build(self): - return self.screen - - def remove_item(self, instance): - self.screen.ids.md_list.remove_widget(instance) - - def on_start(self): - for i in range(20): - self.screen.ids.md_list.add_widget( - SwipeToDeleteItem(text=f"One-line item {i}") - ) - - - Example().run() - - .. tab:: Decralative python styles - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.button import MDIconButton - from kivymd.uix.card import ( - MDCardSwipe, MDCardSwipeLayerBox, MDCardSwipeFrontBox - ) - from kivymd.uix.list import MDList, OneLineListItem - from kivymd.uix.screen import MDScreen - from kivymd.uix.scrollview import MDScrollView - from kivymd.uix.toolbar import MDTopAppBar - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return ( - MDScreen( - MDBoxLayout( - MDTopAppBar( - elevation=4, - title="MDCardSwipe", - ), - MDScrollView( - MDList( - id="md_list", - ), - id="scroll", - scroll_timeout=100, - ), - id="box", - orientation="vertical", - ), - ) - ) - - def on_start(self): - '''Creates a list of cards.''' - - for i in range(20): - self.root.ids.box.ids.scroll.ids.md_list.add_widget( - MDCardSwipe( - MDCardSwipeLayerBox( - MDIconButton( - icon="trash-can", - pos_hint={"center_y": 0.5}, - on_release=self.remove_item, - ), - ), - MDCardSwipeFrontBox( - OneLineListItem( - id="content", - text=f"One-line item {i}", - _no_ripple_effect=True, - ) - ), - size_hint_y=None, - height="52dp", - ) - ) - - def remove_item(self, instance): - self.root.ids.box.ids.scroll.ids.md_list.remove_widget( - instance.parent.parent - ) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/handdelete-mdcard-swipe.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/mdcard-swipe-content.png :align: center - -Focus behavior --------------- - -.. code-block:: kv - - MDCard: - focus_behavior: True - -.. tabs:: - - .. tab:: Declarative KV styles - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - - KV = ''' - MDScreen: - - MDCard: - size_hint: .7, .4 - focus_behavior: True - pos_hint: {"center_x": .5, "center_y": .5} - md_bg_color: "darkgrey" - unfocus_color: "darkgrey" - focus_color: "grey" - elevation: 6 - ''' - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - - Example().run() - - .. tab:: Declarative python styles - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.card import MDCard - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return ( - MDScreen( - MDCard( - size_hint=(0.7, 0.4), - focus_behavior=True, - pos_hint={"center_x": 0.5, "center_y": 0.5}, - md_bg_color="darkgrey", - unfocus_color="darkgrey", - focus_color="grey", - elevation=6, - ), - ) - ) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-focus.gif - :align: center - -Ripple behavior ---------------- - -.. code-block:: kv - - MDCard: - ripple_behavior: True - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-behavior.gif - :align: center - """ +from __future__ import annotations + __all__ = ( "MDCard", "MDCardSwipe", "MDCardSwipeFrontBox", "MDCardSwipeLayerBox", - "MDSeparator", ) import os -from typing import Union from kivy.animation import Animation from kivy.clock import Clock @@ -688,67 +526,32 @@ from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import ( BooleanProperty, - ColorProperty, NumericProperty, OptionProperty, StringProperty, VariableListProperty, + ColorProperty, ) +from kivy.uix.behaviors import ButtonBehavior from kivy.uix.boxlayout import BoxLayout -from kivy.utils import get_color_from_hex from kivymd import uix_path -from kivymd.color_definitions import colors -from kivymd.material_resources import ( - CARD_STYLE_ELEVATED_M3_ELEVATION, - CARD_STYLE_OUTLINED_FILLED_M3_ELEVATION, -) from kivymd.theming import ThemableBehavior from kivymd.uix import MDAdaptiveWidget from kivymd.uix.behaviors import ( - BackgroundColorBehavior, CommonElevationBehavior, DeclarativeBehavior, RectangularRippleBehavior, + BackgroundColorBehavior, ) -from kivymd.uix.behaviors.focus_behavior import FocusBehavior +from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.relativelayout import MDRelativeLayout with open( os.path.join(uix_path, "card", "card.kv"), encoding="utf-8" ) as kv_file: - Builder.load_string(kv_file.read()) - - -class MDSeparator(MDBoxLayout): - """ - A separator line. - - For more information, see in the - :class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation. - """ - - color = ColorProperty(None) - """ - Separator color in (r, g, b, a) or string format. - - :attr:`color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.on_orientation() - - def on_orientation(self, *args) -> None: - self.size_hint = ( - (1, None) if self.orientation == "horizontal" else (None, 1) - ) - if self.orientation == "horizontal": - self.height = dp(1) - else: - self.width = dp(1) + Builder.load_string(kv_file.read(), filename="MDCard.kv") class MDCard( @@ -756,34 +559,28 @@ class MDCard( MDAdaptiveWidget, ThemableBehavior, BackgroundColorBehavior, - RectangularRippleBehavior, CommonElevationBehavior, - FocusBehavior, + RectangularRippleBehavior, + StateLayerBehavior, + ButtonBehavior, BoxLayout, ): """ Card class. For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and :class:`~kivymd.uix.MDAdaptiveWidget` and :class:`~kivymd.theming.ThemableBehavior` and - :class:`~kivymd.uix.behaviors.BackgroundColorBehavior` and - :class:`~kivymd.uix.behaviors.RectangularRippleBehavior` and - :class:`~kivymd.uix.behaviors.CommonElevationBehavior` and - :class:`~kivymd.uix.behaviors.FocusBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and + :class:`~kivymd.uix.behaviors.state_layer_behavior.StateLayerBehavior` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and :class:`~kivy.uix.boxlayout.BoxLayout` and classes documentation. """ - focus_behavior = BooleanProperty(False) - """ - Using focus when hovering over a card. - - :attr:`focus_behavior` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - ripple_behavior = BooleanProperty(False) """ Use ripple effect for card. @@ -792,17 +589,17 @@ class MDCard( and defaults to `False`. """ - radius = VariableListProperty([dp(6), dp(6), dp(6), dp(6)]) + radius = VariableListProperty([dp(16), dp(16), dp(16), dp(16)]) """ Card radius by default. .. versionadded:: 1.0.0 :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` - and defaults to `[dp(6), dp(6), dp(6), dp(6)]`. + and defaults to `[dp(16), dp(16), dp(16), dp(16)]`. """ - style = OptionProperty(None, options=("filled", "elevated", "outlined")) + style = OptionProperty("filled", options=("filled", "elevated", "outlined")) """ Card type. @@ -811,65 +608,78 @@ class MDCard( Available options are: 'filled', 'elevated', 'outlined'. :attr:`style` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'elevated'`. + and defaults to `None`. """ - _bg_color_map = ( - get_color_from_hex(colors["Light"]["CardsDialogs"]), - get_color_from_hex(colors["Dark"]["CardsDialogs"]), - [1.0, 1.0, 1.0, 0.0], - ) + md_bg_color_disabled = ColorProperty(None) + """ + The background color in (r, g, b, a) or string format of the card when + the card is disabled. + + :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.theme_cls.bind( - material_style=self.set_style, theme_style=self.update_md_bg_color - ) - Clock.schedule_once(self.set_style) Clock.schedule_once( lambda x: self.on_ripple_behavior(0, self.ripple_behavior) ) - self.update_md_bg_color(self, self.theme_cls.theme_style) - def update_md_bg_color(self, instance_card, theme_style: str) -> None: - if self.md_bg_color in self._bg_color_map: - self.md_bg_color = get_color_from_hex( - colors[theme_style]["CardsDialogs"] - ) + def on_press(self, *args) -> None: + """Fired when the button is pressed.""" - def set_style(self, *args) -> None: - self.set_radius() - self.set_elevation() - self.set_line_color() + self._on_press(args) - def set_line_color(self) -> None: - if self.theme_cls.material_style == "M3": - if self.style == "elevated" or self.style == "filled": - self.line_color = [0, 0, 0, 0] + def on_release(self, *args) -> None: + """ + Fired when the button is released + (i.e. the touch/click that pressed the button goes away). + """ - def set_elevation(self) -> None: - if self.theme_cls.material_style == "M3": - if self.style == "outlined" or self.style == "filled": - self.elevation = CARD_STYLE_OUTLINED_FILLED_M3_ELEVATION - elif self.style == "elevated": - self.elevation = CARD_STYLE_ELEVATED_M3_ELEVATION + self._on_release(args) - def set_radius(self) -> None: - if ( - self.radius == [dp(6), dp(6), dp(6), dp(6)] - and self.theme_cls.material_style == "M3" - ): - self.radius = [dp(16), dp(16), dp(16), dp(16)] - elif ( - self.radius == [dp(16), dp(16), dp(16), dp(16)] - and self.theme_cls.material_style == "M2" - ): - self.radius = [dp(6), dp(6), dp(6), dp(6)] + def on_ripple_behavior(self, interval: int | float, value: bool) -> None: + """Fired when the :attr:`ripple_behavior` value changes.""" - def on_ripple_behavior( - self, interval: Union[int, float], value_behavior: bool - ) -> None: - self._no_ripple_effect = False if value_behavior else True + self.ripple_effect = not self.ripple_effect + + def set_properties_widget(self) -> None: + """Fired `on_release/on_press/on_enter/on_leave` events.""" + + super().set_properties_widget() + + if not self.disabled: + if self._state == self.state_hover and self.focus_behavior: + self._elevation_level = self.elevation_level + self._shadow_softness = self.shadow_softness + self._bg_color = self.md_bg_color + + if self.style in ["filled", "outlined"]: + if self.theme_elevation_level == "Primary": + self.elevation_level = 0 + if self.theme_shadow_softness == "Primary": + self.shadow_softness = 0 + else: + if self.theme_elevation_level == "Primary": + self.elevation_level = 2 + if self.theme_shadow_softness == "Primary": + self.shadow_softness = dp(4) + if self.theme_shadow_offset == "Primary": + self.shadow_offset = [0, -2] + elif self._state == self.state_press: + if self.theme_elevation_level == "Primary": + self.elevation_level = 1 + if self.theme_shadow_softness == "Primary": + self.shadow_softness = 0 + elif not self._state: + if self.theme_elevation_level == "Primary": + self.elevation_level = 1 + if self.theme_shadow_softness == "Primary": + self.shadow_softness = 0 + if self.theme_shadow_offset == "Primary": + self.shadow_offset = [0, -2] + self.md_bg_color = self._bg_color class MDCardSwipe(MDRelativeLayout): @@ -881,7 +691,7 @@ class MDCardSwipe(MDRelativeLayout): :Events: :attr:`on_swipe_complete` - Called when a swipe of card is completed. + Fired when a swipe of card is completed. """ open_progress = NumericProperty(0.0) @@ -993,16 +803,14 @@ class MDCardSwipe(MDRelativeLayout): self.register_event_type("on_swipe_complete") super().__init__(*args, **kwargs) - def add_widget(self, widget, index=0, canvas=None): - if isinstance(widget, (MDCardSwipeFrontBox, MDCardSwipeLayerBox)): - return super().add_widget(widget) - def on_swipe_complete(self, *args): - """Called when a swipe of card is completed.""" + """Fired when a swipe of card is completed.""" def on_anchor( self, instance_swipe_to_delete_item, anchor_value: str ) -> None: + """Fired when the value of :attr:`anchor` changes.""" + if anchor_value == "right": self.open_progress = 1.0 else: @@ -1011,6 +819,8 @@ class MDCardSwipe(MDRelativeLayout): def on_open_progress( self, instance_swipe_to_delete_item, progress_value: float ) -> None: + """Fired when the value of :attr:`open_progress` changes.""" + def on_open_progress(*args): if self.anchor == "left": self.children[0].x = self.width * progress_value @@ -1043,7 +853,7 @@ class MDCardSwipe(MDRelativeLayout): if self.collide_point(touch.x, touch.y): if not self._to_closed: self._opens_process = False - self.complete_swipe() + self._complete_swipe() return super().on_touch_up(touch) def on_touch_down(self, touch): @@ -1053,18 +863,9 @@ class MDCardSwipe(MDRelativeLayout): Clock.schedule_once(self.close_card, self.closing_interval) return super().on_touch_down(touch) - def complete_swipe(self) -> None: - expr = ( - self.open_progress <= self.max_swipe_x - if self.anchor == "left" - else self.open_progress >= self.max_swipe_x - ) - if expr: - Clock.schedule_once(self.close_card, self.closing_interval) - else: - self.open_card() - def open_card(self) -> None: + """Animates the opening of the card.""" + if self.type_swipe == "hand": swipe_x = ( self.max_opened_x @@ -1081,11 +882,28 @@ class MDCardSwipe(MDRelativeLayout): self.state = "opened" def close_card(self, *args) -> None: + """Animates the closing of the card.""" + anim = Animation(x=0, t=self.closing_transition, d=self.opening_time) anim.bind(on_complete=self._reset_open_progress) anim.start(self.children[0]) self.state = "closed" + def add_widget(self, widget, index=0, canvas=None): + if isinstance(widget, (MDCardSwipeFrontBox, MDCardSwipeLayerBox)): + return super().add_widget(widget) + + def _complete_swipe(self) -> None: + expr = ( + self.open_progress <= self.max_swipe_x + if self.anchor == "left" + else self.open_progress >= self.max_swipe_x + ) + if expr: + Clock.schedule_once(self.close_card, self.closing_interval) + else: + self.open_card() + def _on_swipe_complete(self, *args): self.dispatch("on_swipe_complete") @@ -1104,4 +922,9 @@ class MDCardSwipeFrontBox(MDCard): class MDCardSwipeLayerBox(MDBoxLayout): - pass + """ + Card swipe back box. + + For more information, see in the :class:`~kivymd.uix.boxlayout.MDBoxLayout` + class documentation. + """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/carousel.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/carousel.py deleted file mode 100644 index 5f68886..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/carousel.py +++ /dev/null @@ -1,218 +0,0 @@ -""" -Components/Carousel -=================== - -:class:`~kivy.uix.boxlayout.Carousel` class equivalent. Simplifies working -with some widget properties. For example: - - -Carousel ---------- - -.. code-block:: python - - kv=''' - YourCarousel: - BoxLayout: - [...] - BoxLayout: - [...] - BoxLayout: - [...] - ''' - builder.load_string(kv) - - class YourCarousel(Carousel): - def __init__(self,*kwargs): - self.register_event_type("on_slide_progress") - self.register_event_type("on_slide_complete") - - def on_touch_down(self, *args): - ["Code to detect when the slide changes"] - - def on_touch_up(self, *args): - ["Code to detect when the slide changes"] - - def Calculate_slide_pos(self, *args): - ["Code to calculate the current position of the slide"] - - def do_custom_animation(self, *args): - ["Code to recreate an animation"] - - -MDCarousel ------------ - -.. code-block:: kv - - MDCarousel: - on_slide_progress: - do_something() - on_slide_complete: - do_something() - -""" -# TODO: Add documentation. - -from kivy.animation import Animation -from kivy.uix.carousel import Carousel - -from kivymd.theming import ThemableBehavior -from kivymd.uix.behaviors import DeclarativeBehavior - - -class MDCarousel(DeclarativeBehavior, ThemableBehavior, Carousel): - """ - based on kivy's carousel. - - .. seealso:: - `kivy.uix.carousel.Carousel `_ - """ - - _scrolling = False - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.register_event_type("on_slide_progress") - self.register_event_type("on_slide_complete") - - def on_slide_progress(self, *args): - """ - Event launched when the Slide animation is progress. - remember to bind and unbid to this method. - """ - - def on_slide_complete(self, *args): - """ - Event launched when the Slide animation is complete. - remember to bind and unbid to this method. - """ - - def _position_visible_slides(self, *args): - slides, index = self.slides, self.index - no_of_slides = len(slides) - 1 - if not slides: - return - x, y, width, height = self.x, self.y, self.width, self.height - _offset, direction = self._offset, self.direction - _prev, _next, _current = self._prev, self._next, self._current - get_slide_container = self.get_slide_container - last_slide = get_slide_container(slides[-1]) - first_slide = get_slide_container(slides[0]) - skip_next = False - _loop = self.loop - - if direction[0] in ["r", "l"]: - xoff = x + _offset - x_prev = {"l": xoff + width, "r": xoff - width} - x_next = {"l": xoff - width, "r": xoff + width} - if _prev: - _prev.pos = (x_prev[direction[0]], y) - elif _loop and _next and index == 0: - if (_offset > 0 and direction[0] == "r") or ( - _offset < 0 and direction[0] == "l" - ): - last_slide.pos = (x_prev[direction[0]], y) - skip_next = True - if _current: - _current.pos = (xoff, y) - - if self._scrolling: - self.dispatch("on_slide_progress", xoff) - - if skip_next: - return - if _next: - _next.pos = (x_next[direction[0]], y) - elif _loop and _prev and index == no_of_slides: - if (_offset < 0 and direction[0] == "r") or ( - _offset > 0 and direction[0] == "l" - ): - first_slide.pos = (x_next[direction[0]], y) - if direction[0] in ["t", "b"]: - yoff = y + _offset - y_prev = {"t": yoff - height, "b": yoff + height} - y_next = {"t": yoff + height, "b": yoff - height} - if _prev: - _prev.pos = (x, y_prev[direction[0]]) - elif _loop and _next and index == 0: - if (_offset > 0 and direction[0] == "t") or ( - _offset < 0 and direction[0] == "b" - ): - last_slide.pos = (x, y_prev[direction[0]]) - skip_next = True - if _current: - _current.pos = (x, yoff) - if skip_next: - return - if _next: - _next.pos = (x, y_next[direction[0]]) - elif _loop and _prev and index == no_of_slides: - if (_offset < 0 and direction[0] == "t") or ( - _offset > 0 and direction[0] == "b" - ): - first_slide.pos = (x, y_next[direction[0]]) - - def on_touch_down(self, touch): - self._scrolling = True - return super().on_touch_down(touch) - - def on_touch_up(self, touch): - self._scrolling = False - return super().on_touch_up(touch) - - def _start_animation(self, *args, **kwargs): - # compute target offset for ease back, next or prev - new_offset = 0 - direction = kwargs.get("direction", self.direction)[0] - is_horizontal = direction in "rl" - extent = self.width if is_horizontal else self.height - min_move = kwargs.get("min_move", self.min_move) - _offset = kwargs.get("offset", self._offset) - - if _offset < min_move * -extent: - new_offset = -extent - elif _offset > min_move * extent: - new_offset = extent - - # if new_offset is 0, it wasnt enough to go next/prev - dur = self.anim_move_duration - if new_offset == 0: - dur = self.anim_cancel_duration - - # detect edge cases if not looping - len_slides = len(self.slides) - index = self.index - if not self.loop or len_slides == 1: - is_first = index == 0 - is_last = index == len_slides - 1 - if direction in "rt": - towards_prev = new_offset > 0 - towards_next = new_offset < 0 - else: - towards_prev = new_offset < 0 - towards_next = new_offset > 0 - if (is_first and towards_prev) or (is_last and towards_next): - new_offset = 0 - - anim = Animation(_offset=new_offset, d=dur, t=self.anim_type) - anim.cancel_all(self) - - def _cmp(*args): - self.dispatch( - "on_slide_complete", - self.previous_slide, - self.current_slide, - self.next_slide, - ) - if self._skip_slide is not None: - self.index = self._skip_slide - self._skip_slide = None - - anim.bind( - on_complete=_cmp, - on_progress=lambda *args: self.dispatch( - "on_slide_progress", self._offset - ), - ) - anim.start(self) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__init__.py index fc6a3a2..7246a41 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__init__.py @@ -1 +1,7 @@ -from .chip import MDChip, MDChipText # NOQA F401 +from .chip import ( + MDChip, + MDChipText, + MDChipLeadingIcon, + MDChipTrailingIcon, + MDChipLeadingAvatar, +) # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc index 93c52e1..9c8f35f 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/chip.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/chip.cpython-311.pyc index 81f82ed..d9d49ae 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/chip.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/__pycache__/chip.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.kv index e008dd2..17d4ce9 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.kv @@ -1,29 +1,91 @@ + + icon_color: + ( \ + { \ + "filter": app.theme_cls.onSurfaceVariantColor, \ + "suggestion": app.theme_cls.onSurfaceVariantColor, \ + "input": app.theme_cls.onSurfaceVariantColor, \ + "assist": app.theme_cls.primaryColor, \ + }[self._type] \ + if self.theme_icon_color == "Primary" else self.icon_color \ + ) \ + if not root.disabled else self.disabled_color + disabled_color: + { \ + "filter": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_icon], \ + "suggestion": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_icon], \ + "input": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_icon], \ + "assist": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_icon], \ + }[self._type] \ + if not self.icon_color_disabled else self.icon_color_disabled + + + + font_style: "Label" + role: "large" + text_color: + ( \ + { \ + "filter": app.theme_cls.onSurfaceVariantColor, \ + "suggestion": app.theme_cls.onSurfaceVariantColor, \ + "input": app.theme_cls.onSurfaceVariantColor, \ + "assist": app.theme_cls.onSurfaceColor, \ + }[self._type] \ + if root.theme_text_color == "Primary" else root.text_color \ + ) \ + if not root.disabled else self.disabled_color + disabled_color: + { \ + "filter": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_text], \ + "suggestion": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_text], \ + "input": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_text], \ + "assist": app.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_text], \ + }[self._type] \ + if not self.text_color_disabled else self.text_color_disabled + + size_hint_y: None height: "32dp" adaptive_width: True radius: - 16 \ + dp(16) \ if self.radius == [0, 0, 0, 0] else \ - (max(self.radius) if max(self.radius) < self.height / 2 else 16) - md_bg_color: - ( \ - ( \ - app.theme_cls.bg_darkest \ - if app.theme_cls.theme_style == "Light" else \ - app.theme_cls.bg_light \ - ) \ - if not self._origin_md_bg_color else \ - self._origin_md_bg_color - ) \ - if not self.disabled else app.theme_cls.disabled_primary_color + (max(self.radius) if max(self.radius) < self.height / 2 else dp(16)) line_color: - app.theme_cls.disabled_hint_text_color \ - if self.disabled else ( \ - self._origin_line_color \ - if self._origin_line_color else \ - self.line_color \ + ( \ + ( \ + self.theme_cls.outlineColor \ + if not self.disabled else \ + self.theme_cls.onSurfaceColor[:-1] + \ + [self.chip_opacity_value_disabled_container] \ + ) \ + if self.type != "filter" else \ + self.theme_cls.transparentColor \ + ) \ + if self.theme_line_color == "Primary" else \ + self._line_color if not self.disabled else \ + ( \ + self.line_color_disabled \ + if self.line_color_disabled else \ + self._line_color \ ) + md_bg_color: + { \ + "filter": self.theme_cls.surfaceContainerLowColor, \ + "suggestion": self.theme_cls.surfaceContainerLowColor, \ + "input": self.theme_cls.surfaceContainerLowColor, \ + "assist": self.theme_cls.surfaceContainerLowColor, \ + }[self.type] \ + if self.theme_bg_color == "Primary" else self.md_bg_color LeadingIconContainer: id: leading_icon_container diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.py index c9f3593..71d33d3 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.py @@ -4,7 +4,7 @@ Components/Chip .. seealso:: - `Material Design spec, Chips `_ + `Material Design 3 spec, Chips `_ .. rubric:: Chips can show multiple interactive elements together in the same area, such as a list of selectable movie times, or a series of email @@ -17,6 +17,25 @@ Components/Chip Usage ----- +.. code-block:: kv + + MDChip: + + MDChipLeadingAvatar: # MDChipLeadingIcon + + MDChipText: + + MDChipTrailingIcon: + +Anatomy +======= + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-anatomy.png + :align: center + +Example +------- + .. tabs:: .. tab:: Declarative KV style @@ -75,34 +94,6 @@ Usage .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip.png :align: center -Anatomy -------- - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/anatomy-chip.png - :align: center - -1. Container -2. Label text -3. Leading icon or image (optional) -4. Trailing remove icon (optional, input & filter chips only) - -Container ---------- - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/radius-chip.png - :align: center - -All chips are slightly rounded with an 8dp corner. - -Shadows and elevation ---------------------- - -Chip containers can be elevated if the placement requires protection, such as -on top of an image. - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadows-elevation-chip.png - :align: center - The following types of chips are available: ------------------------------------------- @@ -115,6 +106,7 @@ The following types of chips are available: - Suggestion_ .. Assist: + Assist ------ @@ -225,6 +217,7 @@ Example of assist :align: center .. Filter: + Filter ------ @@ -248,18 +241,22 @@ Example of filtering from kivymd.app import MDApp from kivymd.uix.chip import MDChip, MDChipText - from kivymd.uix.list import OneLineIconListItem + from kivymd.uix.list import MDListItem from kivymd.icon_definitions import md_icons from kivymd.uix.screen import MDScreen - from kivymd.utils import asynckivy + + import asynckivy Builder.load_string( ''' - IconLeftWidget: + MDListItemLeadingIcon: icon: root.icon + MDListItemHeadlineText: + text: root.text + @@ -270,11 +267,15 @@ Example of filtering MDTextField: id: search_field - hint_text: "Search icon" - mode: "rectangle" - icon_left: "magnify" + mode: "outlined" on_text: root.set_list_md_icons(self.text, True) + MDTextFieldLeadingIcon: + icon: "magnify" + + MDTextFieldHintText: + text: "Search icon" + MDBoxLayout: id: chip_box spacing: "12dp" @@ -294,18 +295,19 @@ Example of filtering orientation: "vertical" ''' ) - - - class CustomOneLineIconListItem(OneLineIconListItem): + + + class CustomOneLineIconListItem(MDListItem): icon = StringProperty() - - + text = StringProperty() + + class PreviewIconsScreen(MDScreen): filter = ListProperty() # list of tags for filtering icons - + def set_filter_chips(self): '''Asynchronously creates and adds chips to the container.''' - + async def set_filter_chips(): for tag in ["Outline", "Off", "On"]: await asynckivy.sleep(0) @@ -318,7 +320,7 @@ Example of filtering ) chip.bind(active=lambda x, y, z=tag: self.set_filter(y, z)) self.ids.chip_box.add_widget(chip) - + asynckivy.start(set_filter_chips()) def set_filter(self, active: bool, tag: str) -> None: @@ -358,7 +360,6 @@ Example of filtering def build(self) -> PreviewIconsScreen: self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "LightGreen" return self.screen def on_start(self) -> None: @@ -380,7 +381,8 @@ Tap a chip to select it. Multiple chips can be selected or unselected: from kivymd.app import MDApp from kivymd.uix.chip import MDChip, MDChipText from kivymd.uix.screen import MDScreen - from kivymd.utils import asynckivy + + import asynckivy Builder.load_string( ''' @@ -402,10 +404,12 @@ Tap a chip to select it. Multiple chips can be selected or unselected: MDWidget: - MDFlatButton: - text: "Uncheck chips" + MDButton: pos: "20dp", "20dp" on_release: root.unchecks_chips() + + MDButtonText: + text: "Uncheck chips" ''' ) @@ -442,7 +446,6 @@ Tap a chip to select it. Multiple chips can be selected or unselected: def build(self) -> ChipScreen: self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "LightGreen" return self.screen def on_start(self) -> None: @@ -465,7 +468,8 @@ menus: from kivymd.app import MDApp from kivymd.uix.chip import MDChip, MDChipText from kivymd.uix.screen import MDScreen - from kivymd.utils import asynckivy + + import asynckivy Builder.load_string( ''' @@ -485,11 +489,6 @@ menus: spacing: "12dp" adaptive_height: True - MDFillRoundFlatButton: - text: "Add to cart" - md_bg_color: "green" - size_hint_x: 1 - MDWidget: ''' ) @@ -542,6 +541,7 @@ menus: :align: center .. Input: + Input ----- @@ -595,6 +595,7 @@ Example of input :align: center .. Suggestion: + Suggestion ---------- @@ -641,7 +642,7 @@ Example of suggestion API break ========= -1.1.1 version +1.2.0 version ------------- .. code-block:: python @@ -670,7 +671,7 @@ API break Test().run() -1.2.0 version +2.0.0 version ------------- .. code-block:: python @@ -724,7 +725,6 @@ from kivy.properties import ( BooleanProperty, ColorProperty, OptionProperty, - StringProperty, VariableListProperty, ) from kivy.uix.behaviors import ButtonBehavior @@ -738,6 +738,7 @@ from kivymd.uix.behaviors import ( ScaleBehavior, TouchBehavior, ) +from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.label import MDIcon, MDLabel @@ -750,6 +751,29 @@ with open( class BaseChipIcon( CircularRippleBehavior, ScaleBehavior, ButtonBehavior, MDIcon ): + icon_color = ColorProperty(None) + """ + Button icon color in (r, g, b, a) or string format. + + :attr:`icon_color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + icon_color_disabled = ColorProperty(None) + """ + The icon color in (r, g, b, a) or string format of the chip when + the chip is disabled. + + .. versionadded:: 2.0.0 + + :attr:`icon_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + _type = OptionProperty( + "suggestion", options=["assist", "filter", "input", "suggestion"] + ) + def __init__(self, **kwargs): super().__init__(**kwargs) self.ripple_scale = 1.5 @@ -760,7 +784,8 @@ class BaseChipIcon( # icon size according to the standards of material design version 3. if ( self.font_name == "Icons" - and self.theme_cls.font_styles["Icon"][1] == self.font_size + and self.theme_cls.font_styles["Icon"]["large"]["font-size"] + == self.font_size ): self.font_size = ( "18sp" @@ -792,10 +817,10 @@ class MDChipLeadingAvatar(BaseChipIcon): Implements the leading avatar for the chip. For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~kivymd.uix.behaviors.ScaleBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and + :class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivymd.uix.label.MDIcon` + :class:`~kivymd.uix.label.label.MDIcon` classes documentation. """ @@ -805,10 +830,10 @@ class MDChipLeadingIcon(BaseChipIcon): Implements the leading icon for the chip. For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~kivymd.uix.behaviors.ScaleBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and + :class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivymd.uix.label.MDIcon` + :class:`~kivymd.uix.label.label.MDIcon` classes documentation. """ @@ -818,10 +843,10 @@ class MDChipTrailingIcon(BaseChipIcon): Implements the trailing icon for the chip. For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~kivymd.uix.behaviors.ScaleBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and + :class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivymd.uix.label.MDIcon` + :class:`~kivymd.uix.label.label.MDIcon` classes documentation. """ @@ -831,9 +856,24 @@ class MDChipText(MDLabel): Implements the label for the chip. For more information, see in the - :class:`~kivymd.uix.label.MDLabel` classes documentation. + :class:`~kivymd.uix.label.label.MDLabel` classes documentation. """ + text_color_disabled = ColorProperty(None) + """ + The text color in (r, g, b, a) or string format of the chip when + the chip is disabled. + + .. versionadded:: 2.0.0 + + :attr:`text_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + _type = OptionProperty( + "suggestion", options=["assist", "filter", "input", "suggestion"] + ) + class MDChip( MDBoxLayout, @@ -841,16 +881,17 @@ class MDChip( ButtonBehavior, CommonElevationBehavior, TouchBehavior, + StateLayerBehavior, ): """ Chip class. For more information, see in the :class:`~kivymd.uix.boxlayout.MDBoxLayout` and - :class:`~kivymd.uix.behaviors.RectangularRippleBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivymd.uix.behaviors.CommonElevationBehavior` and - :class:`~kivymd.uix.behaviors.TouchBehavior` + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivymd.uix.behaviors.touch_behavior.TouchBehavior` classes documentation. """ @@ -862,23 +903,13 @@ class MDChip( and defaults to `[dp(8), dp(8), dp(8), dp(8)]`. """ - text = StringProperty(deprecated=True) - """ - Chip text. - - .. deprecated:: 1.2.0 - - :attr:`text` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - type = OptionProperty( "suggestion", options=["assist", "filter", "input", "suggestion"] ) """ Type of chip. - .. versionadded:: 1.2.0 + .. versionadded:: 2.0.0 Available options are: `'assist'`, `'filter'`, `'input'`, `'suggestion'`. @@ -886,74 +917,6 @@ class MDChip( and defaults to `'suggestion'`. """ - icon_left = StringProperty(deprecated=True) - """ - Chip left icon. - - .. versionadded:: 1.0.0 - - .. deprecated:: 1.2.0 - - :attr:`icon_left` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - icon_right = StringProperty(deprecated=True) - """ - Chip right icon. - - .. versionadded:: 1.0.0 - - .. deprecated:: 1.2.0 - - :attr:`icon_right` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - text_color = ColorProperty(None, deprecated=True) - """ - Chip's text color in (r, g, b, a) or string format. - - .. deprecated:: 1.2.0 - - :attr:`text_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - icon_right_color = ColorProperty(None, deprecated=True) - """ - Chip's right icon color in (r, g, b, a) or string format. - - .. versionadded:: 1.0.0 - - .. deprecated:: 1.2.0 - - :attr:`icon_right_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - icon_left_color = ColorProperty(None, deprecated=True) - """ - Chip's left icon color in (r, g, b, a) or string format. - - .. versionadded:: 1.0.0 - - .. deprecated:: 1.2.0 - - :attr:`icon_left_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - icon_check_color = ColorProperty(None) - """ - Chip's check icon color in (r, g, b, a) or string format. - - .. versionadded:: 1.0.0 - - :attr:`icon_check_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - active = BooleanProperty(False) """ Whether the check is marked or not. @@ -969,12 +932,23 @@ class MDChip( The background color of the chip in the marked state in (r, g, b, a) or string format. - .. versionadded:: 1.2.0 + .. versionadded:: 2.0.0 :attr:`selected_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ + line_color_disabled = ColorProperty(None) + """ + The color of the outline in the disabled state + + .. versionadded:: 2.0.0 + + :attr:`line_color_disabled` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + _line_color = ColorProperty(None) _current_md_bg_color = ColorProperty(None) # A flag that disallow ripple animation of the chip # at the time of clicking the chip icons. @@ -986,11 +960,19 @@ class MDChip( super().__init__(*args, **kwargs) def on_long_touch(self, *args) -> None: + """Fired when the widget is pressed for a long time.""" + if self.type == "filter": self.active = not self.active + def on_line_color(self, instance, value) -> None: + """Fired when the values of :attr:`line_color` change.""" + + if not self.disabled: + self._line_color = value + def on_type(self, instance, value: str) -> None: - """Called when the values of :attr:`type` change.""" + """Fired when the values of :attr:`type` change.""" def adjust_padding(*args): """ @@ -1069,7 +1051,14 @@ class MDChip( self.set_chip_bg_color( self.selected_color if self.selected_color - else self.theme_cls.primary_color + else { + "filter": self.theme_cls.surfaceContainerLowColor, + "suggestion": self.theme_cls.surfaceContainerLowColor, + "input": self.theme_cls.surfaceContainerLowColor, + "assist": self.theme_cls.surfaceContainerLowColor, + }[self.type] + if self.theme_bg_color == "Primary" + else self.md_bg_color ) else: if ( @@ -1125,11 +1114,26 @@ class MDChip( Animation(md_bg_color=color, d=0.2).start(self) self._anim_complete = not self._anim_complete - def on_press(self, *args): + def on_press(self, *args) -> None: + """Fired when the button is pressed.""" + if self.active: self.active = False + self._on_press(args) + + def on_release(self, *args) -> None: + """ + Fired when the button is released + (i.e. the touch/click that pressed the button goes away). + """ + + self._on_release(args) + def add_widget(self, widget, *args, **kwargs): + def set_type(*args): + widget._type = self.type + def add_icon_leading_trailing(container): if len(container.children): type_icon = ( @@ -1213,6 +1217,7 @@ class MDChip( container.add_widget(widget) if isinstance(widget, MDChipText): + Clock.schedule_once(set_type) widget.adaptive_size = True widget.pos_hint = {"center_y": 0.5} if self.type == "suggestion": @@ -1221,12 +1226,14 @@ class MDChip( lambda x: self.ids.label_container.add_widget(widget) ) elif isinstance(widget, (MDChipLeadingIcon, MDChipLeadingAvatar)): + Clock.schedule_once(set_type) Clock.schedule_once( lambda x: add_icon_leading_trailing( self.ids.leading_icon_container ) ) elif isinstance(widget, MDChipTrailingIcon): + Clock.schedule_once(set_type) Clock.schedule_once( lambda x: add_icon_leading_trailing( self.ids.trailing_icon_container @@ -1236,6 +1243,10 @@ class MDChip( widget, (LabelTextContainer, LeadingIconContainer, TrailingIconContainer), ): + if isinstance( + widget, (LeadingIconContainer, TrailingIconContainer) + ): + Clock.schedule_once(set_type) return super().add_widget(widget) def _set_allow_chip_ripple( diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/circularlayout.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/circularlayout.py index cca5d21..f7b343b 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/circularlayout.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/circularlayout.py @@ -16,7 +16,7 @@ MDCircularLayout from kivymd.app import MDApp - kv = ''' + KV = ''' MDScreen: MDCircularLayout: @@ -26,20 +26,18 @@ MDCircularLayout ''' - class Main(MDApp): + class Example(MDApp): def build(self): - return Builder.load_string(kv) + return Builder.load_string(KV) def on_start(self): for x in range(1, 49): - self.root.ids.container.add_widget( - Label(text=f"{x}", color=[0, 0, 0, 1]) - ) + self.root.ids.container.add_widget(Label(text=f"{x}") - Main().run() + Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/circular-layout.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/circular-layout-dark.png :align: center """ @@ -48,11 +46,10 @@ __all__ = ("MDCircularLayout",) from math import atan2, cos, degrees, radians, sin from kivy.properties import BooleanProperty, NumericProperty - -from kivymd.uix.floatlayout import MDFloatLayout +from kivy.uix.floatlayout import FloatLayout -class MDCircularLayout(MDFloatLayout): +class MDCircularLayout(FloatLayout): degree_spacing = NumericProperty(30) """ The space between children in degree. @@ -63,7 +60,8 @@ class MDCircularLayout(MDFloatLayout): circular_radius = NumericProperty(None, allownone=True) """ - Radius of circle. Radius will be the greatest value in the layout if `circular_radius` if not specified. + Radius of circle. Radius will be the greatest value in the layout + if `circular_radius` if not specified. :attr:`circular_radius` is an :class:`~kivy.properties.NumericProperty` and defaults to `None`. @@ -79,7 +77,8 @@ class MDCircularLayout(MDFloatLayout): max_degree = NumericProperty(360) """ - Maximum range in degree allowed for each row of widgets before jumping to the next row. + Maximum range in degree allowed for each row of widgets before jumping + to the next row. :attr:`max_degree` is an :class:`~kivy.properties.NumericProperty` and defaults to `360`. @@ -185,7 +184,7 @@ if __name__ == "__main__": from kivymd.app import MDApp - kv = """ + KV = """ MDScreen: MDCircularLayout: @@ -194,14 +193,12 @@ MDScreen: row_spacing: min(self.size) * 0.1 """ - class Main(MDApp): + class Example(MDApp): def build(self): - return Builder.load_string(kv) + return Builder.load_string(KV) def on_start(self): for x in range(1, 49): - self.root.ids.container.add_widget( - Label(text=f"{x}", color=[0, 0, 0, 1]) - ) + self.root.ids.container.add_widget(Label(text=f"{x}")) - Main().run() + Example().run() diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc index fe18f04..d700e35 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc index fbdfc73..c77686f 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/controllers/__pycache__/windowcontroller.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__init__.py deleted file mode 100644 index fc4115d..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .datatables import MDDataTable # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 6701f2f..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__pycache__/datatables.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__pycache__/datatables.cpython-311.pyc deleted file mode 100644 index fc5c193..0000000 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/__pycache__/datatables.cpython-311.pyc and /dev/null differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/datatables.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/datatables.kv deleted file mode 100644 index b5d81a7..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/datatables.kv +++ /dev/null @@ -1,241 +0,0 @@ -#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE - - - - orientation: "vertical" - md_bg_color: - ( \ - ( \ - root.theme_cls.bg_darkest \ - if root.theme_cls.theme_style == "Light" else \ - root.theme_cls.bg_light \ - ) \ - if not root.background_color_selected_cell \ - else root.background_color_selected_cell \ - ) \ - if self.selected \ - else \ - ( \ - root.theme_cls.bg_normal \ - if not root.background_color_cell \ - else root.background_color_cell \ - ) - on_press: if DEVICE_TYPE != "desktop": root.table.on_mouse_select(self) - on_enter: if DEVICE_TYPE == "desktop": root.table.on_mouse_select(self) - - MDBoxLayout: - id: box - padding: "8dp", "8dp", 0, "8dp" - spacing: "16dp" - - MDCheckbox: - id: check - size_hint: None, None - size: 0, 0 - opacity: 0 - - MDBoxLayout: - id: inner_box - - MDIcon: - id: icon - size_hint: None, None - pos_hint: {"center_y": 0.5} - size: ("24dp", "24dp") if root.icon else (0, 0) - icon: root.icon if root.icon else "" - theme_text_color: "Custom" - text_color: - root.icon_color if root.icon_color else \ - root.theme_cls.primary_color - - MDLabel: - id: label - text: " " + root.text - markup: True - color: - (1, 1, 1, 1) \ - if root.theme_cls.theme_style == "Dark" else \ - (0, 0, 0, 1) - - MDSeparator: - - - - orientation: "vertical" - size_hint_y: None - height: self.minimum_height - spacing: "4dp" - tooltip_text: root.tooltip if root.tooltip else root.text - - BoxLayout: - id: box - size_hint_y: None - height: lbl.height - - MDLabel: - id: lbl - text: " " + root.text - adaptive_height: True - bold: True - markup: True - color: - (1, 1, 1, 1) \ - if root.theme_cls.theme_style == "Dark" else \ - (0, 0, 0, 1) - - MDSeparator: - id: separator - - - - id: sort_btn - icon: "arrow-up" - pos_hint: {"center_y": 0.5} - size: [dp(24), dp(0)] - theme_text_color: "Custom" - text_color: self.theme_cls.secondary_text_color - opacity: 0 - - - - bar_width: 0 - do_scroll: False - size_hint: 1, None - height: header.height - - MDGridLayout: - id: header - rows: 1 - cols_minimum: root.cols_minimum - adaptive_size: True - padding: 0, "8dp", 0, 0 - md_bg_color: - root.theme_cls.bg_light \ - if not root.background_color_header \ - else root.background_color_header - - MDBoxLayout: - orientation: "vertical" - - MDBoxLayout: - id: box - padding: "8dp", "8dp", "4dp", 0 - spacing: "16dp" - - MDCheckbox: - id: check - size_hint: None, None - size: 0, 0 - opacity: 0 - on_release: root.table_data.select_all(self.state) - - CellHeader: - id: first_cell - - MDSeparator: - - - - data: root.recycle_data - data_first_cells: root.data_first_cells - key_viewclass: "viewclass" - - TableRecycleGridLayout: - id: row_controller - key_selection: "selectable" - cols: root.total_col_headings - cols_minimum: root.cols_minimum - default_size: None, dp(52) - default_size_hint: 1, None - size_hint: None, None - height: self.minimum_height - width: self.minimum_width - multiselect: True - touch_multiselect: True - - - - adaptive_height: True - spacing: "8dp" - - MDLabel: - text: "Rows per page" - shorten: True - halign: "right" - font_style: "Caption" - color: - (1, 1, 1, 1) \ - if root.theme_cls.theme_style == "Dark" else \ - (0, 0, 0, 1) - - MDDropDownItem: - id: drop_item - pos_hint: {'center_y': .5} - font_size: "14sp" - on_release: root.table_data.open_pagination_menu() - text: - "{}".format( \ - root.table_data.rows_num \ - if root.table_data.rows_num < len(root.table_data.row_data) else \ - len(root.table_data.row_data) \ - ) - - Widget: - size_hint_x: None - width: "32dp" if DEVICE_TYPE != "mobile" else "8dp" - - MDLabel: - id: label_rows_per_page - adaptive_size: True - -text_size: None, None - pos_hint: {"center_y": .5} - font_style: "Caption" - color: - (1, 1, 1, 1) \ - if root.theme_cls.theme_style == "Dark" else \ - (0, 0, 0, 1) - text: - "1-{} of {}".format( \ - root.table_data.rows_num \ - if root.table_data.rows_num > len(root.table_data.row_data) else \ - len(root.table_data.row_data), len(root.table_data.row_data) \ - ) - - MDIconButton: - id: button_back - icon: "chevron-left" - user_font_size: "20sp" if DEVICE_TYPE != "mobile" else "16dp" - ripple_scale: .5 if DEVICE_TYPE == "mobile" else 1 - pos_hint: {'center_y': .5} - disabled: True - md_bg_color_disabled: 0, 0, 0, 0 - on_release: root.table_data.set_next_row_data_parts("back") - - MDIconButton: - id: button_forward - icon: "chevron-right" - user_font_size: "20sp" if DEVICE_TYPE != "mobile" else "16dp" - ripple_scale: .5 if DEVICE_TYPE == "mobile" else 1 - pos_hint: {'center_y': .5} - disabled: True - md_bg_color_disabled: 0, 0, 0, 0 - on_release: root.table_data.set_next_row_data_parts("forward") - - - - - - - - TableContainer: - id: container - orientation: "vertical" - elevation: root.elevation - shadow_radius: root.shadow_radius - shadow_softness: root.shadow_softness - shadow_offset: root.shadow_offset - shadow_color: root.shadow_color - shadow_color: root.shadow_color - shadow_softness_size: root.shadow_softness_size - padding: "24dp", "24dp", "8dp", "8dp" - md_bg_color: app.theme_cls.bg_normal diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/datatables.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/datatables.py deleted file mode 100644 index 44748a5..0000000 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/datatables/datatables.py +++ /dev/null @@ -1,2113 +0,0 @@ -""" -Components/DataTables -===================== - -.. seealso:: - - `Material Design spec, DataTables `_ - -.. rubric:: Data tables display sets of data across rows and columns. - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-previous.png - :align: center - -.. note:: `MDDataTable` allows developers to sort the data provided by column. - This happens thanks to the use of an external function that you can bind - while you're defining the table columns. Be aware that the sorting function - must return a 2 value list in the format of: - `[Index, Sorted_Row_Data]` - - This is because the index list is needed to allow MDDataTable to keep track - of the selected rows. and, after the data is sorted, update the row - checkboxes. - -""" - -# Special thanks for the info - -# https://stackoverflow.com/questions/50219281/python-how-to-add-vertical-scroll-in-recycleview - -__all__ = ("MDDataTable",) - -import os -from collections import defaultdict -from typing import Union - -from kivy.clock import Clock -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ( - BooleanProperty, - BoundedNumericProperty, - ColorProperty, - DictProperty, - ListProperty, - NumericProperty, - ObjectProperty, - OptionProperty, - StringProperty, - VariableListProperty, -) -from kivy.uix.anchorlayout import AnchorLayout -from kivy.uix.behaviors import ButtonBehavior, FocusBehavior -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.recyclegridlayout import RecycleGridLayout -from kivy.uix.recycleview import RecycleView -from kivy.uix.recycleview.layout import LayoutSelectionBehavior -from kivy.uix.recycleview.views import RecycleDataViewBehavior -from kivy.uix.scrollview import ScrollView - -from kivymd import uix_path -from kivymd.effects.stiffscroll import StiffScrollEffect -from kivymd.material_resources import ( - DATA_TABLE_ELEVATION, - DATA_TABLE_OFFSET, - DATA_TABLE_SOFTNESS, -) -from kivymd.theming import ThemableBehavior -from kivymd.uix.behaviors import HoverBehavior -from kivymd.uix.boxlayout import MDBoxLayout -from kivymd.uix.button import MDIconButton -from kivymd.uix.menu import MDDropdownMenu -from kivymd.uix.selectioncontrol import MDCheckbox -from kivymd.uix.tooltip import MDTooltip - -with open( - os.path.join(uix_path, "datatables", "datatables.kv"), encoding="utf-8" -) as kv_file: - Builder.load_string(kv_file.read()) - - -class TableRecycleGridLayout( - FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout -): - selected_row = NumericProperty(0) - table_data = ObjectProperty(None) - - def get_nodes(self): - nodes = self.get_selectable_nodes() - if self.nodes_order_reversed: - nodes = nodes[::-1] - if not nodes: - return None, None - - selected = self.selected_nodes - if not selected: # nothing selected, select the first - self.selected_row = 0 - self.select_row(nodes) - return None, None - - if len(nodes) == 1: # the only selectable node is selected already - return None, None - - index = selected[-1] - if index > len(nodes): - last = len(nodes) - else: - last = nodes.index(index) - self.clear_selection() - return last, nodes - - def select_next(self, instance): - """Select next row.""" - - self.table_data = instance - last, nodes = self.get_nodes() - if not nodes: - return - - if last == len(nodes) - 1: - self.selected_row = nodes[0] - else: - self.selected_row = nodes[last + 1] - - self.selected_row += self.table_data.total_col_headings - self.select_row(nodes) - - def select_current(self, instance): - """Select current row.""" - - self.table_data = instance - last, nodes = self.get_nodes() - if not nodes: - return - - self.select_row(nodes) - - def select_row(self, nodes): - col = self.table_data.recycle_data[self.selected_row]["range"] - for x in range(col[0], col[1] + 1): - self.select_node(nodes[x]) - - -class CellHeader(MDTooltip, BoxLayout): - """ - Implements the label text in the column header panel from - :attr:`~MDDataTable.column_data` data. - """ - - text = StringProperty() - """ - Column text. - - :attr:`text` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - tooltip = StringProperty() - """ - Tooltip containing descriptive text for the column. - If the tooltip is not provided, column `text` shall be used instead. - - :attr:`tooltip` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - # TODO: Added example. - sort_action = ObjectProperty() - """ - Custom function for sorting. - - :attr:`sort_action` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - table_data = ObjectProperty() - """ - :class:`~TableData` class. - - :attr:`table_data` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - is_sorted = BooleanProperty(False) - sorted_order = StringProperty() - - def __init__(self, *args, **kwargs): - super().__init__(**kwargs) - if self.sort_action: - box = self.ids.box - ib = SortButton() - ib.bind(on_release=self._sort_release) - - if self.is_sorted: - ib.icon = ( - "arrow-down" if self.sorted_order == "ASC" else "arrow-up" - ) - ib.size = [dp(24), dp(24)] - ib.opacity = 1 - else: - self.bind(on_enter=self.set_sort_btn) - self.bind(on_leave=self.set_sort_btn) - - box.add_widget(ib, index=1) - - def restore_checks(self, indices: dict) -> None: - curr_checks = self.table_data.current_selection_check - rows_num = self.table_data.rows_num - columns = self.table_data.total_col_headings - - new_checks = defaultdict(list) - for i, x in enumerate(curr_checks): - for j, y in enumerate(curr_checks[x]): - new_page = (indices[y // columns + x * rows_num]) // rows_num - new_indice = ( - (indices[y // columns + x * rows_num]) % rows_num - ) * columns - new_checks[new_page].append(new_indice) - self.table_data.current_selection_check = dict(new_checks) - - def set_sort_btn(self, instance_cell_header) -> None: - btn = instance_cell_header.ids.box.children[-1] - if btn.opacity: - btn.size = [dp(24), dp(0)] - btn.opacity = 0 - else: - btn.size = [dp(24), dp(24)] - btn.opacity = 1 - - def _sort_release(self, inst): - inst.icon = "arrow-down" if inst.icon == "arrow-up" else "arrow-up" - - if not self.parent.parent._col_with_sort: - c = self.parent.children - col_with_sort = [ - each - for each in c - if each.ids.get("box", None) and len(each.ids.box.children) == 2 - ] - self.parent.parent._col_with_sort = col_with_sort - else: - col_with_sort = self.parent.parent._col_with_sort - - for each in col_with_sort: - if each == self: - self.unbind(on_enter=self.set_sort_btn) - self.unbind(on_leave=self.set_sort_btn) - else: - btn = each.ids.box.children[-1] - btn.size = [dp(24), dp(0)] - btn.opacity = 0 - each.bind(on_enter=each.set_sort_btn) - each.bind(on_leave=each.set_sort_btn) - - if self.sort_action: - if not self.table_data: - th = self.parent.parent - self.table_data = th.table_data - - indices, sorted_data = self.sort_action(self.table_data.row_data) - - if not sorted_data: - return - - if inst.icon == "arrow-down": - sorted_data = sorted_data[::-1] - indices = indices[::-1] - - self.table_data.row_data = sorted_data - self.table_data.on_rows_num(self, self.table_data.rows_num) - self.restore_checks(dict(zip(indices, range(len(indices))))) - self.table_data.set_next_row_data_parts("reset") - self.table_data.cell_row_obj_dict = {} - self.table_data.table_header.ids.check.state = "normal" - - -class TableHeader(ThemableBehavior, ScrollView): - """ - Implements a panel for column heading labels - - :attr:`~MDDataTable.column_data`. - """ - - table_data = ObjectProperty() - """ - Class :class:`~TableData`. - - :attr:`table_data` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - column_data = ListProperty() - """ - See :attr:`~MDDataTable.sorted_on` - - :attr:`column_data` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - sorted_on = StringProperty() - """ - See :attr:`~MDDataTable.sorted_on`. - - :attr:`sorted_on` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - cols_minimum = DictProperty() - """ - See :attr:`~kivy.uix.gridlayout.GridLayout.cols_minimum`. - - :attr:`cols_minimum` is an :class:`~kivy.properties.DictProperty` - and defaults to `{}`. - """ - - sorted_order = StringProperty() - """ - See :attr:`~MDDataTable.sorted_order`. - - :attr:`sorted_order` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - background_color_header = ColorProperty(None) - """ - See :attr:`~MDDataTable.background_color_header`. - - .. versionadded:: 1.0.0 - - :attr:`background_color_header` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - _col_with_sort = [] # store cols which contain sort functions - _col_headings = ListProperty() # column names list - - def __init__(self, **kwargs): - super().__init__(**kwargs) - # Create cells. - for i, col_heading in enumerate(self.column_data): - self.cols_minimum[i] = col_heading[1] * 5 - self._col_headings.append(col_heading[0]) - if i: - self.ids.header.add_widget( - ( - CellHeader( - text=col_heading[0], - sort_action=col_heading[2], - tooltip=col_heading[3], - width=self.cols_minimum[i], - table_data=self.table_data, - is_sorted=(col_heading[0] == self.sorted_on), - sorted_order=self.sorted_order, - ) - if len(col_heading) == 4 - else CellHeader( - text=col_heading[0], - sort_action=col_heading[2], - width=self.cols_minimum[i], - table_data=self.table_data, - ) - if len(col_heading) == 3 - else CellHeader( - text=col_heading[0], - width=self.cols_minimum[i], - table_data=self.table_data, - ) - ) - ) - else: - # Sets the text in the first cell. - self.ids.first_cell.text = col_heading[0] - self.ids.first_cell.tooltip = ( - col_heading[3] if len(col_heading) == 4 else "" - ) - self.ids.first_cell.ids.separator.height = 0 - self.ids.first_cell.width = self.cols_minimum[i] - - def on_table_data(self, instance_table_header, instance_table_data) -> None: - """Sets the checkbox in the first cell.""" - - if self.table_data.check: - self.ids.check.size = (dp(32), dp(32)) - self.ids.check.opacity = 1 - else: - self.ids.box.padding[0] = 0 - self.ids.box.spacing = 0 - - -class TableData(RecycleView): - """Implements a list of table data.""" - - recycle_data = ListProperty() - """ - See :attr:`~kivy.uix.recycleview.RecycleView.data`. - - :attr:`recycle_data` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - data_first_cells = ListProperty() - """ - List of first row cells. - - :attr:`data_first_cells` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - row_data = ListProperty() - """ - See :attr:`~MDDataTable.row_data`. - - :attr:`row_data` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - total_col_headings = NumericProperty(0) # TableHeader._col_headings - """ - See :attr:`~TableHeader._col_headings`. - - :attr:`total_col_headings` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0`. - """ - - cols_minimum = DictProperty() - """ - See :attr:`~TableHeader.cols_minimum`. - - :attr:`cols_minimum` is an :class:`~kivy.properties.DictProperty` - and defaults to `{}`. - """ - - table_header = ObjectProperty() - """ - :class:`~TableHeader` class. - - :attr:`table_header` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - pagination_menu = ObjectProperty() - """ - :class:`~kivymd.uix.menu.MDDropdownMenu` class. - - :attr:`pagination_menu` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - pagination = ObjectProperty() - """ - :class:`~TablePagination` class. - - :attr:`pagination` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - check = ObjectProperty() - """ - See :attr:`~MDDataTable.check`. - - :attr:`check` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - rows_num = NumericProperty() - """ - Number of rows displayed on the table page. - - :attr:`rows_num` is an :class:`~kivy.properties.NumericProperty` - and defaults to `None`. - """ - - pagination_menu_open = BooleanProperty(False) - """ - Open or close the menu for selecting the number of rows displayed - on the table page. - - :attr:`pagination_menu_open` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - current_selection_check = DictProperty() - """ - List of indexes of marked checkboxes. - - :attr:`current_selection_check` is an :class:`~kivy.properties.DictProperty` - and defaults to `{}`. - """ - - cell_row_obj_dict = {} - - _parent = ObjectProperty() - _rows_number = NumericProperty(0) - _rows_num = NumericProperty() - _current_value = NumericProperty(1) - _to_value = NumericProperty() - _row_data_parts = ListProperty() - - def __init__(self, table_header, **kwargs): - super().__init__(**kwargs) - self.table_header = table_header - self.total_col_headings = len(table_header._col_headings) - self.cols_minimum = table_header.cols_minimum - self.set_row_data() - self.effect_cls = self._parent.effect_cls - Clock.schedule_once(self.set_default_first_row, 0) - - def get_select_row(self, index: int) -> None: - """Returns the current row with all elements.""" - - row = [] - for data in self.recycle_data: - if index in data["range"]: - row.append(data["text"]) - self._parent.dispatch("on_check_press", row) - self._get_row_checks() # update the dict - - def set_default_first_row(self, interval: Union[int, float]) -> None: - """Set default first row as selected.""" - - self.ids.row_controller.select_next(self) - - def set_row_data(self) -> None: - data = [] - low = 0 - high = self.total_col_headings - 1 - self.recycle_data = [] - self.data_first_cells = [] - - if self._row_data_parts: - # for row in self.row_data: - for row in self._row_data_parts[self._rows_number]: - for i in range(len(row)): - data.append([row[i], row[0], [low, high]]) - low += self.total_col_headings - high += self.total_col_headings - - for j, x in enumerate(data): - if x[0] == x[1]: - self.data_first_cells.append(x[2][0]) - self.recycle_data.append( - { - "text": str(x[0]), - "Index": str(j), - "range": x[2], - "selectable": True, - "viewclass": "CellRow", - "table": self, - "background_color_cell": self._parent.background_color_cell, - "background_color_selected_cell": self._parent.background_color_selected_cell, - } - ) - else: - r_data = { - "Index": str(j), - "range": x[2], - "selectable": True, - "viewclass": "CellRow", - "table": self, - "background_color_cell": self._parent.background_color_cell, - "background_color_selected_cell": self._parent.background_color_selected_cell, - } - - if ( - isinstance(x[0], tuple) or isinstance(x[0], list) - ) and len(x[0]) == 3: - r_data["icon"] = x[0][0] - r_data["icon_color"] = x[0][1] - r_data["text"] = str(x[0][2]) - self.recycle_data.append(r_data) - - elif ( - isinstance(x[0], tuple) or isinstance(x[0], list) - ) and len(x[0]) == 2: - r_data["icon"] = x[0][0] - r_data["text"] = str(x[0][1]) - - self.recycle_data.append(r_data) - - else: - r_data["text"] = str(x[0]) - self.recycle_data.append(r_data) - - if not self.table_header.column_data: - raise ValueError("Set value for column_data in class TableData") - self.data_first_cells.append(self.table_header.column_data[0][0]) - - def set_text_from_of(self, direction: str) -> None: - """Sets the text of the numbers of displayed pages in table.""" - - if self.pagination: - if direction == "reset": - self._current_value = 1 - self._to_value = len(self._row_data_parts[self._rows_number]) - elif direction == "forward": - if ( - len(self._row_data_parts[self._rows_number]) - < self._to_value - ): - self._current_value = self._current_value + self.rows_num - else: - self._current_value = self._current_value + len( - self._row_data_parts[self._rows_number] - ) - self._to_value = self._to_value + len( - self._row_data_parts[self._rows_number] - ) - if direction == "back": - self._current_value = self._current_value - len( - self._row_data_parts[self._rows_number] - ) - self._to_value = self._to_value - len( - self._row_data_parts[self._rows_number + 1] - ) - if direction == "increment": - self._current_value = 1 - self._to_value = self.rows_num + self._current_value - 1 - - self.pagination.ids.label_rows_per_page.text = ( - f"{self._current_value}-{self._to_value} " - f"of {len(self.row_data)}" - ) - - def select_all(self, state: str) -> None: - """Sets the checkboxes of all rows to the active/inactive position.""" - - for i in range(0, len(self.recycle_data), self.total_col_headings): - cell_row_obj = self.view_adapter.get_visible_view(i) - if cell_row_obj: - self.cell_row_obj_dict[i] = cell_row_obj - self.on_mouse_select(cell_row_obj) - cell_row_obj.ids.check.state = state - - if state == "down": - # select all checks on all pages - rows_num = self.rows_num - columns = self.total_col_headings - full_pages = len(self.row_data) // self.rows_num - left_over_rows = len(self.row_data) % self.rows_num - - new_checks = {} - for page in range(full_pages): - new_checks[page] = list(range(0, rows_num * columns, columns)) - - if left_over_rows: - new_checks[full_pages] = list( - range(0, left_over_rows * columns, columns) - ) - - self.current_selection_check = new_checks - return - - # resets all checks on all pages - self.current_selection_check = {} - - def check_all(self, state: str) -> bool: - """Checks if checkboxes of all rows are in the same state.""" - - tmp = [] - for i in range(0, len(self.recycle_data), self.total_col_headings): - if self.cell_row_obj_dict.get(i, None): - cell_row_obj = self.cell_row_obj_dict[i] - else: - cell_row_obj = self.view_adapter.get_visible_view(i) - if cell_row_obj: - self.cell_row_obj_dict[i] = cell_row_obj - if cell_row_obj: - tmp.append(cell_row_obj.ids.check.state == state) - return all(tmp) - - def close_pagination_menu(self, *args) -> None: - """Called when the pagination menu window is closed.""" - - self.pagination_menu_open = False - - def open_pagination_menu(self) -> None: - """Open pagination menu window.""" - - if self.pagination_menu.items: - self.pagination_menu_open = True - self.pagination_menu.open() - - def set_number_displayed_lines(self, text_item) -> None: - """ - Called when the user sets the number of pages displayed - in the table. - """ - - # self.rows_num = int(text_item) - self.rows_num = int(text_item) - self.set_next_row_data_parts("reset") - self.set_text_from_of("reset") - self.pagination_menu.caller.text = text_item - - def set_next_row_data_parts(self, direction: str) -> None: - """Called when switching the pages of the table.""" - - if direction == "reset": - self._rows_number = 0 - self.pagination.ids.button_back.disabled = True - self.pagination.ids.button_forward.disabled = False - elif direction == "forward": - self._rows_number += 1 - self.pagination.ids.button_back.disabled = False - elif direction == "back": - self._rows_number -= 1 - self.pagination.ids.button_forward.disabled = False - - self.set_row_data() - self.set_text_from_of(direction) - - if self._to_value == len(self.row_data): - self.pagination.ids.button_forward.disabled = True - if self._current_value == 1: - self.pagination.ids.button_back.disabled = True - - def on_mouse_select(self, instance_cell_row) -> None: - """Called on the ``on_enter`` event of the :class:`~CellRow` class.""" - - if not self.pagination_menu_open: - if self.ids.row_controller.selected_row != instance_cell_row.index: - self.ids.row_controller.selected_row = instance_cell_row.index - self.ids.row_controller.select_current(self) - - def on_rows_num(self, instance_table_date, value_rows_num: int) -> None: - if not self._to_value: - self._to_value = value_rows_num - - self._rows_number = 0 - self._row_data_parts = list( - self._split_list_into_equal_parts(self.row_data, value_rows_num) - ) - - def on_pagination( - self, instance_table_date, instance_table_pagination - ) -> None: - if self._to_value < len(self.row_data): - self.pagination.ids.button_forward.disabled = False - - def _split_list_into_equal_parts(self, lst, parts): - for i in range(0, len(lst), parts): - yield lst[i : i + parts] - - def _get_row_checks(self): - """Returns all rows that are checked.""" - - tmp = [] - for i in range(0, len(self.recycle_data), self.total_col_headings): - if self.cell_row_obj_dict.get(i, None): - cell_row_obj = self.cell_row_obj_dict[i] - else: - cell_row_obj = self.view_adapter.get_visible_view(i) - if cell_row_obj: - self.cell_row_obj_dict[i] = cell_row_obj - - if cell_row_obj and cell_row_obj.ids.check.state == "down": - idx = cell_row_obj.index - row = [] - for data in self.recycle_data: - if idx in data["range"]: - row.append(data["text"]) - - tmp.append(row) - return tmp - - # def on_pagination(self, instance_table, instance_pagination): - # if len(self._row_data_parts) <= self._to_value: - # instance_pagination.ids.button_forward.disabled = True - - -class TablePagination(MDBoxLayout): - """Pagination Container.""" - - table_data = ObjectProperty() - """ - :class:`~TableData` class. - - :attr:`table_data` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - -class MDDataTable(ThemableBehavior, AnchorLayout): - """ - Datatable class. - - For more information, see in the - :class:`~kivymd.theming.ThemableBehavior` and - :class:`~kivy.uix.anchorlayout.AnchorLayout` classes documentation. - - :Events: - :attr:`on_row_press` - Called when a table row is clicked. - :attr:`on_check_press` - Called when the check box in the table row is checked. - - .. rubric:: Use events as follows - - .. code-block:: python - - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - from kivymd.uix.screen import MDScreen - - - class Example(MDApp): - def build(self): - self.data_tables = MDDataTable( - use_pagination=True, - check=True, - column_data=[ - ("No.", dp(30)), - ("Status", dp(30)), - ("Signal Name", dp(60), self.sort_on_signal), - ("Severity", dp(30)), - ("Stage", dp(30)), - ("Schedule", dp(30), self.sort_on_schedule), - ("Team Lead", dp(30), self.sort_on_team), - ], - row_data=[ - ( - "1", - ("alert", [255 / 256, 165 / 256, 0, 1], "No Signal"), - "Astrid: NE shared managed", - "Medium", - "Triaged", - "0:33", - "Chase Nguyen", - ), - ( - "2", - ("alert-circle", [1, 0, 0, 1], "Offline"), - "Cosmo: prod shared ares", - "Huge", - "Triaged", - "0:39", - "Brie Furman", - ), - ( - "3", - ( - "checkbox-marked-circle", - [39 / 256, 174 / 256, 96 / 256, 1], - "Online", - ), - "Phoenix: prod shared lyra-lists", - "Minor", - "Not Triaged", - "3:12", - "Jeremy lake", - ), - ( - "4", - ( - "checkbox-marked-circle", - [39 / 256, 174 / 256, 96 / 256, 1], - "Online", - ), - "Sirius: NW prod shared locations", - "Negligible", - "Triaged", - "13:18", - "Angelica Howards", - ), - ( - "5", - ( - "checkbox-marked-circle", - [39 / 256, 174 / 256, 96 / 256, 1], - "Online", - ), - "Sirius: prod independent account", - "Negligible", - "Triaged", - "22:06", - "Diane Okuma", - ), - ], - sorted_on="Schedule", - sorted_order="ASC", - elevation=2, - ) - self.data_tables.bind(on_row_press=self.on_row_press) - self.data_tables.bind(on_check_press=self.on_check_press) - screen = MDScreen() - screen.add_widget(self.data_tables) - return screen - - def on_row_press(self, instance_table, instance_row): - '''Called when a table row is clicked.''' - - print(instance_table, instance_row) - - def on_check_press(self, instance_table, current_row): - '''Called when the check box in the table row is checked.''' - - print(instance_table, current_row) - - # Sorting Methods: - # since the https://github.com/kivymd/KivyMD/pull/914 request, the - # sorting method requires you to sort out the indexes of each data value - # for the support of selections. - # - # The most common method to do this is with the use of the builtin function - # zip and enumerate, see the example below for more info. - # - # The result given by these funcitons must be a list in the format of - # [Indexes, Sorted_Row_Data] - - def sort_on_signal(self, data): - return zip(*sorted(enumerate(data), key=lambda l: l[1][2])) - - def sort_on_schedule(self, data): - return zip( - *sorted( - enumerate(data), - key=lambda l: sum( - [ - int(l[1][-2].split(":")[0]) * 60, - int(l[1][-2].split(":")[1]), - ] - ), - ) - ) - - def sort_on_team(self, data): - return zip(*sorted(enumerate(data), key=lambda l: l[1][-1])) - - - Example().run() - """ - - column_data = ListProperty() - """ - Data for header columns. - - .. tabs:: - - .. tab:: Imperative python style - - .. code-block:: python - - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - from kivy.uix.anchorlayout import AnchorLayout - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - layout = AnchorLayout() - self.data_tables = MDDataTable( - size_hint=(0.7, 0.6), - use_pagination=True, - check=True, - # name column, width column, sorting function column(optional), custom tooltip - column_data=[ - ("No.", dp(30), None, "Custom tooltip"), - ("Status", dp(30)), - ("Signal Name", dp(60)), - ("Severity", dp(30)), - ("Stage", dp(30)), - ("Schedule", dp(30), lambda *args: print("Sorted using Schedule")), - ("Team Lead", dp(30)), - ], - ) - layout.add_widget(self.data_tables) - return layout - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.anchorlayout import MDAnchorLayout - from kivymd.uix.datatables import MDDataTable - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return MDAnchorLayout( - MDDataTable( - size_hint=(0.7, 0.6), - use_pagination=True, - check=True, - # name column, width column, sorting function column(optional) - column_data=[ - ("No.", dp(30)), - ("Status", dp(30)), - ("Signal Name", dp(60)), - ("Severity", dp(30)), - ("Stage", dp(30)), - ("Schedule", dp(30), - lambda *args: print("Sorted using Schedule")), - ("Team Lead", dp(30)), - ], - ) - ) - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-column-data.png - :align: center - - :attr:`column_data` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - - .. note:: The functions which will be called for sorting must accept a data - argument and return the sorted data. Incoming data format will be - similar to the provided row_data except that it'll be all list instead - of tuple like below. Any icon provided initially will also be there in - this data so handle accordingly. - - .. code-block:: python - - [ - [ - "1", - ["icon", "No Signal"], - "Astrid: NE shared managed", - "Medium", - "Triaged", - "0:33", - "Chase Nguyen", - ], - [ - "2", - "Offline", - "Cosmo: prod shared ares", - "Huge", - "Triaged", - "0:39", - "Brie Furman", - ], - [ - "3", - "Online", - "Phoenix: prod shared lyra-lists", - "Minor", - "Not Triaged", - "3:12", - "Jeremy lake", - ], - [ - "4", - "Online", - "Sirius: NW prod shared locations", - "Negligible", - "Triaged", - "13:18", - "Angelica Howards", - ], - [ - "5", - "Online", - "Sirius: prod independent account", - "Negligible", - "Triaged", - "22:06", - "Diane Okuma", - ], - ] - - You must sort inner lists in ascending order and return the sorted data - in the same format. - """ - - row_data = ListProperty() - """ - Data for rows. To add icon in addition to a row data, include a tuple with - This property stores the row data used to display each row in the DataTable - To show an icon inside a column in a row, use the folowing format in the - row's columns. - - Format: - - `("MDicon-name", [icon color in rgba], "Column Value")` - - Example: - - .. code-block:: python - [...] - row_data = [ - - # row 1 - [ - "value 1", - "value 2", - # the third value will have an icon inside the box - ["home", [128/255, 48/255, 76/255, 1], "Offie" ] - ], - - # row 2 - [ - "value 1", - "value 2", - # the third value will have an icon inside the box - ["git", [1, 0.1, 0.1, 1], "Git Repo" ] - ] - ] - - For a more complex example see below. - - .. code-block:: python - - from kivy.metrics import dp - from kivy.uix.anchorlayout import AnchorLayout - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - layout = AnchorLayout() - data_tables = MDDataTable( - size_hint=(0.9, 0.6), - column_data=[ - ("Column 1", dp(20)), - ("Column 2", dp(30)), - ("Column 3", dp(50), self.sort_on_col_3), - ("Column 4", dp(30)), - ("Column 5", dp(30)), - ("Column 6", dp(30)), - ("Column 7", dp(30), self.sort_on_col_2), - ], - row_data=[ - # The number of elements must match the length - # of the `column_data` list. - ( - "1", - ("alert", [255 / 256, 165 / 256, 0, 1], "No Signal"), - "Astrid: NE shared managed", - "Medium", - "Triaged", - "0:33", - "Chase Nguyen", - ), - ( - "2", - ("alert-circle", [1, 0, 0, 1], "Offline"), - "Cosmo: prod shared ares", - "Huge", - "Triaged", - "0:39", - "Brie Furman", - ), - ( - "3", - ( - "checkbox-marked-circle", - [39 / 256, 174 / 256, 96 / 256, 1], - "Online", - ), - "Phoenix: prod shared lyra-lists", - "Minor", - "Not Triaged", - "3:12", - "Jeremy lake", - ), - ( - "4", - ( - "checkbox-marked-circle", - [39 / 256, 174 / 256, 96 / 256, 1], - "Online", - ), - "Sirius: NW prod shared locations", - "Negligible", - "Triaged", - "13:18", - "Angelica Howards", - ), - ( - "5", - ( - "checkbox-marked-circle", - [39 / 256, 174 / 256, 96 / 256, 1], - "Online", - ), - "Sirius: prod independent account", - "Negligible", - "Triaged", - "22:06", - "Diane Okuma", - ), - ], - ) - layout.add_widget(data_tables) - return layout - - def sort_on_col_3(self, data): - return zip( - *sorted( - enumerate(data), - key=lambda l: l[1][3] - ) - ) - - def sort_on_col_2(self, data): - return zip( - *sorted( - enumerate(data), - key=lambda l: l[1][-1] - ) - ) - - Example().run() - - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-row-data.png - :align: center - - :attr:`row_data` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. - """ - - sorted_on = StringProperty() - """ - Column name upon which the data is already sorted. - - If the table data is showing an already sorted data then this can be used - to indicate upon which column the data is sorted. - - :attr:`sorted_on` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - sorted_order = OptionProperty("ASC", options=["ASC", "DSC"]) - """ - Order of already sorted data. Must be one of `'ASC'` for ascending or - `'DSC'` for descending order. - - :attr:`sorted_order` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'ASC'`. - """ - - check = BooleanProperty(False) - """ - Use or not use checkboxes for rows. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-check.png - :align: center - - :attr:`check` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - use_pagination = BooleanProperty(False) - """ - Use page pagination for table or not. - - .. code-block:: python - - from kivy.metrics import dp - from kivy.uix.anchorlayout import AnchorLayout - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - layout = AnchorLayout() - data_tables = MDDataTable( - size_hint=(0.9, 0.6), - use_pagination=True, - column_data=[ - ("No.", dp(30)), - ("Column 1", dp(30)), - ("Column 2", dp(30)), - ("Column 3", dp(30)), - ("Column 4", dp(30)), - ("Column 5", dp(30)), - ], - row_data=[ - (f"{i + 1}", "1", "2", "3", "4", "5") for i in range(50) - ], - ) - layout.add_widget(data_tables) - return layout - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-use-pagination.png - :align: center - - :attr:`use_pagination` is an :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - elevation = NumericProperty(DATA_TABLE_ELEVATION) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.elevation` - attribute. - - :attr:`elevation` is an :class:`~kivy.properties.NumericProperty` - and defaults to `4`. - """ - - shadow_radius = VariableListProperty([6], length=4) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_radius` - attribute. - - .. versionadded:: 1.2.0 - - :attr:`shadow_radius` is an :class:`~kivy.properties.VariableListProperty` - and defaults to `[6]`. - """ - - shadow_softness = NumericProperty(DATA_TABLE_SOFTNESS) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_softness` - attribute. - - .. versionadded:: 1.2.0 - - :attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty` - and defaults to `12`. - """ - - shadow_softness_size = BoundedNumericProperty(2, min=2) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_softness_size` - attribute. - - .. versionadded:: 1.2.0 - - :attr:`shadow_softness_size` is an :class:`~kivy.properties.BoundedNumericProperty` - and defaults to `2`. - """ - - shadow_offset = ListProperty(DATA_TABLE_OFFSET) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_offset` - attribute. - - .. versionadded:: 1.2.0 - - :attr:`shadow_offset` is an :class:`~kivy.properties.ListProperty` - and defaults to `(0, 2)`. - """ - - shadow_color = ColorProperty([0, 0, 0, 0.6]) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_color` - attribute. - - .. versionadded:: 1.2.0 - - :attr:`shadow_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 0.6]`. - """ - - rows_num = NumericProperty(5) - """ - The number of rows displayed on one page of the table. - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-use-pagination-rows-num.png - :align: center - - :attr:`rows_num` is an :class:`~kivy.properties.NumericProperty` - and defaults to `10`. - """ - - pagination_menu_pos = OptionProperty( - "top", options=["center", "auto", "top"] - ) - """ - Menu position for selecting the number of displayed rows. - Available options are `'center'`, `'auto'`. - - .. rubric:: Center - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-pos-top.png - :align: center - - .. rubric:: Auto - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-pos-auto.png - :align: center - - :attr:`pagination_menu_pos` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'center'`. - """ - - pagination_menu_height = NumericProperty("140dp") - """ - Menu height for selecting the number of displayed rows. - - .. rubric:: 240dp - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-height-240.png - :align: center - - :attr:`pagination_menu_height` is an :class:`~kivy.properties.NumericProperty` - and defaults to `'140dp'`. - """ - - background_color = ColorProperty([0, 0, 0, 0]) - """ - Background color in the format (r, g, b, a) or string format. - See :attr:`~kivy.uix.modalview.ModalView.background_color`. - - Use markup strings - ------------------ - - .. code-block:: python - - from kivy.metrics import dp - from kivy.uix.anchorlayout import AnchorLayout - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - layout = AnchorLayout() - data_tables = MDDataTable( - size_hint=(0.9, 0.6), - use_pagination=True, - column_data=[ - ("No.", dp(30)), - ("Column 1", dp(30)), - ("[color=#52251B]Column 2[/color]", dp(30)), - ("Column 3", dp(30)), - ("[size=24][color=#C042B8]Column 4[/color][/size]", dp(30)), - ("Column 5", dp(30)), - ], - row_data=[ - ( - f"{i + 1}", - "[color=#297B50]1[/color]", - "[color=#C552A1]2[/color]", - "[color=#6C9331]3[/color]", - "4", - "5", - ) - for i in range(50) - ], - ) - layout.add_widget(data_tables) - return layout - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/datatables-use-markup-strings.png - :align: center - - :attr:`background_color` is a :class:`~kivy.properties.ColorProperty` and - defaults to `[0, 0, 0, 0]`. - """ - - background_color_header = ColorProperty(None) - """ - Background color in the format (r, g, b, a) or string format for - :class:`~TableHeader` class. - - .. versionadded:: 1.0.0 - - .. code-block:: python - - self.data_tables = MDDataTable( - ..., - background_color_header="#65275d", - ) - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-header.png - :align: center - - :attr:`background_color_header` is a :class:`~kivy.properties.ColorProperty` and - defaults to `None`. - """ - - background_color_cell = ColorProperty(None) - """ - Background color in the format (r, g, b, a) or string format for - :class:`~CellRow` class. - - .. versionadded:: 1.0.0 - - .. code-block:: python - - self.data_tables = MDDataTable( - ..., - background_color_header="#65275d", - background_color_cell="#451938", - ) - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-cell.png - :align: center - - :attr:`background_color_cell` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - background_color_selected_cell = ColorProperty(None) - """ - Background selected color in the format (r, g, b, a) or string format for - :class:`~CellRow` class. - - .. versionadded:: 1.0.0 - - .. code-block:: python - - self.data_tables = MDDataTable( - ..., - background_color_header="#65275d", - background_color_cell="#451938", - background_color_selected_cell="e4514f", - ) - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-selected-cell.png - :align: center - - :attr:`background_color_selected_cell` is a :class:`~kivy.properties.ColorProperty` and - defaults to `None`. - """ - - effect_cls = ObjectProperty(StiffScrollEffect) - """ - Effect class. See ``kivy/effects`` package for more information. - - .. versionadded:: 1.0.0 - - :attr:`effect_cls` is an :class:`~kivy.properties.ObjectProperty` - and defaults to :class:`~kivymd.effects.stiffscroll.StiffScrollEffect`. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.header = TableHeader( - column_data=self.column_data, - sorted_on=self.sorted_on, - sorted_order=self.sorted_order, - background_color_header=self.background_color_header, - ) - self.table_data = TableData( - self.header, - row_data=self.row_data, - check=self.check, - rows_num=self.rows_num, - _parent=self, - ) - self.register_event_type("on_row_press") - self.register_event_type("on_check_press") - self.pagination = TablePagination(table_data=self.table_data) - self.table_data.pagination = self.pagination - self.header.table_data = self.table_data - self.table_data.fbind("scroll_x", self._scroll_with_header) - self.ids.container.add_widget(self.header) - self.ids.container.add_widget(self.table_data) - if self.use_pagination: - self.ids.container.add_widget(self.pagination) - Clock.schedule_once(self.create_pagination_menu, 0.5) - self.bind(row_data=self.update_row_data) - - def update_row_data(self, instance_data_table, data: list) -> None: - """ - Called when a the widget data must be updated. - - Remember that this is a heavy function. since the whole data set must - be updated. you can get better results calling this metod with in a - coroutine. - """ - - self.table_data.row_data = data - self.row_data = data - self.table_data.on_rows_num(self, self.table_data.rows_num) - # Set cursors to 0. - self.table_data._rows_number = 0 - self.table_data._current_value = 1 - - if len(data) < self.table_data.rows_num: - self.table_data._to_value = len(data) - self.table_data.pagination.ids.button_forward.disabled = True - else: - self.table_data._to_value = self.table_data.rows_num - self.table_data.pagination.ids.button_forward.disabled = False - - self.table_data.set_next_row_data_parts("") - self.pagination.ids.button_back.disabled = True - if self.use_pagination: - Clock.schedule_once(self.create_pagination_menu, 0.5) - - def add_row(self, data: Union[list, tuple]) -> None: - """ - Added new row to common table. - Argument `data` is the row data from the list :attr:`row_data`. - - .. rubric:: Add/remove row - - .. code-block:: python - - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.floatlayout import MDFloatLayout - from kivymd.uix.button import MDRaisedButton - - - class Example(MDApp): - data_tables = None - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - layout = MDFloatLayout() # root layout - # Creating control buttons. - button_box = MDBoxLayout( - pos_hint={"center_x": 0.5}, - adaptive_size=True, - padding="24dp", - spacing="24dp", - ) - - for button_text in ["Add row", "Remove row"]: - button_box.add_widget( - MDRaisedButton( - text=button_text, on_release=self.on_button_press - ) - ) - - # Create a table. - self.data_tables = MDDataTable( - pos_hint={"center_y": 0.5, "center_x": 0.5}, - size_hint=(0.9, 0.6), - use_pagination=False, - column_data=[ - ("No.", dp(30)), - ("Column 1", dp(40)), - ("Column 2", dp(40)), - ("Column 3", dp(40)), - ], - row_data=[("1", "1", "2", "3")], - ) - # Adding a table and buttons to the toot layout. - layout.add_widget(self.data_tables) - layout.add_widget(button_box) - - return layout - - def on_button_press(self, instance_button: MDRaisedButton) -> None: - '''Called when a control button is clicked.''' - - try: - { - "Add row": self.add_row, - "Remove row": self.remove_row, - }[instance_button.text]() - except KeyError: - pass - - def add_row(self) -> None: - last_num_row = int(self.data_tables.row_data[-1][0]) - self.data_tables.add_row((str(last_num_row + 1), "1", "2", "3")) - - def remove_row(self) -> None: - if len(self.data_tables.row_data) > 1: - self.data_tables.remove_row(self.data_tables.row_data[-1]) - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-add-remove-row.gif - :align: center - - Deleting checked rows - --------------------- - - .. code-block:: python - - from kivy.metrics import dp - from kivy.lang import Builder - from kivy.clock import Clock - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - from kivymd.uix.screen import MDScreen - - KV = ''' - MDBoxLayout: - orientation: "vertical" - padding: "56dp" - spacing: "24dp" - - MDData: - id: table_screen - - MDRaisedButton: - text: "DELETE CHECKED ROWS" - on_release: table_screen.delete_checked_rows() - ''' - - - class MDData(MDScreen): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.data = [ - ["1", "Asep Sudrajat", "Male", "Soccer"], - ["2", "Egy", "Male", "Soccer"], - ["3", "Tanos", "Demon", "Soccer"], - ] - self.data_tables = MDDataTable( - use_pagination=True, - check=True, - column_data=[ - ("No", dp(30)), - ("No Urut.", dp(30)), - ("Alamat Pengirim", dp(30)), - ("No Surat", dp(60)), - ] - ) - self.data_tables.row_data = self.data - self.add_widget(self.data_tables) - - def delete_checked_rows(self): - def deselect_rows(*args): - self.data_tables.table_data.select_all("normal") - - for data in self.data_tables.get_row_checks(): - self.data_tables.remove_row(data) - - Clock.schedule_once(deselect_rows) - - - class MyApp(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return Builder.load_string(KV) - - - MyApp().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-deleting-checked-rows.gif - :align: center - - .. versionadded:: 1.0.0 - """ - - self.row_data.append(data) - - def remove_row(self, data: Union[list, tuple]) -> None: - """ - Removed row from common table. - Argument `data` is the row data from the list :attr:`row_data`. - - See the code in the doc string for the :attr:`add_row` method for more - information. - - .. versionadded:: 1.0.0 - """ - - self.row_data.remove(data) - - def update_row( - self, old_data: Union[list, tuple], new_data: Union[list, tuple] - ) -> None: - """ - Updates a table row. - Argument `old_data/new_data` is the row data from the list :attr:`row_data`. - - .. rubric:: Update row - - .. code-block:: python - - from kivy.metrics import dp - - from kivymd.app import MDApp - from kivymd.uix.datatables import MDDataTable - from kivymd.uix.floatlayout import MDFloatLayout - from kivymd.uix.button import MDRaisedButton - - - class Example(MDApp): - data_tables = None - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - - layout = MDFloatLayout() - layout.add_widget( - MDRaisedButton( - text="Change 2 row", - pos_hint={"center_x": 0.5}, - on_release=self.update_row, - y=24, - ) - ) - self.data_tables = MDDataTable( - pos_hint={"center_y": 0.5, "center_x": 0.5}, - size_hint=(0.9, 0.6), - use_pagination=False, - column_data=[ - ("No.", dp(30)), - ("Column 1", dp(40)), - ("Column 2", dp(40)), - ("Column 3", dp(40)), - ], - row_data=[(f"{i + 1}", "1", "2", "3") for i in range(3)], - ) - layout.add_widget(self.data_tables) - - return layout - - def update_row(self, instance_button: MDRaisedButton) -> None: - self.data_tables.update_row( - self.data_tables.row_data[1], # old row data - ["2", "A", "B", "C"], # new row data - ) - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-change-row.gif - :align: center - - .. versionadded:: 1.0.0 - """ - - for data in self.row_data: - if data == old_data: - index_data = self.row_data.index(data) - self.row_data[index_data] = new_data - break - - def on_row_press(self, instance_cell_row) -> None: - """Called when a table row is clicked.""" - - def on_check_press(self, row_data: list) -> None: - """ - Called when the check box in the table row is checked. - - :param row_data: One of the elements from the :attr:`MDDataTable.row_data` list. - """ - - def get_row_checks(self) -> list: - """Returns all rows that are checked.""" - - return self.table_data._get_row_checks() - - def create_pagination_menu(self, interval: Union[int, float]) -> None: - menu_items = [ - { - "text": f"{i}", - "viewclass": "OneLineListItem", - "height": dp(56), - "on_release": lambda x=f"{i}": self.table_data.set_number_displayed_lines( - x - ), - } - for i in range(self.rows_num, len(self.row_data), self.rows_num) - ] - pagination_menu = MDDropdownMenu( - caller=self.pagination.ids.drop_item, - items=menu_items, - position=self.pagination_menu_pos, - max_height=self.pagination_menu_height, - width_mult=2, - ) - pagination_menu.bind( - on_dismiss=self.table_data.close_pagination_menu, - ) - self.table_data.pagination_menu = pagination_menu - - def _scroll_with_header(self, instance, value): - self.header.scroll_x = value - - -class CellRow( - RecycleDataViewBehavior, - HoverBehavior, - ButtonBehavior, - MDBoxLayout, -): - """Implements a data row from :attr:`~MDDataTable.column_data`.""" - - background_color_cell = ColorProperty(None) - """ - See :attr:`~MDDataTable.background_color_cell.`. - - .. versionadded:: 1.0.0 - - :attr:`background_color_cell` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - background_color_selected_cell = ColorProperty(None) - """ - See :attr:`~MDDataTable.background_color_selected_cell.`. - - .. versionadded:: 1.0.0 - - :attr:`background_color_selected_cell` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - text = StringProperty() - """ - Row text. - - :attr:`text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - table = ObjectProperty() - """ - Class class:`~TableData`. - - :attr:`table` is a :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - icon = StringProperty() - """ - Row icon name. - - :attr:`icon` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - icon_color = ColorProperty(None) - """ - Row icon color. - - :attr:`icon_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - selected = BooleanProperty(False) - selectable = BooleanProperty(True) - index = None - icon_copy = icon - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.ids.check.bind(active=self.select_check) - self.ids.check.bind(active=self.notify_checkbox_click) - - def notify_checkbox_click( - self, instance_check: MDCheckbox, active: bool - ) -> None: - """Called when the table row checkbox is activated/deactivated.""" - - self.table.get_select_row(self.index) - - def refresh_view_attrs( - self, instance_table_data: TableData, index: int, data: dict - ): - """ - Called by the :class:`RecycleAdapter` when the view is initially - populated with the values from the `data` dictionary for this item. - - Any pos or size info should be removed because they are set - subsequently with :attr:`refresh_view_layout`. - - :Parameters: - - `table_data`: :class:`TableData` instance - The :class:`TableData` that caused the update. - `data`: dict - The data dict used to populate this view. - """ - - self.index = index - return super().refresh_view_attrs(instance_table_data, index, data) - - def apply_selection( - self, instance_table_data: TableData, index: int, is_selected: bool - ) -> None: - """Called when list items of table appear on the screen.""" - - self.selected = is_selected - - # Fixes cloning of icons. - ic = instance_table_data.recycle_data[index].get("icon", None) - cell_row_obj = instance_table_data.view_adapter.get_visible_view(index) - - if not ic: - cell_row_obj.icon = "" - else: - cell_row_obj.icon = cell_row_obj.icon_copy - - # Set checkboxes. - if instance_table_data.check: - if self.index in instance_table_data.data_first_cells: - self.ids.check.size = (dp(32), dp(32)) - self.ids.check.opacity = 1 - self.ids.box.spacing = dp(16) - self.ids.box.padding[0] = dp(8) - else: - self.ids.check.size = (0, 0) - self.ids.check.opacity = 0 - self.ids.box.spacing = 0 - self.ids.box.padding[0] = 0 - - # Set checkboxes state. - if ( - instance_table_data._rows_number - in instance_table_data.current_selection_check - ): - for index in instance_table_data.current_selection_check[ - instance_table_data._rows_number - ]: - if ( - self.index - in instance_table_data.current_selection_check[ - instance_table_data._rows_number - ] - ): - self.change_check_state_no_notify("down") - else: - self.change_check_state_no_notify("normal") - else: - self.change_check_state_no_notify("normal") - - def change_check_state_no_notify(self, new_state: str) -> None: - checkbox = self.ids.check - checkbox.unbind(active=self.notify_checkbox_click) - checkbox.state = new_state - checkbox.bind(active=self.notify_checkbox_click) - - def select_check( - self, instance_table_data: MDDataTable, active: bool - ) -> None: - """Called upon activation/deactivation of the checkbox.""" - - if active: - if ( - self.table._rows_number - not in self.table.current_selection_check - ): - self.table.current_selection_check[self.table._rows_number] = [] - if ( - self.index - not in self.table.current_selection_check[ - self.table._rows_number - ] - ): - self.table.current_selection_check[ - self.table._rows_number - ].append(self.index) - else: - if self.table._rows_number in self.table.current_selection_check: - if ( - self.index - in self.table.current_selection_check[ - self.table._rows_number - ] - and not active - ): - self.table.current_selection_check[ - self.table._rows_number - ].remove(self.index) - - def on_touch_down(self, touch): - if super().on_touch_down(touch): - if self.table._parent: - self.table._parent.dispatch("on_row_press", self) - return True - - def on_icon(self, instance_cell_row, name_icon: str) -> None: - self.icon_copy = name_icon - - def on_table( - self, instance_cell_row, instance_table_data: TableData - ) -> None: - """Sets padding/spacing to zero if no checkboxes are used for rows.""" - - if not instance_table_data.check: - self.ids.box.padding = 0 - self.ids.box.spacing = 0 - - def _check_all(self, state): - """Checks if all checkboxes are in same state.""" - - if state == "down" and self.table.check_all(state): - self.table.table_header.ids.check.state = "down" - else: - self.table.table_header.ids.check.state = "normal" - - -class SortButton(MDIconButton): - """Implements a sort button in the :class:`~CellHeader` class.""" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__init__.py index 40adbe4..9fc91de 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__init__.py @@ -1 +1,8 @@ -from .dialog import BaseDialog, MDDialog # NOQA F401 +from .dialog import ( + MDDialog, + MDDialogIcon, + MDDialogHeadlineText, + MDDialogSupportingText, + MDDialogContentContainer, + MDDialogButtonContainer, +) # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc index 4668b8d..d27038f 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc index 03ecd8e..4a2d581 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/__pycache__/dialog.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.kv index 96e01a3..42eb3ae 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.kv @@ -1,90 +1,114 @@ -#:import images_path kivymd.images_path - - - - background: '{}/transparent.png'.format(images_path) - - canvas.before: - PushMatrix - RoundedRectangle: - pos: self.pos - size: self.size - radius: root.radius - Scale: - origin: self.center - x: root._scale_x - y: root._scale_y - canvas.after: - PopMatrix - - - - shadow_color: 0.0, 0.0, 0.0, 0.0 - elevation: 0 - shadow_softness: 0 - shadow_offset: 0, 0 - - + radius: root.radius + size_hint_min_x: "280dp" + size_hint_max_x: "560dp" + pos_hint: {"center_x": .5, "center_y": .5} + size_hint_y: None + height: container.height + theme_shadow_color: "Custom" + shadow_color: self.theme_cls.transparentColor + focus_behavior: False - DialogContainer: - id: container - orientation: "vertical" + RelativeLayout: size_hint_y: None - height: self.minimum_height - padding: "24dp", "24dp", "8dp", "8dp" - radius: root.radius - md_bg_color: - root.theme_cls.bg_dark \ - if not root.md_bg_color else root.md_bg_color - - MDLabel: - id: title - text: root.title - font_style: "H6" - bold: True - markup: True - size_hint_y: None - height: self.texture_size[1] - valign: "top" + height: container.height BoxLayout: - id: spacer_top_box + id: container + orientation: "vertical" size_hint_y: None - height: root._spacer_top + height: self.minimum_height + button_container.height + dp(24) + spacing: "16dp" + padding: "24dp" + y: button_container.height + dp(24) - MDLabel: - id: text - text: root.text - font_style: "Body1" - theme_text_color: "Custom" - text_color: root.theme_cls.disabled_hint_text_color - size_hint_y: None - height: self.texture_size[1] - markup: True + AnchorLayout: + id: icon_container + size_hint_y: None + anchor_x: "center" + height: self.children[0].height if self.children else 0 - ScrollView: - id: scroll - size_hint_y: None - height: root._scroll_height + BoxLayout: + id: headline_container + size_hint_y: None + height: self.minimum_height - MDGridLayout: - id: box_items - adaptive_height: True - cols: 1 + BoxLayout: + id: supporting_text_container + size_hint_y: None + height: self.minimum_height + + BoxLayout: + id: content_container + size_hint_y: None + height: self.minimum_height BoxLayout: - id: spacer_bottom_box + id: button_container size_hint_y: None height: self.minimum_height + y: content_container.y - AnchorLayout: - id: root_button_box - size_hint_y: None - height: "52dp" - anchor_x: "right" - MDBoxLayout: - id: button_box - adaptive_size: True - spacing: "8dp" + + size_hint: None, None + size: "24dp", "24dp" + theme_font_size: "Custom" + font_size: "24sp" + icon_color: + self.theme_cls.secondaryColor \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color \ + if self.icon_color else self.theme_cls.transparentColor \ + ) + + + + adaptive_height: True + halign: "center" + font_style: "Headline" + role: "small" + markup: True + color: + self.theme_cls.onSurfaceColor \ + if self.theme_text_color == "Primary" else ( \ + self.text_color \ + if self.text_color != self.theme_cls.transparentColor else \ + self.theme_cls.onSurfaceColor \ + ) + + + + adaptive_height: True + halign: "center" + font_style: "Body" + role: "medium" + markup: True + text_color: + self.theme_cls.onSurfaceVariantColor \ + if self.theme_text_color == "Primary" else ( \ + self.text_color \ + if self.text_color != self.theme_cls.transparentColor else \ + self.theme_cls.onSurfaceVariantColor \ + ) + + + + size_hint_y: None + height: self.minimum_height + + + + size_hint_y: None + height: self.minimum_height + padding: "24dp", 0, "24dp", 0 + + + + canvas: + Color: + rgba: self.color[:-1] + [self.alpha] + Rectangle: + pos: self.pos + size: self.size diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.py index 9f2db53..1eddfa1 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dialog/dialog.py @@ -4,182 +4,156 @@ Components/Dialog .. seealso:: - `Material Design spec, Dialogs `_ + `Material Design spec, Dialogs `_ -.. rubric:: Dialogs inform users about a task and can contain critical - information, require decisions, or involve multiple tasks. +.. rubric:: Dialogs provide important prompts in a user flow. -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialogs.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-preview.png :align: center -Usage ------ +- Use dialogs to make sure users act on information +- Two types: basic and full-screen (full-screen not provided in KivyMD) +- Should be dedicated to completing a single task +- Can also display information relevant to the task +- Commonly used to confirm high-risk actions like deleting progress + +Anatomy +======= + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-anatomy.png + :align: center + +Example +======= .. code-block:: python from kivy.lang import Builder + from kivy.uix.widget import Widget + + from kivymd.app import MDApp + from kivymd.uix.button import MDButton, MDButtonText + from kivymd.uix.dialog import ( + MDDialog, + MDDialogIcon, + MDDialogHeadlineText, + MDDialogSupportingText, + MDDialogButtonContainer, + MDDialogContentContainer, + ) + from kivymd.uix.divider import MDDivider + from kivymd.uix.list import ( + MDListItem, + MDListItemLeadingIcon, + MDListItemSupportingText, + ) + + KV = ''' + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDButton: + pos_hint: {'center_x': .5, 'center_y': .5} + on_release: app.show_alert_dialog() + + MDButtonText: + text: "Show dialog" + ''' + + + class Example(MDApp): + def build(self): + return Builder.load_string(KV) + + def show_alert_dialog(self): + MDDialog( + # ----------------------------Icon----------------------------- + MDDialogIcon( + icon="refresh", + ), + # -----------------------Headline text------------------------- + MDDialogHeadlineText( + text="Reset settings?", + ), + # -----------------------Supporting text----------------------- + MDDialogSupportingText( + text="This will reset your app preferences back to their " + "default settings. The following accounts will also " + "be signed out:", + ), + # -----------------------Custom content------------------------ + MDDialogContentContainer( + MDDivider(), + MDListItem( + MDListItemLeadingIcon( + icon="gmail", + ), + MDListItemSupportingText( + text="KivyMD-library@yandex.com", + ), + theme_bg_color="Custom", + md_bg_color=self.theme_cls.transparentColor, + ), + MDListItem( + MDListItemLeadingIcon( + icon="gmail", + ), + MDListItemSupportingText( + text="kivydevelopment@gmail.com", + ), + theme_bg_color="Custom", + md_bg_color=self.theme_cls.transparentColor, + ), + MDDivider(), + orientation="vertical", + ), + # ---------------------Button container------------------------ + MDDialogButtonContainer( + Widget(), + MDButton( + MDButtonText(text="Cancel"), + style="text", + ), + MDButton( + MDButtonText(text="Accept"), + style="text", + ), + spacing="8dp", + ), + # ------------------------------------------------------------- + ).open() + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-example.gif + :align: center + +.. warning:: Do not try to use the MDDialog widget in KV files. + +API break +========= + +1.2.0 version +------------- + +.. code-block:: python + + from kivy.uix.widget import Widget from kivymd.app import MDApp from kivymd.uix.button import MDFlatButton from kivymd.uix.dialog import MDDialog - KV = ''' - MDFloatLayout: - - MDFlatButton: - text: "ALERT DIALOG" - pos_hint: {'center_x': .5, 'center_y': .5} - on_release: app.show_alert_dialog() - ''' - class Example(MDApp): - dialog = None - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return Builder.load_string(KV) + return Widget() - def show_alert_dialog(self): - if not self.dialog: - self.dialog = MDDialog( - text="Discard draft?", - buttons=[ - MDFlatButton( - text="CANCEL", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - MDFlatButton( - text="DISCARD", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - ], - ) - self.dialog.open() - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/alert-dialog.png - :align: center -""" - -__all__ = ("MDDialog", "BaseDialog") - -import os - -from kivy.clock import Clock -from kivy.core.window import Window -from kivy.lang import Builder -from kivy.metrics import dp -from kivy.properties import ( - ColorProperty, - ListProperty, - NumericProperty, - ObjectProperty, - OptionProperty, - StringProperty, -) -from kivy.uix.modalview import ModalView - -from kivymd import uix_path -from kivymd.material_resources import DEVICE_TYPE -from kivymd.theming import ThemableBehavior -from kivymd.uix.behaviors import CommonElevationBehavior, MotionDialogBehavior -from kivymd.uix.button import BaseButton -from kivymd.uix.card import MDSeparator -from kivymd.uix.list import BaseListItem - -with open( - os.path.join(uix_path, "dialog", "dialog.kv"), encoding="utf-8" -) as kv_file: - Builder.load_string(kv_file.read()) - - -class BaseDialog( - ThemableBehavior, MotionDialogBehavior, ModalView, CommonElevationBehavior -): - elevation = NumericProperty(3) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.elevation` - attribute for more information. - - .. versionadded:: 1.1.0 - - :attr:`elevation` is an :class:`~kivy.properties.NumericProperty` - and defaults to `3`. - """ - - shadow_softness = NumericProperty(24) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_softness` - attribute for more information. - - .. versionadded:: 1.1.0 - - :attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty` - and defaults to `24`. - """ - - shadow_offset = ListProperty((0, 4)) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_offset` - attribute for more information. - - .. versionadded:: 1.1.0 - - :attr:`shadow_offset` is an :class:`~kivy.properties.ListProperty` - and defaults to `[0, 4]`. - """ - - radius = ListProperty([dp(7), dp(7), dp(7), dp(7)]) - """ - Dialog corners rounding value. - - .. code-block:: python - - [...] - self.dialog = MDDialog( - text="Oops! Something seems to have gone wrong!", - radius=[20, 7, 20, 7], - ) - [...] - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-radius.png - :align: center - - :attr:`radius` is an :class:`~kivy.properties.ListProperty` - and defaults to `[7, 7, 7, 7]`. - """ - - _scale_x = NumericProperty(1) - _scale_y = NumericProperty(1) - - -class MDDialog(BaseDialog): - """ - Dialog class. - - For more information, see in the - :class:`~kivymd.theming.ThemableBehavior` and - :class:`~kivy.uix.modalview.ModalView` and - :class:`~kivymd.uix.behaviors.CommonElevationBehavior` - classes documentation. - """ - - title = StringProperty() - """ - Title dialog. - - .. code-block:: python - - [...] - self.dialog = MDDialog( - title="Reset settings?", + def on_start(self): + MDDialog( + title="Discard draft?", buttons=[ MDFlatButton( text="CANCEL", @@ -187,30 +161,35 @@ class MDDialog(BaseDialog): text_color=self.theme_cls.primary_color, ), MDFlatButton( - text="ACCEPT", + text="DISCARD", theme_text_color="Custom", text_color=self.theme_cls.primary_color, ), ], - ) - [...] + ).open() - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-title.png - :align: center - :attr:`title` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ + Example().run() - text = StringProperty() - """ - Text dialog. +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-api-break-1-2-0.png + :align: center - .. code-block:: python +.. code-block:: python - [...] - self.dialog = MDDialog( - title="Reset settings?", + from kivy.uix.widget import Widget + + from kivymd.app import MDApp + from kivymd.uix.button import MDFlatButton + from kivymd.uix.dialog import MDDialog + + + class Example(MDApp): + def build(self): + return Widget() + + def on_start(self): + MDDialog( + title="Discard draft?", text="This will reset your device to its default factory settings.", buttons=[ MDFlatButton( @@ -219,198 +198,267 @@ class MDDialog(BaseDialog): text_color=self.theme_cls.primary_color, ), MDFlatButton( - text="ACCEPT", + text="DISCARD", theme_text_color="Custom", text_color=self.theme_cls.primary_color, ), ], - ) - [...] + ).open() - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-text.png - :align: center - :attr:`text` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ + Example().run() - buttons = ListProperty() - """ - List of button objects for dialog. - Objects must be inherited from :class:`~kivymd.uix.button.BaseButton` class. +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/2-dialog-api-break-1-2-0.png + :align: center - .. code-block:: python +.. code-block:: python - [...] - self.dialog = MDDialog( - text="Discard draft?", - buttons=[ - MDFlatButton(text="CANCEL"), MDRaisedButton(text="DISCARD"), + from kivy.lang import Builder + from kivy.properties import StringProperty + from kivy.uix.widget import Widget + + from kivymd import images_path + from kivymd.app import MDApp + from kivymd.uix.dialog import MDDialog + from kivymd.uix.list import OneLineAvatarListItem + + KV = ''' + + + ImageLeftWidget: + source: root.source + ''' + + + class Item(OneLineAvatarListItem): + divider = None + source = StringProperty() + + + class Example(MDApp): + def build(self): + Builder.load_string(KV) + return Widget() + + def on_start(self): + MDDialog( + title="Set backup account", + type="simple", + items=[ + Item(text="user01@gmail.com", source=f"{images_path}/logo/kivymd-icon-128.png"), + Item(text="user02@gmail.com", source="data/logo/kivy-icon-128.png"), ], - ) - [...] + ).open() - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-buttons.png - :align: center - :attr:`buttons` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/3-dialog-api-break-1-2-0.png + :align: center + +2.2.0 version +------------- + +.. code-block:: python + + from kivy.uix.widget import Widget + + from kivymd.uix.widget import MDWidget + from kivymd.app import MDApp + from kivymd.uix.button import MDButton, MDButtonText + from kivymd.uix.dialog import MDDialog, MDDialogHeadlineText, MDDialogButtonContainer + + + class Example(MDApp): + def build(self): + return MDWidget(md_bg_color=self.theme_cls.backgroundColor) + + def on_start(self): + MDDialog( + MDDialogHeadlineText( + text="Discard draft?", + halign="left", + ), + MDDialogButtonContainer( + Widget(), + MDButton( + MDButtonText(text="Cancel"), + style="text", + ), + MDButton( + MDButtonText(text="Discard"), + style="text", + ), + spacing="8dp", + ), + ).open() + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-api-break-2-2-0.png + :align: center + +.. code-block:: python + + from kivy.uix.widget import Widget + + from kivymd.uix.widget import MDWidget + from kivymd.app import MDApp + from kivymd.uix.button import MDButton, MDButtonText + from kivymd.uix.dialog import MDDialog, MDDialogHeadlineText, MDDialogButtonContainer + + + class Example(MDApp): + def build(self): + return MDWidget(md_bg_color=self.theme_cls.backgroundColor) + + def on_start(self): + MDDialog( + MDDialogHeadlineText( + text="Discard draft?", + halign="left", + ), + MDDialogSupportingText( + text="This will reset your device to its default factory settings.", + halign="left", + ), + MDDialogButtonContainer( + Widget(), + MDButton( + MDButtonText(text="Cancel"), + style="text", + ), + MDButton( + MDButtonText(text="Discard"), + style="text", + ), + spacing="8dp", + ), + ).open() + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/2-dialog-api-break-2-2-0.png + :align: center + +.. code-block:: python + + from kivymd import images_path + from kivymd.uix.widget import MDWidget + from kivymd.app import MDApp + from kivymd.uix.dialog import ( + MDDialog, + MDDialogHeadlineText, + MDDialogContentContainer, + ) + from kivymd.uix.list import ( + MDListItem, + MDListItemLeadingAvatar, + MDListItemSupportingText, + ) + + + class Example(MDApp): + def build(self): + return MDWidget(md_bg_color=self.theme_cls.backgroundColor) + + def on_start(self): + MDDialog( + MDDialogHeadlineText( + text="Set backup account", + halign="left", + ), + MDDialogContentContainer( + MDListItem( + MDListItemLeadingAvatar( + source=f"{images_path}/logo/kivymd-icon-128.png", + ), + MDListItemSupportingText( + text="user01@gmail.com", + ), + theme_bg_color="Custom", + md_bg_color=self.theme_cls.transparentColor, + ), + MDListItem( + MDListItemLeadingAvatar( + source="data/logo/kivy-icon-128.png", + ), + MDListItemSupportingText( + text="user01@gmail.com", + ), + theme_bg_color="Custom", + md_bg_color=self.theme_cls.transparentColor, + ), + orientation="vertical", + ), + ).open() + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/3-dialog-api-break-2-2-0.png + :align: center + +""" + +__all__ = [ + "MDDialog", + "MDDialogIcon", + "MDDialogHeadlineText", + "MDDialogSupportingText", + "MDDialogContentContainer", + "MDDialogButtonContainer", +] + +import os + +from kivy.core.window import Window +from kivy.lang import Builder +from kivy.metrics import dp +from kivy.properties import ( + VariableListProperty, + NumericProperty, + ColorProperty, + ObjectProperty, + BooleanProperty, +) +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.widget import Widget + +from kivymd.uix.card import MDCard +from kivymd.uix.label import MDIcon, MDLabel +from kivymd import uix_path +from kivymd.material_resources import DEVICE_TYPE +from kivymd.uix.behaviors import MotionDialogBehavior, DeclarativeBehavior + +with open( + os.path.join(uix_path, "dialog", "dialog.kv"), encoding="utf-8" +) as kv_file: + Builder.load_string(kv_file.read()) + + +class MDDialog(MDCard, MotionDialogBehavior): """ + Dialog class. - items = ListProperty() - """ - List of items objects for dialog. - Objects must be inherited from :class:`~kivymd.uix.list.BaseListItem` class. + For more information, see in the + :class:`~kivymd.uix.card.card.MDCard` and + :class:`~kivymd.uix.behaviors.motion_behavior.MotionDialogBehavior` + classes documentation. - With type 'simple' - ~~~~~~~~~~~~~~~~~~ - - .. code-block:: python - - from kivy.lang import Builder - from kivy.properties import StringProperty - - from kivymd.app import MDApp - from kivymd.uix.dialog import MDDialog - from kivymd.uix.list import OneLineAvatarListItem - - KV = ''' - - - ImageLeftWidget: - source: root.source - - - MDFloatLayout: - - MDFlatButton: - text: "ALERT DIALOG" - pos_hint: {'center_x': .5, 'center_y': .5} - on_release: app.show_simple_dialog() - ''' - - - class Item(OneLineAvatarListItem): - divider = None - source = StringProperty() - - - class Example(MDApp): - dialog = None - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return Builder.load_string(KV) - - def show_simple_dialog(self): - if not self.dialog: - self.dialog = MDDialog( - title="Set backup account", - type="simple", - items=[ - Item(text="user01@gmail.com", source="kivymd/images/logo/kivymd-icon-128.png"), - Item(text="user02@gmail.com", source="data/logo/kivy-icon-128.png"), - ], - ) - self.dialog.open() - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-items.png - :align: center - - With type 'confirmation' - ~~~~~~~~~~~~~~~~~~~~~~~~ - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - from kivymd.uix.button import MDFlatButton - from kivymd.uix.dialog import MDDialog - from kivymd.uix.list import OneLineAvatarIconListItem - - KV = ''' - - on_release: root.set_icon(check) - - CheckboxLeftWidget: - id: check - group: "check" - - - MDFloatLayout: - - MDFlatButton: - text: "ALERT DIALOG" - pos_hint: {'center_x': .5, 'center_y': .5} - on_release: app.show_confirmation_dialog() - ''' - - - class ItemConfirm(OneLineAvatarIconListItem): - divider = None - - def set_icon(self, instance_check): - instance_check.active = True - check_list = instance_check.get_widgets(instance_check.group) - for check in check_list: - if check != instance_check: - check.active = False - - - class Example(MDApp): - dialog = None - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return Builder.load_string(KV) - - def show_confirmation_dialog(self): - if not self.dialog: - self.dialog = MDDialog( - title="Phone ringtone", - type="confirmation", - items=[ - ItemConfirm(text="Callisto"), - ItemConfirm(text="Luna"), - ItemConfirm(text="Night"), - ItemConfirm(text="Solo"), - ItemConfirm(text="Phobos"), - ItemConfirm(text="Diamond"), - ItemConfirm(text="Sirena"), - ItemConfirm(text="Red music"), - ItemConfirm(text="Allergio"), - ItemConfirm(text="Magic"), - ItemConfirm(text="Tic-tac"), - ], - buttons=[ - MDFlatButton( - text="CANCEL", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - MDFlatButton( - text="OK", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - ], - ) - self.dialog.open() - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-confirmation.png - :align: center - - :attr:`items` is an :class:`~kivy.properties.ListProperty` - and defaults to `[]`. + :Events: + `on_pre_open`: + Fired before the MDDialog is opened. When this event is fired + MDDialog is not yet added to window. + `on_open`: + Fired when the MDDialog is opened. + `on_pre_dismiss`: + Fired before the MDDialog is closed. + `on_dismiss`: + Fired when the MDDialog is closed. If the callback returns True, + the dismiss will be canceled. """ width_offset = NumericProperty(dp(48)) @@ -421,270 +469,160 @@ class MDDialog(BaseDialog): and defaults to `dp(48)`. """ - type = OptionProperty( - "alert", options=["alert", "simple", "confirmation", "custom"] - ) + radius = VariableListProperty(dp(28), lenght=4) """ - Dialog type. - Available option are `'alert'`, `'simple'`, `'confirmation'`, `'custom'`. + Dialog corners rounding value. - :attr:`type` is an :class:`~kivy.properties.OptionProperty` - and defaults to `'alert'`. + :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` + and defaults to `[dp(28), dp(28), dp(28), dp(28)]`. """ - content_cls = ObjectProperty() + scrim_color = ColorProperty([0, 0, 0, 0.5]) """ - Custom content class. This attribute is only available when :attr:`type` is - set to `'custom'`. + Color for scrim in (r, g, b, a) or string format. - .. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: python - - from kivy.lang import Builder - from kivy.uix.boxlayout import BoxLayout - - from kivymd.app import MDApp - from kivymd.uix.button import MDFlatButton - from kivymd.uix.dialog import MDDialog - - KV = ''' - - orientation: "vertical" - spacing: "12dp" - size_hint_y: None - height: "120dp" - - MDTextField: - hint_text: "City" - - MDTextField: - hint_text: "Street" - - - MDFloatLayout: - - MDFlatButton: - text: "ALERT DIALOG" - pos_hint: {'center_x': .5, 'center_y': .5} - on_release: app.show_confirmation_dialog() - ''' - - - class Content(BoxLayout): - pass - - - class Example(MDApp): - dialog = None - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return Builder.load_string(KV) - - def show_confirmation_dialog(self): - if not self.dialog: - self.dialog = MDDialog( - title="Address:", - type="custom", - content_cls=Content(), - buttons=[ - MDFlatButton( - text="CANCEL", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - MDFlatButton( - text="OK", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - ], - ) - self.dialog.open() - - - Example().run() - - .. tab:: Declarative Python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.button import MDFlatButton - from kivymd.uix.dialog import MDDialog - from kivymd.uix.floatlayout import MDFloatLayout - from kivymd.uix.textfield import MDTextField - - - class Example(MDApp): - dialog = None - - def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" - return ( - MDFloatLayout( - MDFlatButton( - text="ALERT DIALOG", - pos_hint={'center_x': 0.5, 'center_y': 0.5}, - on_release=self.show_confirmation_dialog, - ) - ) - ) - - def show_confirmation_dialog(self, *args): - if not self.dialog: - self.dialog = MDDialog( - title="Address:", - type="custom", - content_cls=MDBoxLayout( - MDTextField( - hint_text="City", - ), - MDTextField( - hint_text="Street", - ), - orientation="vertical", - spacing="12dp", - size_hint_y=None, - height="120dp", - ), - buttons=[ - MDFlatButton( - text="CANCEL", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - MDFlatButton( - text="OK", - theme_text_color="Custom", - text_color=self.theme_cls.primary_color, - ), - ], - ) - self.dialog.open() - - - Example().run() - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-custom.png - :align: center - - :attr:`content_cls` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `'None'`. + :attr:`scrim_color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `[0, 0, 0, 0.5]`. """ - md_bg_color = ColorProperty(None) + auto_dismiss = BooleanProperty(True) """ - Background color in the (r, g, b, a) or string format. + This property determines if the dialog is automatically + dismissed when the user clicks outside it. - :attr:`md_bg_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. + ..versionadded:: 2.0.0 + + :attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty` and + defaults to True. """ - _scroll_height = NumericProperty("28dp") - _spacer_top = NumericProperty("24dp") + _scrim = ObjectProperty() # kivymd.uix.dialog.dialog.MDDialogScrim object + _is_open = False # is the dialog currently open or closed. - def __init__(self, **kwargs): - super().__init__(**kwargs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.register_event_type("on_open") + self.register_event_type("on_pre_open") + self.register_event_type("on_dismiss") + self.register_event_type("on_pre_dismiss") + self.opacity = 0 Window.bind(on_resize=self.update_width) - if self.size_hint == [1, 1] and ( - DEVICE_TYPE == "desktop" or DEVICE_TYPE == "tablet" - ): - self.size_hint = (None, None) - self.width = min(dp(560), Window.width - self.width_offset) - elif self.size_hint == [1, 1] and DEVICE_TYPE == "mobile": - self.size_hint = (None, None) - self.width = min(dp(280), Window.width - self.width_offset) - - if not self.title: - self._spacer_top = 0 - - if not self.buttons: - self.ids.root_button_box.height = 0 - else: - self.create_buttons() - - update_height = False - if self.type in ("simple", "confirmation"): - if self.type == "confirmation": - self.ids.spacer_top_box.add_widget(MDSeparator()) - self.ids.spacer_bottom_box.add_widget(MDSeparator()) - self.create_items() - if self.type == "custom": - if self.content_cls: - self.ids.container.remove_widget(self.ids.scroll) - self.ids.container.remove_widget(self.ids.text) - self.ids.spacer_top_box.add_widget(self.content_cls) - self.ids.spacer_top_box.padding = (0, "24dp", "16dp", 0) - update_height = True - if self.type == "alert": - self.ids.scroll.bar_width = 0 - - if update_height: - Clock.schedule_once(self.update_height) - def update_width(self, *args) -> None: - self.width = max( - self.height + self.width_offset, + self.size_hint_max_x = max( + self.width_offset, min( dp(560) if DEVICE_TYPE != "mobile" else dp(280), Window.width - self.width_offset, ), ) - def update_height(self, *args) -> None: - self._spacer_top = self.content_cls.height + dp(24) + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDDialogIcon): + self.ids.icon_container.add_widget(widget) + elif isinstance(widget, MDDialogHeadlineText): + self.ids.headline_container.add_widget(widget) + elif isinstance(widget, MDDialogSupportingText): + self.ids.supporting_text_container.add_widget(widget) + elif isinstance(widget, MDDialogContentContainer): + self.ids.content_container.add_widget(widget) + elif isinstance(widget, MDDialogButtonContainer): + self.ids.button_container.add_widget(widget) + else: + return super().add_widget(widget) - def update_items(self, items: list) -> None: - self.ids.box_items.clear_widgets() - self.items = items - self.create_items() + def open(self) -> None: + """Show the dialog.""" - def on_open(self) -> None: - # TODO: Add scrolling text. - self.height = self.ids.container.height + if self._is_open: + return + + self.dispatch("on_pre_open") + self._is_open = True + + if not self._scrim: + self._scrim = MDDialogScrim(color=self.scrim_color) + + Window.add_widget(self._scrim) + Window.add_widget(self) super().on_open() + self.dispatch("on_open") - def get_normal_height(self) -> float: - return ( - (Window.height * 80 / 100) - - self._spacer_top - - dp(52) - - self.ids.container.padding[1] - - self.ids.container.padding[-1] - - 100 - ) + def on_pre_open(self, *args) -> None: + """Fired when a dialog pre opened.""" - def edit_padding_for_item(self, instance_item) -> None: - instance_item.ids._left_container.x = 0 - instance_item._txt_left_pad = "56dp" + def on_open(self, *args) -> None: + """Fired when a dialog opened.""" - def create_items(self) -> None: - if not self.text: - self.ids.container.remove_widget(self.ids.text) - height = 0 - else: - height = self.ids.text.height + def on_dismiss(self, *args) -> None: + """Fired when a dialog dismiss.""" - for item in self.items: - if issubclass(item.__class__, BaseListItem): - height += item.height # calculate height contents - self.edit_padding_for_item(item) - self.ids.box_items.add_widget(item) + def on_pre_dismiss(self, *args) -> None: + """Fired when a dialog pre-dismiss.""" - if height > Window.height: - self.ids.scroll.height = self.get_normal_height() - else: - self.ids.scroll.height = height + def on_touch_down(self, touch): + if not self.collide_point(*touch.pos) and self.auto_dismiss: + self.dismiss() + return True + super().on_touch_down(touch) + return True - def create_buttons(self) -> None: - for button in self.buttons: - if issubclass(button.__class__, BaseButton): - self.ids.button_box.add_widget(button) + def dismiss(self, *args) -> None: + """Closes the dialog.""" + + self.dispatch("on_pre_dismiss") + super().on_dismiss() + self._is_open = False + self.dispatch("on_dismiss") + + +class MDDialogIcon(MDIcon): + """ + The class implements an icon. + + For more information, see in the + :class:`~kivymd.uix.label.label.MDIcon` class documentation. + """ + + +class MDDialogHeadlineText(MDLabel): + """ + The class implements the headline text. + + For more information, see in the + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + """ + + +class MDDialogSupportingText(MDLabel): + """ + The class implements the supporting text. + + For more information, see in the + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + """ + + +class MDDialogContentContainer(DeclarativeBehavior, BoxLayout): + """ + The class implements the container for custom widgets. + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation. + """ + + +class MDDialogButtonContainer(DeclarativeBehavior, BoxLayout): + """ + The class implements a container for placing dialog buttons. + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation. + """ + + +class MDDialogScrim(Widget): + color = ColorProperty(None) + alpha = NumericProperty(0) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__init__.py new file mode 100644 index 0000000..91a4075 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__init__.py @@ -0,0 +1 @@ +from .divider import MDDivider # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..ce7708e Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__pycache__/divider.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__pycache__/divider.cpython-311.pyc new file mode 100644 index 0000000..3fe3afe Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/__pycache__/divider.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/divider.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/divider.kv new file mode 100644 index 0000000..071ea90 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/divider.kv @@ -0,0 +1,10 @@ + + canvas: + Color: + rgba: + app.theme_cls.outlineVariantColor \ + if not self.color else \ + self.color + Rectangle: + size: self.size + pos: self.pos diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/divider.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/divider.py new file mode 100644 index 0000000..b9c14a3 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/divider/divider.py @@ -0,0 +1,159 @@ +""" +Components/Divider +================== + +.. versionadded:: 2.0.0 + +.. seealso:: + + `Material Design 3 spec, Divider `_ + +.. rubric:: Dividers are thin lines that group content in lists or other containers. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/divider.png + :align: center + +- Make dividers visible but not bold +- Only use dividers if items can’t be grouped with open space +- Use dividers to group things, not separate individual items + +`KivyMD` provides the following bar positions for use: + +- HorizontalDivider_ +- VerticalDivider_ + +.. HorizontalDivider: + +HorizontalDivider +----------------- + +Dividers are one way to visually group components and create hierarchy. +They can also be used to imply nested parent/child relationships. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/divider-horizontal-desc.png + :align: center + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + + KV = ''' + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDDivider: + size_hint_x: .5 + pos_hint: {'center_x': .5, 'center_y': .5} + ''' + + + class Example(MDApp): + def build(self): + self.theme_cls.theme_style = "Dark" + return Builder.load_string(KV) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/divider-horizontal.png + :align: center + +.. VerticalDivider: + +VerticalDivider +--------------- + +A vertical divider can be used to arrange content on a larger screen, such as +separating paragraph text from video or imagery media. + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/divider-vertical-desc.png + :align: center + +.. code-block:: kv + + MDDivider: + size_hint_y: .5 + orientation: "vertical" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/divider-vertical.png + :align: center + +API break +========= + +1.2.0 version +------------- + +.. code-block:: kv + + MDSeparator: + [...] + +2.0.0 version +------------- + +.. code-block:: kv + + MDDivider: + [...] +""" + +__all__ = ("MDDivider",) + +import os + +from kivy.clock import Clock +from kivy.lang import Builder +from kivy.metrics import dp +from kivy.properties import ColorProperty, NumericProperty +from kivy.uix.boxlayout import BoxLayout + +from kivymd import uix_path + +with open( + os.path.join(uix_path, "divider", "divider.kv"), encoding="utf-8" +) as kv_file: + Builder.load_string(kv_file.read()) + + +class MDDivider(BoxLayout): + """ + A divider line. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. + """ + + color = ColorProperty(None) + """ + Divider color in (r, g, b, a) or string format. + + :attr:`color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + divider_width = NumericProperty(dp(1)) + """ + Divider width. + + :attr:`divider_width` is an :class:`~kivy.properties.NumericProperty` + and defaults to `dp(1)`. + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + Clock.schedule_once(self.on_orientation) + + def on_orientation(self, *args) -> None: + """Fired when the values of :attr:`orientation` change.""" + + if self.orientation == "vertical": + self.size_hint_x = None + self.width = self.divider_width + elif self.orientation == "horizontal": + self.size_hint_y = None + self.height = self.divider_width diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__init__.py index a2ca639..d3574d7 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__init__.py @@ -1 +1 @@ -from .dropdownitem import MDDropDownItem # NOQA F401 +from .dropdownitem import MDDropDownItem, MDDropDownItemText # NOQA F401 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc index 4c3a9a7..a3ac579 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc index 34492c2..c6614e7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/__pycache__/dropdownitem.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.kv index 82960e3..431a7b3 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.kv @@ -1,38 +1,43 @@ -<_Triangle>: + + size_hint: None, None + size: + (self._size[0] + dp(12), self._size[1] + dp(8)) \ + if self._size else \ + (0, 0) + md_bg_color: "red" + canvas: Color: - rgba: app.theme_cls.text_color + group: "drop-down-item-color" + Rectangle: + group: "drop-down-item-text" + texture: + self._drop_down_text.texture \ + if self._drop_down_text else \ + None + size: + self._drop_down_text.texture_size \ + if self._drop_down_text else \ + (0, 0) + pos: + self.x, self.y + dp(8) + Color: + group: "drop-down-item-triangle-color" Triangle: points: [ \ - self.right-dp(14), self.y+dp(7), \ - self.right-dp(7), self.y+dp(7), \ - self.right-dp(7), self.y+dp(14) \ + self.right + dp(0), self.y + dp(12), \ + self.right - dp(6), self.y + dp(12), \ + self.right - dp(6), self.y + root.height - dp(3) \ ] - - - orientation: "vertical" - size_hint: None, None - size: self.minimum_size - spacing: "5dp" - padding: "5dp", "5dp", "5dp", 0 - - MDBoxLayout: - adaptive_size: True - spacing: "10dp" - - Label: - id: label_item - size_hint: None, None - size: self.texture_size - color: root.theme_cls.text_color - disabled_color: root.theme_cls.disabled_hint_text_color - font_size: root.font_size + MDDivider: + size_hint_x: None + width: root._size[0] + dp(14) if root._size else 0 - _Triangle: - size_hint: None, None - size: "20dp", "20dp" - - MDSeparator: + + size_hint_x: None + width: self.texture_size[0] + adaptive_width: True + role: "small" diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.py index 951357d..24bdb1b 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/dropdownitem/dropdownitem.py @@ -11,46 +11,83 @@ Usage .. code-block:: python from kivy.lang import Builder + from kivymd.uix.menu import MDDropdownMenu from kivymd.app import MDApp KV = ''' MDScreen + md_bg_color: self.theme_cls.backgroundColor MDDropDownItem: - id: drop_item - pos_hint: {'center_x': .5, 'center_y': .5} - text: 'Item' - on_release: print("Press item") + pos_hint: {"center_x": .5, "center_y": .5} + on_release: app.open_menu(self) + + MDDropDownItemText: + id: drop_text + text: "Item" ''' - class Test(MDApp): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.screen = Builder.load_string(KV) + class Example(MDApp): + def open_menu(self, item): + menu_items = [ + { + "text": f"{i}", + "on_release": lambda x=f"Item {i}": self.menu_callback(x), + } for i in range(5) + ] + MDDropdownMenu(caller=item, items=menu_items).open() + + def menu_callback(self, text_item): + self.root.ids.drop_text.text = text_item def build(self): - return self.screen + return Builder.load_string(KV) - Test().run() + Example().run() .. seealso:: `Work with the class MDDropdownMenu see here `_ + +API break +========= + +1.2.0 version +------------- + +.. code-block:: kv + + MDDropDownItem: + text: 'Item' + on_release: print(*args) + +2.0.0 version +------------- + +.. code-block:: kv + + MDDropDownItem: + on_release: print(*args) + + MDDropDownItemText: + text: "Item text" """ -__all__ = ("MDDropDownItem",) +__all__ = ("MDDropDownItem", "MDDropDownItemText") import os +from kivy.clock import Clock from kivy.lang import Builder -from kivy.properties import NumericProperty, StringProperty +from kivy.metrics import dp +from kivy.properties import ObjectProperty, ListProperty from kivy.uix.behaviors import ButtonBehavior from kivy.uix.boxlayout import BoxLayout -from kivy.uix.widget import Widget +from kivymd.uix.label import MDLabel from kivymd import uix_path from kivymd.theming import ThemableBehavior from kivymd.uix.behaviors import DeclarativeBehavior @@ -61,8 +98,19 @@ with open( Builder.load_string(kv_file.read()) -class _Triangle(Widget): - pass +# FIXME: When resizing the texture of the `MDDropDownItemText` widget, +# the canvas instruction that implements the triangle looks terrible. +# You need to edit the Triangle instructions according to the size +# of the `MDDropDownItemText` texture. +class MDDropDownItemText(MDLabel): + """ + Base texture for :class:`~MDDropDownItem` class (item text). + + For more information, see in the + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + + .. versionadded:: 2.0.0 + """ class MDDropDownItem( @@ -72,42 +120,52 @@ class MDDropDownItem( Dropdown item class. For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and :class:`~kivymd.theming.ThemableBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and :class:`~kivy.uix.boxlayout.BoxLayout` classes documentation. """ - text = StringProperty() - """ - Text item. + _drop_down_text = ObjectProperty() + _size = ListProperty() - :attr:`text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDDropDownItemText): + self._drop_down_text = widget + widget.bind(text=self.update_text_item) + Clock.schedule_once(lambda x: self.on_disabled(self, self.disabled)) + else: + return super().add_widget(widget) - current_item = StringProperty() - """ - Current name item. + def update_text_item(self, instance, value) -> None: + """Updates the text of the item.""" - :attr:`current_item` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ + self._drop_down_text.texture_update() + drop_down_item_text = self.canvas.get_group("drop-down-item-text")[0] + drop_down_item_text.texture = None + drop_down_item_text.texture = self._drop_down_text.texture + drop_down_item_text.size = self._drop_down_text.texture_size + drop_down_item_text.pos = (self.x, self.y + dp(8)) + self._size = self._drop_down_text.texture_size - font_size = NumericProperty("16sp") - """ - Item font size. + def on_disabled(self, instance, value) -> None: + """Fired when the values of :attr:`disabled` change.""" - :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` - and defaults to `'16sp'`. - """ + self._drop_down_text.disabled = value + drop_down_item_triangle_color = self.canvas.get_group( + "drop-down-item-triangle-color" + )[0] + drop_down_item_triangle_color.rgba = ( + self._drop_down_text.disabled_color + if value + else self._drop_down_text.color + ) - def on_text(self, instance_drop_down_item, text_item: str) -> None: - self.ids.label_item.text = text_item + def on__drop_down_text(self, instance, value) -> None: + """Fired when the values of :attr:`_drop_down_text` change.""" - def set_item(self, name_item: str) -> None: - """Sets new text for an item.""" + def set_size(*args): + self._size = value.texture_size - self.ids.label_item.text = name_item - self.current_item = name_item + Clock.schedule_once(set_size) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__init__.py index 2f5badd..dbe183c 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__init__.py @@ -1,8 +1,6 @@ # NOQA F401 from .expansionpanel import ( MDExpansionPanel, - MDExpansionPanelLabel, - MDExpansionPanelOneLine, - MDExpansionPanelThreeLine, - MDExpansionPanelTwoLine, + MDExpansionPanelContent, + MDExpansionPanelHeader, ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc index 31ab28e..b5a4670 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc index 0660361..0b0f3dd 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/__pycache__/expansionpanel.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.kv index 4aadaef..0ecc4e2 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.kv @@ -1,18 +1,15 @@ -: - icon: "chevron-right" - disabled: True - md_bg_color_disabled: 0, 0, 0, 0 - - canvas.before: - PushMatrix - Rotate: - angle: self._angle - axis: (0, 0, 1) - origin: self.center - canvas.after: - PopMatrix - - + orientation: "vertical" size_hint_y: None - # height: dp(68) + height: self.minimum_height + + + + size_hint_y: None + height: self.minimum_height + + + + size_hint_y: None + height: self.minimum_height + opacity: 0 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.py index d0fe33d..670e701 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/expansionpanel/expansionpanel.py @@ -2,10 +2,6 @@ Components/ExpansionPanel ========================= -.. seealso:: - - `Material Design spec, Expansion panel `_ - .. rubric:: Expansion panels contain creation flows and allow lightweight editing of an element. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel.png @@ -16,160 +12,311 @@ Usage .. code-block:: python - self.add_widget( - MDExpansionPanel( - icon="logo.png", # panel icon - content=Content(), # panel content - panel_cls=MDExpansionPanelOneLine(text="Secondary text"), # panel class - ) - ) + MDExpansionPanel: -To use :class:`~MDExpansionPanel` you must pass one of the following classes -to the :attr:`~MDExpansionPanel.panel_cls` parameter: + MDExpansionPanelHeader: -- :class:`~MDExpansionPanelOneLine` -- :class:`~MDExpansionPanelTwoLine` -- :class:`~MDExpansionPanelThreeLine` + # Content of header. + [...] -These classes are inherited from the following classes: + MDExpansionPanelContent: -- :class:`~kivymd.uix.list.OneLineAvatarIconListItem` -- :class:`~kivymd.uix.list.TwoLineAvatarIconListItem` -- :class:`~kivymd.uix.list.ThreeLineAvatarIconListItem` + # Content of panel. + [...] -.. code-block:: python +Anatomy +------- - self.root.ids.box.add_widget( - MDExpansionPanel( - icon="logo.png", - content=Content(), - panel_cls=MDExpansionPanelThreeLine( - text="Text", - secondary_text="Secondary text", - tertiary_text="Tertiary text", - ) - ) - ) +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel-anatomy.png + :align: center Example ------- .. code-block:: python - import os - from kivy.lang import Builder + from kivy.uix.behaviors import ButtonBehavior from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelThreeLine - from kivymd import images_path + from kivymd.uix.behaviors import RotateBehavior + from kivymd.uix.expansionpanel import MDExpansionPanel + from kivymd.uix.list import MDListItemTrailingIcon KV = ''' - - adaptive_height: True + MDScreen: + md_bg_color: self.theme_cls.backgroundColor - TwoLineIconListItem: - text: "(050)-123-45-67" - secondary_text: "Mobile" + MDExpansionPanel: + id: panel + pos_hint: {"center_x": .5, "center_y": .5} - IconLeftWidget: - icon: 'phone' + MDExpansionPanelHeader: + MDListItem: + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.surfaceContainerLowColor + ripple_effect: False - MDScrollView: + MDListItemSupportingText: + text: "Supporting text" - MDGridLayout: - id: box - cols: 1 - adaptive_height: True + TrailingPressedIconButton: + id: chevron + icon: "chevron-right" + on_release: app.tap_expansion_chevron(panel, chevron) + + MDExpansionPanelContent: + orientation: "vertical" + padding: "12dp", 0, "12dp", 0 + + MDLabel: + text: "Channel information" + adaptive_height: True + padding_x: "16dp" + padding_y: "12dp" + + MDListItem: + + MDListItemLeadingIcon: + icon: "email" + + MDListItemHeadlineText: + text: "Email" + + MDListItemSupportingText: + text: "kivydevelopment@gmail.com" + + MDListItem: + + MDListItemLeadingIcon: + icon: "instagram" + + MDListItemHeadlineText: + text: "Instagram" + + MDListItemSupportingText: + text: "Account" + + MDListItemTertiaryText: + text: "www.instagram.com/KivyMD" ''' - class Content(MDBoxLayout): - '''Custom content.''' + class TrailingPressedIconButton( + ButtonBehavior, RotateBehavior, MDListItemTrailingIcon + ): + ... - class Test(MDApp): + class Example(MDApp): def build(self): + self.theme_cls.theme_style = "Dark" return Builder.load_string(KV) - def on_start(self): - for i in range(10): - self.root.ids.box.add_widget( - MDExpansionPanel( - icon=os.path.join(images_path, "logo", "kivymd-icon-128.png"), - content=Content(), - panel_cls=MDExpansionPanelThreeLine( - text="Text", - secondary_text="Secondary text", - tertiary_text="Tertiary text", - ) - ) - ) + def tap_expansion_chevron( + self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton + ): + panel.open() if not panel.is_open else panel.close() + panel.set_chevron_down( + chevron + ) if not panel.is_open else panel.set_chevron_up(chevron) - Test().run() + Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel-example.gif :align: center -Two events are available for :class:`~MDExpansionPanel` -------------------------------------------------------- - -- :attr:`~MDExpansionPanel.on_open` -- :attr:`~MDExpansionPanel.on_close` - -.. code-block:: kv - - MDExpansionPanel: - on_open: app.on_panel_open(args) - on_close: app.on_panel_close(args) - -The user function takes one argument - the object of the panel: +Use with ScrollView +------------------- .. code-block:: python - def on_panel_open(self, instance_panel): - print(instance_panel) + import asynckivy + from kivy.animation import Animation + from kivy.lang import Builder + from kivy.metrics import dp + from kivy.uix.behaviors import ButtonBehavior -.. seealso:: `See Expansion panel example `_ + from kivymd.app import MDApp + from kivymd.uix.behaviors import RotateBehavior + from kivymd.uix.expansionpanel import MDExpansionPanel + from kivymd.uix.list import MDListItemTrailingIcon - `Expansion panel and MDCard `_ + KV = ''' + + + MDExpansionPanelHeader: + + MDListItem: + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.surfaceContainerLowColor + ripple_effect: False + + MDListItemSupportingText: + text: "Supporting text" + + TrailingPressedIconButton: + id: chevron + icon: "chevron-right" + on_release: app.tap_expansion_chevron(root, chevron) + + MDExpansionPanelContent: + orientation: "vertical" + padding: "12dp", 0, "12dp", "12dp" + md_bg_color: self.theme_cls.surfaceContainerLowestColor + + MDLabel: + text: "Channel information" + adaptive_height: True + padding_x: "16dp" + padding_y: "12dp" + + MDListItem: + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.surfaceContainerLowestColor + + MDListItemLeadingIcon: + icon: "email" + + MDListItemHeadlineText: + text: "Email" + + MDListItemSupportingText: + text: "kivydevelopment@gmail.com" + + MDListItem: + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.surfaceContainerLowestColor + + MDListItemLeadingIcon: + icon: "instagram" + + MDListItemHeadlineText: + text: "Instagram" + + MDListItemSupportingText: + text: "Account" + + MDListItemTertiaryText: + text: "www.instagram.com/KivyMD" + + + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + ScrollView: + size_hint_x: .5 + pos_hint: {"center_x": .5, "center_y": .5} + + MDList: + id: container + ''' + + + class ExpansionPanelItem(MDExpansionPanel): + ... + + + class TrailingPressedIconButton( + ButtonBehavior, RotateBehavior, MDListItemTrailingIcon + ): + ... + + + class Example(MDApp): + def on_start(self): + async def set_panel_list(): + for i in range(12): + await asynckivy.sleep(0) + self.root.ids.container.add_widget(ExpansionPanelItem()) + + asynckivy.start(set_panel_list()) + + def build(self): + self.theme_cls.theme_style = "Dark" + return Builder.load_string(KV) + + def tap_expansion_chevron( + self, panel: MDExpansionPanel, chevron: TrailingPressedIconButton + ): + Animation( + padding=[0, dp(12), 0, dp(12)] + if not panel.is_open + else [0, 0, 0, 0], + d=0.2, + ).start(panel) + panel.open() if not panel.is_open else panel.close() + panel.set_chevron_down( + chevron + ) if not panel.is_open else panel.set_chevron_up(chevron) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/expansion-panel-example-with-scroll-view.gif + :align: center + +API break +========= + +1.2.0 version +------------- + +.. code-block:: python + + MDExpansionPanel( + icon="icon.png", + content=Content(), # content of panel + panel_cls=MDExpansionPanelThreeLine( # content of header + text="Text", + secondary_text="Secondary text", + tertiary_text="Tertiary text", + ) + ) + +2.0.0 version +------------- + +.. code-block:: python + + MDExpansionPanel: + + MDExpansionPanelHeader: + + # Content of header. + [...] + + MDExpansionPanelContent: + + # Content of panel. + [...] """ __all__ = ( "MDExpansionPanel", - "MDExpansionPanelOneLine", - "MDExpansionPanelTwoLine", - "MDExpansionPanelThreeLine", - "MDExpansionPanelLabel", + "MDExpansionPanelContent", + "MDExpansionPanelHeader", ) import os -from typing import Union from kivy.animation import Animation from kivy.clock import Clock from kivy.lang import Builder from kivy.metrics import dp -from kivy.properties import NumericProperty, ObjectProperty, StringProperty -from kivy.uix.relativelayout import RelativeLayout -from kivy.uix.widget import WidgetException - -import kivymd.material_resources as m_res -from kivymd import uix_path -from kivymd.icon_definitions import md_icons -from kivymd.uix.button import MDIconButton -from kivymd.uix.list import ( - IconLeftWidget, - ImageLeftWidget, - IRightBodyTouch, - OneLineAvatarIconListItem, - ThreeLineAvatarIconListItem, - TwoLineAvatarIconListItem, - TwoLineListItem, +from kivy.properties import ( + NumericProperty, + ObjectProperty, + StringProperty, + BooleanProperty, ) +from kivy.uix.boxlayout import BoxLayout + +from kivymd import uix_path +from kivymd.theming import ThemableBehavior +from kivymd.uix.behaviors import BackgroundColorBehavior, DeclarativeBehavior with open( os.path.join(uix_path, "expansionpanel", "expansionpanel.kv"), @@ -178,92 +325,53 @@ with open( Builder.load_string(kv_file.read()) -class MDExpansionChevronRight(IRightBodyTouch, MDIconButton): - """Chevron icon on the right panel.""" - - _angle = NumericProperty(0) - - -class MDExpansionPanelOneLine(OneLineAvatarIconListItem): +class MDExpansionPanelContent( + DeclarativeBehavior, ThemableBehavior, BackgroundColorBehavior, BoxLayout +): """ - Single line panel. + Implements a container for panel content. + + .. versionadded:: 2.0.0 For more information, see in the - :class:`~kivymd.uix.list.OneLineAvatarIconListItem` class documentation. + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. """ -class MDExpansionPanelTwoLine(TwoLineAvatarIconListItem): +class MDExpansionPanelHeader(DeclarativeBehavior, BoxLayout): """ - Two-line panel. + Implements a container for the content of the panel header. + + .. versionadded:: 2.0.0 For more information, see in the - :class:`~kivymd.uix.list.TwoLineAvatarIconListItem` class documentation. + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. """ -class MDExpansionPanelThreeLine(ThreeLineAvatarIconListItem): - """ - Three-line panel. - - For more information, see in the - :class:`~kivymd.uix.list.ThreeLineAvatarIconListItem` class documentation. - """ - - -class MDExpansionPanelLabel(TwoLineListItem): - """ - Label panel. - - For more information, see in the - :class:`~kivymd.uix.list.TwoLineListItem` class documentation. - - ..warning:: This class is created for use in the - :class:`~kivymd.uix.stepper.MDStepperVertical` and - :class:`~kivymd.uix.stepper.MDStepper` classes, and has not - been tested for use outside of these classes. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Clock.schedule_once(self.set_paddings) - - def set_paddings(self, interval: Union[int, float]) -> None: - self._txt_bot_pad = dp(36) - self._txt_left_pad = dp(0) - - -class MDExpansionPanel(RelativeLayout): +# TODO: Add a successor from kivymd.uix.behaviors.motion_behavior.MotionBase +# to the MDExpansionPanel class to control the properties of the panel +# opening/closing animation. +class MDExpansionPanel(DeclarativeBehavior, BoxLayout): """ Expansion panel class. For more information, see in the - :class:`~kivy.uix.relativelayout.RelativeLayout` classes documentation. + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. :Events: :attr:`on_open` - Called when a panel is opened. + Fired when a panel is opened. :attr:`on_close` - Called when a panel is closed. - """ - - content = ObjectProperty() - """ - Content of panel. Must be `Kivy` widget. - - :attr:`content` is an :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. - """ - - icon = StringProperty() - """ - Icon of panel. - - Icon Should be either be a path to an image or - a logo name in :class:`~kivymd.icon_definitions.md_icons` - - :attr:`icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. + Fired when a panel is closed. """ opening_transition = StringProperty("out_cubic") @@ -300,187 +408,122 @@ class MDExpansionPanel(RelativeLayout): and defaults to `0.2`. """ - panel_cls = ObjectProperty() + is_open = BooleanProperty(False) """ - Panel object. The object must be one of the classes - :class:`~MDExpansionPanelOneLine`, :class:`~MDExpansionPanelTwoLine` or - :class:`~MDExpansionPanelThreeLine`. + The panel is open or closed. - :attr:`panel_cls` is a :class:`~kivy.properties.ObjectProperty` - and defaults to `None`. + .. versionadded:: 2.0.0 + + :attr:`is_open` is a :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. """ - _state = StringProperty("close") - _anim_playing = False + _header = ObjectProperty() # MDExpansionPanelHeader object + _content = ObjectProperty() # MDExpansionPanelContent object + # Height of the MDExpansionPanelContent widget. + _original_content_height = NumericProperty() + _allow_add_content = False + _panel_is_process_opening = False def __init__(self, **kwargs): super().__init__(**kwargs) self.register_event_type("on_open") self.register_event_type("on_close") - if self.panel_cls and isinstance( - self.panel_cls, - ( - MDExpansionPanelOneLine, - MDExpansionPanelTwoLine, - MDExpansionPanelThreeLine, - MDExpansionPanelLabel, - ), - ): - self.panel_cls.pos_hint = {"top": 1} - self.panel_cls._no_ripple_effect = True - self.panel_cls.bind( - on_release=lambda x: self.check_open_panel(self.panel_cls) - ) - if not isinstance(self.panel_cls, MDExpansionPanelLabel): - self.chevron = MDExpansionChevronRight() - self.panel_cls.add_widget(self.chevron) - if self.icon: - if self.icon in md_icons.keys(): - self.panel_cls.add_widget( - IconLeftWidget( - icon=self.icon, - pos_hint={"center_y": 0.5}, - ) - ) - else: - self.panel_cls.add_widget( - ImageLeftWidget( - source=self.icon, pos_hint={"center_y": 0.5} - ) - ) - else: - self.panel_cls.remove_widget( - self.panel_cls.ids._left_container - ) - self.panel_cls._txt_left_pad = 0 - else: - # if no icon - self.panel_cls._txt_left_pad = m_res.HORIZ_MARGINS - self.add_widget(self.panel_cls) - else: - raise ValueError( - "KivyMD: `panel_cls` object must be must be one of the " - "objects from the list\n" - "[MDExpansionPanelOneLine, MDExpansionPanelTwoLine, " - "MDExpansionPanelThreeLine]" - ) + def on_open(self, *args) -> None: + """Fired when a panel is opened.""" - def on_open(self, *args): - """Called when a panel is opened.""" + def on_close(self, *args) -> None: + """Fired when a panel is closed.""" - def on_close(self, *args): - """Called when a panel is closed.""" - - def check_open_panel( - self, - instance_panel: [ - MDExpansionPanelThreeLine, - MDExpansionPanelTwoLine, - MDExpansionPanelThreeLine, - MDExpansionPanelLabel, - ], - ) -> None: - """ - Called when you click on the panel. Called methods to open or close - a panel. - """ - - press_current_panel = False - for panel in self.parent.children: - if isinstance(panel, MDExpansionPanel): - if len(panel.children) == 2: - if instance_panel is panel.children[1]: - press_current_panel = True - panel.remove_widget(panel.children[0]) - if not isinstance(self.panel_cls, MDExpansionPanelLabel): - chevron = panel.children[0].children[0].children[0] - self.set_chevron_up(chevron) - self.close_panel(panel, press_current_panel) - self.dispatch("on_close") - break - if not press_current_panel: - self.set_chevron_down() - - def set_chevron_down(self) -> None: + def set_chevron_down(self, instance) -> None: """Sets the chevron down.""" - if not isinstance(self.panel_cls, MDExpansionPanelLabel): - Animation(_angle=-90, d=self.opening_time).start(self.chevron) - self.open_panel() - self.dispatch("on_open") + Animation(rotate_value_angle=-90, d=self.opening_time).start(instance) - def set_chevron_up(self, instance_chevron: MDExpansionChevronRight) -> None: + def set_chevron_up(self, instance) -> None: """Sets the chevron up.""" - if not isinstance(self.panel_cls, MDExpansionPanelLabel): - Animation(_angle=0, d=self.closing_time).start(instance_chevron) + Animation(rotate_value_angle=0, d=self.closing_time).start(instance) - def close_panel( - self, instance_expansion_panel, press_current_panel: bool - ) -> None: - """Method closes the panel.""" + def close(self, *args) -> None: + """ + Method closes the panel. - if self._anim_playing: - return + .. versionchanged:: 2.0.0 - if press_current_panel: - self._anim_playing = True + Rename from `close_panel` to `close` method. + """ - self._state = "close" + def set_content_height(*args): + anim_height = Animation( + height=0, + t=self.opening_transition, + d=self.opening_time, + ) + anim_height.bind( + on_complete=lambda *args: self.remove_widget(self._content) + ) + anim_height.start(self._content) + self.is_open = False + self.dispatch("on_close") - anim = Animation( - height=self.panel_cls.height, - d=self.closing_time, - t=self.closing_transition, - ) - anim.bind(on_complete=self._disable_anim) - anim.start(instance_expansion_panel) - - def open_panel(self, *args) -> None: - """Method opens a panel.""" - - if self._anim_playing: - return - - self._anim_playing = True - self._state = "open" - - anim = Animation( - height=self.content.height + self.height, - d=self.opening_time, + anim_opacity = Animation( + opacity=0, t=self.opening_transition, + d=self.opening_time, ) - anim.bind(on_complete=self._add_content) - anim.bind(on_complete=self._disable_anim) - anim.start(self) + anim_opacity.bind(on_complete=set_content_height) + anim_opacity.start(self._content) - def get_state(self) -> str: - """Returns the state of panel. Can be `close` or `open` .""" + def open(self, *args) -> None: + """ + Method opens a panel. - return self._state + .. versionchanged:: 2.0.0 + + Rename from `open_panel` to `open` method. + """ + + def set_content_opacity(*args): + Animation( + opacity=1, + t=self.opening_transition, + d=self.opening_time, + ).start(self._content) + self.is_open = True + self._panel_is_process_opening = False + self.dispatch("on_open") + + if not self._panel_is_process_opening: + self._allow_add_content = True + self._panel_is_process_opening = True + self.add_widget(self._content) + + anim_height = Animation( + height=self._original_content_height, + t=self.opening_transition, + d=self.opening_time, + ) + anim_height.bind(on_complete=set_content_opacity) + anim_height.start(self._content) def add_widget(self, widget, index=0, canvas=None): - if isinstance( - widget, - ( - MDExpansionPanelOneLine, - MDExpansionPanelTwoLine, - MDExpansionPanelThreeLine, - MDExpansionPanelLabel, - ), + if isinstance(widget, MDExpansionPanelHeader): + self._header = widget + return super().add_widget(widget) + elif ( + isinstance(widget, MDExpansionPanelContent) + and not self._allow_add_content ): - self.height = widget.height - return super().add_widget(widget) + self._content = widget + Clock.schedule_once(self._set_content_height, 0.8) + elif ( + isinstance(widget, MDExpansionPanelContent) + and self._allow_add_content + ): + return super().add_widget(widget) - def _disable_anim(self, *args): - self._anim_playing = False - - def _add_content(self, *args): - if self.content: - try: - if isinstance(self.panel_cls, MDExpansionPanelLabel): - self.content.y = dp(36) - self.add_widget(self.content) - except WidgetException: - pass + def _set_content_height(self, *args): + self._original_content_height = self._content.height - dp(88) + self._content.height = 0 diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc index 35601b5..012024b 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc index bf28292..5d8fc3e 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/__pycache__/filemanager.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.kv index 29352d7..ceb6e19 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.kv @@ -1,8 +1,7 @@ #:import os os -#:import FILE_MANAGER_TOP_APP_BAR_ELEVATION kivymd.material_resources.FILE_MANAGER_TOP_APP_BAR_ELEVATION - + icon: "folder" path: "" background_normal: "" @@ -10,34 +9,18 @@ dir_or_file_name: "" icon_color: 0, 0, 0, 0 _selected: False - events_callback: lambda x: None - orientation: "vertical" + on_release: root.events_callback(root.path, root) - ModifiedOneLineIconListItem: + MDListItemLeadingIcon: + icon: root.icon + theme_icon_color: "Custom" + icon_color: root.icon_color + + MDListItemSupportingText: text: root.dir_or_file_name - on_release: root.events_callback(root.path, root) - bg_color: - self.theme_cls.bg_darkest \ - if root._selected else \ - self.theme_cls.bg_normal - - IconLeftWidget: - icon: root.icon - theme_icon_color: "Custom" - icon_color: root.icon_color - - MDSeparator: - - adaptive_height: True - shorten: True - shorten_from: "center" - halign: "center" - text_size: self.width, None - - - + name: "" path: "" realpath: "" @@ -46,48 +29,68 @@ _selected: False orientation: "vertical" size_hint_y: None - hright: root.height - padding: dp(20) + height: root.height + padding: "20dp" + spacing: "12dp" - IconButton: + MDFileManagerThumbnail: mipmap: True source: root.path - bg_color: - app.theme_cls.bg_darkest \ - if root._selected else app.theme_cls.bg_normal on_release: root.events_callback( \ os.path.join(root.path if root.type != "folder" \ else root.realpath, root.name), root) - LabelContent: + MDLabel: text: root.name + adaptive_height: True + shorten: True + shorten_from: "center" + halign: "center" + text_size: self.width, None - md_bg_color: root.theme_cls.bg_normal + canvas: + Color: + rgba: self.theme_cls.backgroundColor + Rectangle: + pos: self.pos + size: self.size - MDBoxLayout: + BoxLayout: orientation: "vertical" spacing: dp(5) MDTopAppBar: id: toolbar - title: root.current_path - right_action_items: [["close-box", lambda x: root.exit_manager(1)]] - left_action_items: [["chevron-left", lambda x: root.back()]] - elevation: FILE_MANAGER_TOP_APP_BAR_ELEVATION md_bg_color: - app.theme_cls.primary_color \ + app.theme_cls.surfaceColor \ if not root.background_color_toolbar else \ root.background_color_toolbar + MDTopAppBarLeadingButtonContainer: + padding: "12dp", 0, 0, 0 + + MDActionTopAppBarButton: + icon: "chevron-left" + on_release: root.back() + + MDTopAppBarTitle: + text: root.current_path + + MDTopAppBarTrailingButtonContainer: + + MDActionTopAppBarButton: + icon: "close-box" + on_release: root.exit_manager(1) + RecycleView: id: rv key_viewclass: "viewclass" key_size: "height" bar_width: dp(4) - bar_color: root.theme_cls.primary_color + bar_color: root.theme_cls.primaryColor RecycleGridLayout: padding: "10dp" @@ -97,13 +100,3 @@ default_size_hint: 1, None size_hint_y: None height: self.minimum_height - - - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height / 2 - self.height / 2 - size: dp(48), dp(48) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.py index 4073764..86f793e 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/filemanager/filemanager.py @@ -47,28 +47,22 @@ Example from kivy.core.window import Window from kivy.lang import Builder + from kivy.metrics import dp from kivymd.app import MDApp from kivymd.uix.filemanager import MDFileManager - from kivymd.toast import toast - + from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText KV = ''' - MDBoxLayout: - orientation: "vertical" + MDScreen: + md_bg_color: self.theme_cls.backgroundColor - MDTopAppBar: - title: "MDFileManager" - left_action_items: [["menu", lambda x: None]] - elevation: 3 + MDButton: + pos_hint: {"center_x": .5, "center_y": .5} + on_release: app.file_manager_open() - MDFloatLayout: - - MDRoundFlatIconButton: + MDButtonText: text: "Open manager" - icon: "folder" - pos_hint: {"center_x": .5, "center_y": .5} - on_release: app.file_manager_open() ''' @@ -83,11 +77,11 @@ Example def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" return Builder.load_string(KV) def file_manager_open(self): - self.file_manager.show(os.path.expanduser("~")) # output manager to the screen + self.file_manager.show( + os.path.expanduser("~")) # output manager to the screen self.manager_open = True def select_path(self, path: str): @@ -99,7 +93,14 @@ Example ''' self.exit_manager() - toast(path) + MDSnackbar( + MDSnackbarText( + text=path, + ), + y=dp(24), + pos_hint={"center_x": 0.5}, + size_hint_x=0.8, + ).open() def exit_manager(self, *args): '''Called when the user reaches the root of the directory tree.''' @@ -133,6 +134,8 @@ Not tested on `iOS`. :align: center """ +from __future__ import annotations + __all__ = ("MDFileManager",) import locale @@ -142,28 +145,27 @@ from typing import List, Tuple, Union from kivy import platform from kivy.clock import Clock -from kivy.factory import Factory from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import ( BooleanProperty, ColorProperty, ListProperty, - NumericProperty, ObjectProperty, OptionProperty, StringProperty, ) from kivy.uix.behaviors import ButtonBehavior +from kivy.uix.boxlayout import BoxLayout from kivy.uix.modalview import ModalView +from kivy.uix.relativelayout import RelativeLayout from kivymd import images_path, uix_path +from kivymd.theming import ThemableBehavior from kivymd.uix.behaviors import CircularRippleBehavior -from kivymd.uix.boxlayout import MDBoxLayout -from kivymd.uix.button import MDFloatingActionButton +from kivymd.uix.button import MDFabButton from kivymd.uix.fitimage import FitImage -from kivymd.uix.list import BaseListItem -from kivymd.uix.relativelayout import MDRelativeLayout +from kivymd.uix.list import MDListItem with open( os.path.join(uix_path, "filemanager", "filemanager.kv"), encoding="utf-8" @@ -171,37 +173,57 @@ with open( Builder.load_string(kv_file.read()) -class BodyManager(MDBoxLayout): - """Base class for folders and files icons.""" - - -class BodyManagerWithPreview(MDBoxLayout): +class MDFileManagerItem(MDListItem): """ - Base class for folder icons and thumbnails images in ``preview`` mode. + Base class for folders and files icons. + + .. versionchanged:: 2.0.0 + + The `BodyManager` class has been renamed to `MDFileManagerItem`. + + For more information, see in the + :class:`~kivymd.uix.list.list.MDListItem` class documentation. """ -class IconButton(CircularRippleBehavior, ButtonBehavior, FitImage): - """Folder icons/thumbnails images in ``preview`` mode.""" +class MDFileManagerItemPreview(BoxLayout): + """ + Base class for folder icons and thumbnails images in `preview` mode. + + .. versionchanged:: 2.0.0 + + The `BodyManagerWithPreview` class has been renamed + to `MDFileManagerItemPreview`. + + For more information, see in the + :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. + """ -class ModifiedOneLineIconListItem(BaseListItem): - _txt_left_pad = NumericProperty("72dp") - _txt_top_pad = NumericProperty("16dp") - _txt_bot_pad = NumericProperty("15dp") - _num_lines = 1 +class MDFileManagerThumbnail(CircularRippleBehavior, ButtonBehavior, FitImage): + """ + Folder icons/thumbnails images in `preview` mode. - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.height = dp(48) + .. versionchanged:: 2.0.0 + + The `IconButton` class has been renamed to `MDFileManagerThumbnail`. + + For more information, see in the + :class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and + :class:`~kivymd.uix.fitimage.fitimage.FitImage` + classes documentation. + """ -class MDFileManager(MDRelativeLayout): +class MDFileManager(ThemableBehavior, RelativeLayout): """ Implements a modal dialog with a file manager. For more information, see in the - :class:`~kivymd.uix.relativelayout.MDRelativeLayout` class documentation. + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivy.uix.relativelayout.RelativeLayout` + classes documentation. :Events: `on_pre_open`: @@ -400,8 +422,8 @@ class MDFileManager(MDRelativeLayout): ) """ It can take the values 'nothing' 'name' 'date' 'size' 'type' - sorts files - by option. By default, sort by name. Available options are: - `'nothing'`, `'name'`, `'date'`, `'size'`, `'type'`. + by option. By default, sort by name. + Available options are: `'nothing'`, `'name'`, `'date'`, `'size'`, `'type'`. :attr:`sort_by` is an :class:`~kivy.properties.OptionProperty` and defaults to `name`. @@ -452,9 +474,6 @@ class MDFileManager(MDRelativeLayout): self.register_event_type("on_open") self.register_event_type("on_pre_dismiss") self.register_event_type("on_dismiss") - - toolbar_label = self.ids.toolbar.children[1].children[0] - toolbar_label.font_style = "Subtitle1" Clock.schedule_once(self._create_selection_button) if self.preview: @@ -499,7 +518,7 @@ class MDFileManager(MDRelativeLayout): manager_list.append( { - "viewclass": "BodyManager", + "viewclass": "MDFileManagerItem", "path": disk, "icon": icon, "dir_or_file_name": disk, @@ -532,7 +551,7 @@ class MDFileManager(MDRelativeLayout): for name_dir in self.__sort_files(dirs): manager_list.append( { - "viewclass": "BodyManagerWithPreview", + "viewclass": "MDFileManagerItemPreview", "path": self.icon_folder, "realpath": os.path.join(path), "type": "folder", @@ -549,7 +568,7 @@ class MDFileManager(MDRelativeLayout): ): manager_list.append( { - "viewclass": "BodyManagerWithPreview", + "viewclass": "MDFileManagerItemPreview", "path": os.path.join(path, name_file), "name": name_file, "type": "files", @@ -569,12 +588,12 @@ class MDFileManager(MDRelativeLayout): manager_list.append( { - "viewclass": "BodyManager", + "viewclass": "MDFileManagerItem", "path": _path, "icon": icon, "dir_or_file_name": name, "events_callback": self.select_dir_or_file, - "icon_color": self.theme_cls.primary_color + "icon_color": self.theme_cls.primaryColor if not self.icon_color else self.icon_color, "_selected": False, @@ -586,17 +605,18 @@ class MDFileManager(MDRelativeLayout): manager_list.append( { - "viewclass": "BodyManager", + "viewclass": "MDFileManagerItem", "path": name, "icon": "file-outline", "dir_or_file_name": os.path.split(name)[1], "events_callback": self.select_dir_or_file, - "icon_color": self.theme_cls.primary_color + "icon_color": self.theme_cls.primaryColor if not self.icon_color else self.icon_color, "_selected": False, } ) + self.ids.rv.data = manager_list self._show() @@ -663,8 +683,8 @@ class MDFileManager(MDRelativeLayout): def select_dir_or_file( self, path: str, - widget: Union[BodyManagerWithPreview, Factory.BodyManager], - ): + widget: MDFileManagerItemPreview | MDFileManagerItem, + ) -> None: """Called by tap on the name of the directory or file.""" if os.path.isfile(os.path.join(self.current_path, path)): @@ -715,39 +735,39 @@ class MDFileManager(MDRelativeLayout): self.icon_selection_button = icon_name def on_background_color_toolbar( - self, instance_file_manager, color: Union[str, list] + self, instance_file_manager, color: str | list ) -> None: """ Called when the :attr:`background_color_toolbar` property is changed. """ - def on_background_color_toolbar(*args): + def on_background_color_toolbar(*args) -> None: self.ids.toolbar.md_bg_color = color Clock.schedule_once(on_background_color_toolbar) - def on_pre_open(self, *args): + def on_pre_open(self, *args) -> None: """ Default pre-open event handler. .. versionadded:: 1.1.0 """ - def on_open(self, *args): + def on_open(self, *args) -> None: """ Default open event handler. .. versionadded:: 1.1.0 """ - def on_pre_dismiss(self, *args): + def on_pre_dismiss(self, *args) -> None: """ Default pre-dismiss event handler. .. versionadded:: 1.1.0 """ - def on_dismiss(self, *args): + def on_dismiss(self, *args) -> None: """ Default dismiss event handler. @@ -775,15 +795,15 @@ class MDFileManager(MDRelativeLayout): or self.selector == "multi" or self.selector == "folder" ): - self.selection_button = MDFloatingActionButton( + self.selection_button = MDFabButton( on_release=self.select_directory_on_press_button, - md_bg_color=self.theme_cls.primary_color + theme_bg_color="Custom", + md_bg_color=self.theme_cls.primaryColor if not self.background_color_selection_button else self.background_color_selection_button, icon=self.icon_selection_button, pos_hint={"right": 0.99}, y=dp(12), - elevation=0, ) self.add_widget(self.selection_button) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc index 1fefc72..90447bc 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc index da15de3..049c31f 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/__pycache__/fitimage.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/fitimage.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/fitimage.py index 246bb5a..5079016 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/fitimage.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/fitimage/fitimage.py @@ -2,57 +2,8 @@ Components/FitImage =================== -Feature to automatically crop a `Kivy` image to fit your layout -Write by Benedikt Zwölfer - -Referene - https://gist.github.com/benni12er/95a45eb168fc33a4fcd2d545af692dad - - -Example: -======== - -.. tabs:: - - .. tab:: Declarative KV styles - - .. code-block:: kv - - MDBoxLayout: - size_hint_y: None - height: "200dp" - orientation: 'vertical' - - FitImage: - size_hint_y: 3 - source: 'images/img1.jpg' - - FitImage: - size_hint_y: 1 - source: 'images/img2.jpg' - - .. tab:: Declarative python styles - - .. code-block:: python - - MDBoxLayout( - FitImage( - size_hint_y=.3, - source='images/img1.jpg', - ), - FitImage( - size_hint_y=.7, - source='images/img2.jpg', - ), - size_hint_y=None, - height="200dp", - orientation='vertical', - ) - -Example with round corners: -=========================== - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fitimage-round-corners.png - :align: center +Example +======= .. tabs:: @@ -66,33 +17,36 @@ Example with round corners: KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor - MDCard: - radius: 36 - md_bg_color: "grey" + MDBoxLayout: + radius: "36dp" pos_hint: {"center_x": .5, "center_y": .5} size_hint: .4, .8 + md_bg_color: self.theme_cls.onSurfaceVariantColor FitImage: - source: "bg.jpg" + source: "image.png" size_hint_y: .35 pos_hint: {"top": 1} - radius: 36, 36, 0, 0 + radius: "36dp", "36dp", 0, 0 ''' class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" return Builder.load_string(KV) Example().run() + .. tab:: Declarative python styles .. code-block:: python + from kivy.metrics import dp + from kivymd.app import MDApp from kivymd.uix.card import MDCard from kivymd.uix.fitimage import FitImage @@ -101,19 +55,18 @@ Example with round corners: class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" return ( MDScreen( - MDCard( + MDBoxLayout( FitImage( - source="bg.jpg", + source="image.png", size_hint_y=0.35, pos_hint={"top": 1}, - radius=(36, 36, 0, 0), + radius=(dp(36), dp(36), 0, 0), ), - radius=36, - md_bg_color="grey", - pos_hint={"center_x": .5, "center_y": .5}, + radius=dp(36), + md_bg_color=self.theme_cls.onSurfaceVariantColor, + pos_hint={"center_x": 0.5, "center_y": 0.5}, size_hint=(0.4, 0.8), ), ) @@ -121,118 +74,39 @@ Example with round corners: Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fitimage-round-corners.png + :align: center """ __all__ = ("FitImage",) -from kivy.clock import Clock -from kivy.graphics.context_instructions import Color -from kivy.graphics.vertex_instructions import Rectangle -from kivy.properties import BooleanProperty, ObjectProperty +from kivy.properties import OptionProperty from kivy.uix.image import AsyncImage -from kivy.uix.widget import Widget from kivymd.uix.behaviors import StencilBehavior -from kivymd.uix.boxlayout import MDBoxLayout +from kivymd.uix.behaviors import DeclarativeBehavior -class FitImage(MDBoxLayout, StencilBehavior): +class FitImage(DeclarativeBehavior, StencilBehavior, AsyncImage): """ Fit image class. For more information, see in the - :class:`~kivymd.uix.boxlayout.MDLayout` and - :class:`~kivymd.uix.behaviors.StencilBehavior` classes documentation. + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.image.AsyncImage` and + :class:`~kivymd.uix.behaviors.stencil_behavior.StencilBehavior` + classes documentation. """ - source = ObjectProperty() + fit_mode = OptionProperty( + "cover", options=["scale-down", "fill", "contain", "cover"] + ) """ - Filename/source of your image. + Image will be stretched horizontally or vertically to fill the widget box, + **maintaining its aspect ratio**. If the image has a different aspect ratio + than the widget, then the image will be clipped to fit. - :attr:`source` is a :class:`~kivy.properties.StringProperty` - and defaults to None. + :attr:`fit_mode` is a :class:`~kivy.properties.OptionProperty` and + defaults to `'cover'`. """ - - mipmap = BooleanProperty(False) - """ - Indicate if you want OpenGL mipmapping to be applied to the texture. - Read :ref:`mipmap` for more information. - - .. versionadded:: 1.0.0 - - :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - - _container = ObjectProperty() - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Clock.schedule_once(self._late_init) - - def _late_init(self, *args): - self._container = Container(self.source, self.mipmap) - self.bind(source=self._container.setter("source")) - self.add_widget(self._container) - - def reload(self): - self._container.image.reload() - - -class Container(Widget): - source = ObjectProperty() - image = ObjectProperty() - - def __init__(self, source, mipmap, **kwargs): - super().__init__(**kwargs) - self.image = AsyncImage(mipmap=mipmap) - self.loader_clock = Clock.schedule_interval( - self.adjust_size, self.image.anim_delay - ) - self.image.bind( - on_load=lambda inst: ( - self.adjust_size(), - self.loader_clock.cancel(), - ) - ) - self.source = source - self.bind(size=self.adjust_size, pos=self.adjust_size) - - def on_source(self, instance, value): - if isinstance(value, str): - self.image.source = value - else: - self.image.texture = value - self.adjust_size() - - def adjust_size(self, *args): - if not self.parent or not self.image.texture: - return - - (par_x, par_y) = self.parent.size - - if par_x == 0 or par_y == 0: - with self.canvas: - self.canvas.clear() - return - - par_scale = par_x / par_y - (img_x, img_y) = self.image.texture.size - img_scale = img_x / img_y - - if par_scale > img_scale: - (img_x_new, img_y_new) = (img_x, img_x / par_scale) - else: - (img_x_new, img_y_new) = (img_y * par_scale, img_y) - - crop_pos_x = (img_x - img_x_new) / 2 - crop_pos_y = (img_y - img_y_new) / 2 - - subtexture = self.image.texture.get_region( - crop_pos_x, crop_pos_y, img_x_new, img_y_new - ) - - with self.canvas: - self.canvas.clear() - Color(1, 1, 1) - Rectangle(texture=subtexture, pos=self.pos, size=(par_x, par_y)) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/floatlayout.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/floatlayout.py index b64ddcf..7832d34 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/floatlayout.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/floatlayout.py @@ -13,7 +13,7 @@ FloatLayout FloatLayout: canvas: Color: - rgba: app.theme_cls.primary_color + rgba: app.theme_cls.primaryColor RoundedRectangle: pos: self.pos size: self.size @@ -26,7 +26,7 @@ MDFloatLayout MDFloatLayout: radius: [25, 0, 0, 0] - md_bg_color: app.theme_cls.primary_color + md_bg_color: app.theme_cls.primaryColor .. Warning:: For a :class:`~kivy.uix.floatlayout.FloatLayout`, the ``minimum_size`` attributes are always 0, so you cannot use @@ -37,13 +37,24 @@ from kivy.uix.floatlayout import FloatLayout from kivymd.theming import ThemableBehavior from kivymd.uix import MDAdaptiveWidget -from kivymd.uix.behaviors import DeclarativeBehavior +from kivymd.uix.behaviors import DeclarativeBehavior, BackgroundColorBehavior class MDFloatLayout( - DeclarativeBehavior, ThemableBehavior, FloatLayout, MDAdaptiveWidget + DeclarativeBehavior, + ThemableBehavior, + BackgroundColorBehavior, + FloatLayout, + MDAdaptiveWidget, ): """ - Float layout class. For more information, see in the - :class:`~kivy.uix.floatlayout.FloatLayout` class documentation. + Float layout class. + + For more information see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivy.uix.floatlayout.FloatLayout` and + :class:`~kivymd.uix.MDAdaptiveWidget` + classes documentation. """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/gridlayout.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/gridlayout.py index 96bfd79..90f66ec 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/gridlayout.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/gridlayout.py @@ -16,7 +16,7 @@ GridLayout canvas: Color: - rgba: app.theme_cls.primary_color + rgba: app.theme_cls.primaryColor Rectangle: pos: self.pos size: self.size @@ -28,7 +28,7 @@ MDGridLayout MDGridLayout: adaptive_height: True - md_bg_color: app.theme_cls.primary_color + md_bg_color: app.theme_cls.primaryColor Available options are: ---------------------- @@ -38,6 +38,7 @@ Available options are: - adaptive_size_ .. adaptive_height: + adaptive_height --------------- @@ -53,6 +54,7 @@ Equivalent height: self.minimum_height .. adaptive_width: + adaptive_width -------------- @@ -68,6 +70,7 @@ Equivalent width: self.minimum_width .. adaptive_size: + adaptive_size ------------- @@ -87,13 +90,24 @@ from kivy.uix.gridlayout import GridLayout from kivymd.theming import ThemableBehavior from kivymd.uix import MDAdaptiveWidget -from kivymd.uix.behaviors import DeclarativeBehavior +from kivymd.uix.behaviors import DeclarativeBehavior, BackgroundColorBehavior class MDGridLayout( - DeclarativeBehavior, ThemableBehavior, GridLayout, MDAdaptiveWidget + DeclarativeBehavior, + ThemableBehavior, + BackgroundColorBehavior, + GridLayout, + MDAdaptiveWidget, ): """ - Grid layout class. For more information, see in the - :class:`~kivy.uix.gridlayout.GridLayout` class documentation. + Grid layout class. + + For more information see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivy.uix.gridlayout.GridLayout` and + :class:`~kivymd.uix.MDAdaptiveWidget` + classes documentation. """ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/hero.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/hero.py index 70bb572..dba8931 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/hero.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/hero.py @@ -30,12 +30,13 @@ following: - On screen **A**, place the :class:`~MDHeroFrom` container. - Sets a tag (string) for the :class:`~MDHeroFrom` container. - Place a hero in the :class:`~MDHeroFrom` container. -- On screen **B**, place the :class:`~MDHeroTo` container - our hero from screen **A **will fly into this container. +- On screen **B**, place the :class:`~MDHeroTo` container - our hero from screen **A** will fly into this container. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-base.png :align: center .. warning:: + :class:`~MDHeroFrom` container cannot have more than one child widget. Base example @@ -63,18 +64,20 @@ Base example x: 24 FitImage: - source: "kivymd/images/logo/kivymd-icon-512.png" + source: "bg.jpg" size_hint: None, None size: hero_from.size - MDRaisedButton: - text: "Move Hero To Screen B" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["hero"] root.current = "screen B" + MDButtonText: + text: "Move Hero To Screen B" + MDScreen: name: "screen B" hero_to: hero_to @@ -87,22 +90,24 @@ Base example size: "220dp", "220dp" pos_hint: {"center_x": .5, "center_y": .5} - MDRaisedButton: - text: "Move Hero To Screen A" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["hero"] root.current = "screen A" + + MDButtonText: + text: "Move Hero To Screen A" ''' - class Test(MDApp): + class Example(MDApp): def build(self): return Builder.load_string(KV) - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-usage.gif :align: center @@ -126,23 +131,27 @@ container in which the hero is located: .. code-block:: kv - MDRaisedButton: - text: "Move Hero To Screen B" + MDButton: on_release: root.current_heroes = ["hero"] root.current = "screen 2" + MDButtonText: + text: "Move Hero To Screen B" + If you need to switch to a screen that does not contain heroes, set the `current_hero` attribute for the screen manager as "" (empty string): .. code-block:: kv - MDRaisedButton: - text: "Go To Another Screen" + MDButton: on_release: root.current_heroes = [] root.current = "another screen" + MDButtonText: + text: "Go To Another Screen" + Example ------- @@ -168,18 +177,20 @@ Example x: 24 FitImage: - source: "kivymd/images/logo/kivymd-icon-512.png" + source: "bg.jpg" size_hint: None, None size: hero_from.size - MDRaisedButton: - text: "Move Hero To Screen B" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["hero"] root.current = "screen B" + MDButtonText: + text: "Move Hero To Screen B" + MDScreen: name: "screen B" hero_to: hero_to @@ -192,44 +203,51 @@ Example size: "220dp", "220dp" pos_hint: {"center_x": .5, "center_y": .5} - MDRaisedButton: - text: "Go To Screen C" + MDButton: pos_hint: {"center_x": .5} y: "52dp" on_release: root.current_heroes = [] root.current = "screen C" - MDRaisedButton: - text: "Move Hero To Screen A" + MDButtonText: + text: "Go To Screen C" + + MDButton: pos_hint: {"center_x": .5} y: "8dp" on_release: root.current_heroes = ["hero"] root.current = "screen A" + MDButtonText: + text: "Move Hero To Screen A" + MDScreen: name: "screen C" + md_bg_color: "olive" MDLabel: text: "Screen C" halign: "center" - MDRaisedButton: - text: "Back To Screen B" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current = "screen B" + + MDButtonText: + text: "Back To Screen B" ''' - class Test(MDApp): + class Example(MDApp): def build(self): return Builder.load_string(KV) - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-switch-another-screen.gif :align: center @@ -281,14 +299,16 @@ background color of the hero during the flight between the screens: FitImage: source: "https://github.com/kivymd/internal/raw/main/logo/kivymd_logo_blue.png" - MDRaisedButton: - text: "Move Hero To Screen B" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["hero"] root.current = "screen B" + MDButtonText: + text: "Move Hero To Screen B" + MDScreen: name: "screen B" hero_to: hero_to @@ -301,17 +321,19 @@ background color of the hero during the flight between the screens: size: "220dp", "220dp" pos_hint: {"center_x": .5, "center_y": .5} - MDRaisedButton: - text: "Move Hero To Screen A" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["hero"] root.current = "screen A" + + MDButtonText: + text: "Move Hero To Screen A" ''' - class Test(MDApp): + class Example(MDApp): def build(self): return Builder.load_string(KV) @@ -321,7 +343,7 @@ background color of the hero during the flight between the screens: self, instance_hero_widget: MDRelativeLayout, duration: float ): ''' - Called when the hero flies from screen **A** to screen **B**. + Fired when the hero flies from screen **A** to screen **B**. :param instance_hero_widget: dhild widget of the `MDHeroFrom` class. :param duration of the transition animation between screens. @@ -336,7 +358,7 @@ background color of the hero during the flight between the screens: def on_transform_out( self, instance_hero_widget: MDRelativeLayout, duration: float ): - '''Called when the hero back from screen **B** to screen **A**.''' + '''Fired when the hero back from screen **B** to screen **A**.''' Animation( radius=[24, 12, 24, 12], @@ -345,7 +367,7 @@ background color of the hero during the flight between the screens: ).start(instance_hero_widget) - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-events.gif :align: center @@ -358,6 +380,7 @@ Usage with ScrollView from kivy.animation import Animation from kivy.clock import Clock from kivy.lang import Builder + from kivy.metrics import dp from kivy.properties import StringProperty, ObjectProperty from kivymd.app import MDApp @@ -367,27 +390,36 @@ Usage with ScrollView size_hint_y: None height: "200dp" - radius: 24 + radius: "24dp" MDSmartTile: id: tile - radius: 24 - box_radius: 0, 0, 24, 24 - box_color: 0, 0, 0, .5 - source: "kivymd/images/logo/kivymd-icon-512.png" size_hint: None, None size: root.size - mipmap: True on_release: root.on_release() - MDLabel: - text: root.tag - bold: True - font_style: "H6" - opposite_colors: True + MDSmartTileImage: + id: image + source: "bg.jpg" + radius: dp(24) + + MDSmartTileOverlayContainer: + id: overlay + md_bg_color: 0, 0, 0, .5 + adaptive_height: True + padding: "8dp" + spacing: "8dp" + radius: [0, 0, dp(24), dp(24)] + + MDLabel: + text: root.tag + theme_text_color: "Custom" + text_color: "white" + adaptive_height: True MDScreenManager: + md_bg_color: self.theme_cls.backgroundColor MDScreen: name: "screen A" @@ -411,13 +443,15 @@ Usage with ScrollView height: "220dp" pos_hint: {"top": 1} - MDRaisedButton: - text: "Move Hero To Screen A" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = [hero_to.tag] root.current = "screen A" + + MDButtonText: + text: "Move Hero To Screen A" ''' @@ -427,21 +461,26 @@ Usage with ScrollView def __init__(self, **kwargs): super().__init__(**kwargs) - self.ids.tile.ids.image.ripple_duration_in_fast = 0.05 + self.ids.image.ripple_duration_in_fast = 0.05 def on_transform_in(self, instance_hero_widget, duration): - Animation( - radius=[0, 0, 0, 0], - box_radius=[0, 0, 0, 0], - duration=duration, - ).start(instance_hero_widget) + for instance in [ + instance_hero_widget, + instance_hero_widget._overlay_container, + instance_hero_widget._image, + ]: + Animation(radius=[0, 0, 0, 0], duration=duration).start(instance) def on_transform_out(self, instance_hero_widget, duration): - Animation( - radius=[24, 24, 24, 24], - box_radius=[0, 0, 24, 24], - duration=duration, - ).start(instance_hero_widget) + for instance, radius in { + instance_hero_widget: [dp(24), dp(24), dp(24), dp(24)], + instance_hero_widget._overlay_container: [0, 0, dp(24), dp(24)], + instance_hero_widget._image: [dp(24), dp(24), dp(24), dp(24)], + }.items(): + Animation( + radius=radius, + duration=duration, + ).start(instance) def on_release(self): def switch_screen(*args): @@ -452,7 +491,7 @@ Usage with ScrollView Clock.schedule_once(switch_screen, 0.2) - class Test(MDApp): + class Example(MDApp): def build(self): return Builder.load_string(KV) @@ -466,7 +505,7 @@ Usage with ScrollView self.root.ids.box.add_widget(hero_item) - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-usage-with-scrollview.gif :align: center @@ -496,9 +535,10 @@ Using multiple heroes at the same time x: 24 FitImage: - source: "kivymd/images/logo/kivymd-icon-512.png" + source: "avatar.png" size_hint: None, None size: hero_kivymd.size + radius: self.height / 2 MDHeroFrom: id: hero_kivy @@ -509,18 +549,21 @@ Using multiple heroes at the same time x: 324 FitImage: - source: "data/logo/kivy-icon-512.png" + source: "bg.jpg" size_hint: None, None size: hero_kivy.size + radius: self.height / 2 - MDRaisedButton: - text: "Move Hero To Screen B" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["kivymd", "kivy"] root.current = "screen B" + MDButtonText: + text: "Move Hero To Screen B" + MDScreen: name: "screen B" heroes_to: hero_to_kivymd, hero_to_kivy @@ -538,13 +581,15 @@ Using multiple heroes at the same time size_hint: None, None pos_hint: {"right": 1, "top": 1} - MDRaisedButton: - text: "Move Hero To Screen A" + MDButton: pos_hint: {"center_x": .5} y: "36dp" on_release: root.current_heroes = ["kivy", "kivymd"] root.current = "screen A" + + MDButtonText: + text: "Move Hero To Screen A" ''' @@ -553,7 +598,7 @@ Using multiple heroes at the same time return Builder.load_string(KV) - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-multiple-heroes.gif :align: center @@ -575,7 +620,7 @@ class MDHeroFrom(MDBoxLayout): `on_transform_in` when the hero flies from screen **A** to screen **B**. `on_transform_out` - Called when the hero back from screen **B** to screen **A**. + Fired when the hero back from screen **B** to screen **A**. """ tag = StringProperty(allownone=True) @@ -592,10 +637,10 @@ class MDHeroFrom(MDBoxLayout): self.register_event_type("on_transform_out") def on_transform_in(self, *args): - """Called when the hero flies from screen **A** to screen **B**.""" + """Fired when the hero flies from screen **A** to screen **B**.""" def on_transform_out(self, *args): - """Called when the hero back from screen **B** to screen **A**.""" + """Fired when the hero back from screen **B** to screen **A**.""" class MDHeroTo(MDBoxLayout): diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__init__.py index 97c897c..c759278 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__init__.py @@ -1,2 +1,6 @@ # NOQA F401 -from .imagelist import MDSmartTile +from .imagelist import ( + MDSmartTile, + MDSmartTileOverlayContainer, + MDSmartTileImage, +) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc index aebdd5f..9240cf5 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc index c15356f..f81622d 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/__pycache__/imagelist.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.kv index fe87f76..cfe2d80 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.kv @@ -1,28 +1,37 @@ - SmartTileImage: - id: image - mipmap: root.mipmap - source: root.source - radius: root.radius if root.radius else [0, 0, 0, 0] - size_hint_y: 1 if root.overlap else None - height: root.height if root.overlap else root.height - box.height - pos: - ((0, 0) if root.overlap else (0, box.height)) \ - if root.box_position == "footer" else \ - (0, 0) - on_release: root.dispatch("on_release") - on_press: root.dispatch("on_press") - _no_ripple_effect: root._no_ripple_effect - SmartTileOverlayBox: - id: box - md_bg_color: root.box_color - size_hint_y: None - padding: "8dp" - radius: root.box_radius - height: "68dp" if root.lines == 2 else "48dp" - pos: - (0, 0) \ - if root.box_position == "footer" else \ - (0, root.height - self.height) + + size_hint_y: + (1 if self._smart_tile.overlap else None) \ + if self._smart_tile else None + height: + ( \ + self._smart_tile.height \ + if self._smart_tile.overlap else \ + self._smart_tile.height - (self._overlay_container.height if self._overlay_container else 0) \ + ) \ + if self._smart_tile else 0 + pos: + ( \ + ( \ + (0, 0) \ + if self._smart_tile.overlap else \ + (0, (self._overlay_container.height if self._overlay_container else 0)) \ + ) \ + if self._smart_tile.overlay_mode == "footer" else \ + (0, 0) \ + ) \ + if self._smart_tile else (0, 0) + on_release: self._smart_tile.dispatch("on_release") + on_press: self._smart_tile.dispatch("on_press") + + + + pos: + ( \ + (0, 0) \ + if self._smart_tile.overlay_mode == "footer" else \ + (0, self._smart_tile.height - self.height) \ + ) \ + if self._smart_tile else (0, 0) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.py index ba84b14..88092cf 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/imagelist/imagelist.py @@ -11,11 +11,32 @@ Components/ImageList .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/image-list.png :align: center -`KivyMD` provides the following tile classes for use: - Usage ----- +.. code-block:: kv + + MDSmartTile: + [...] + + MDSmartTileImage: + [...] + + MDSmartTileOverlayContainer: + [...] + + # Content + [...] + +Anatomy +------- + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/image-list-anatomy.png + :align: center + +Example +------- + .. code-block:: python from kivy.lang import Builder @@ -24,69 +45,103 @@ Usage KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor MDSmartTile: - radius: 24 - box_radius: [0, 0, 24, 24] - box_color: 1, 1, 1, .2 - source: "cats.jpg" pos_hint: {"center_x": .5, "center_y": .5} size_hint: None, None size: "320dp", "320dp" + overlap: False - MDIconButton: - icon: "heart-outline" - theme_icon_color: "Custom" - icon_color: 1, 0, 0, 1 - pos_hint: {"center_y": .5} - on_release: self.icon = "heart" if self.icon == "heart-outline" else "heart-outline" + MDSmartTileImage: + source: "bg.jpg" + radius: [dp(24), dp(24), 0, 0] - MDLabel: - text: "Julia and Julie" - bold: True - color: 1, 1, 1, 1 + MDSmartTileOverlayContainer: + md_bg_color: 0, 0, 0, .5 + adaptive_height: True + padding: "8dp" + spacing: "8dp" + radius: [0, 0, dp(24), dp(24)] + + MDIconButton: + icon: "heart-outline" + theme_icon_color: "Custom" + icon_color: 1, 0, 0, 1 + pos_hint: {"center_y": .5} + on_release: + self.icon = "heart" \\ + if self.icon == "heart-outline" else \\ + "heart-outline" + + MDLabel: + text: "Ibanez GRG121DX-BKF" + theme_text_color: "Custom" + text_color: "white" ''' - class MyApp(MDApp): + class Example(MDApp): def build(self): + self.theme_cls.theme_style = "Dark" return Builder.load_string(KV) - MyApp().run() + Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-usage.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/image-list-example.png :align: center -Implementation --------------- +API break +========= -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-usage-sceleton.png - :align: center +1.2.0 version +------------- + +.. code-block:: kv + + MDSmartTile: + [...] + + # Content. + MDIconButton: + [...] + + MDLabel: + [...] + + +2.0.0 version +------------- + +.. code-block:: kv + + MDSmartTile: + [...] + + MDSmartTileImage: + [...] + + MDSmartTileOverlayContainer: + [...] + + # Content. + [...] """ -__all__ = [ - "MDSmartTile", -] +__all__ = ["MDSmartTile", "MDSmartTileOverlayContainer", "MDSmartTileImage"] import os from kivy.clock import Clock from kivy.lang import Builder -from kivy.properties import ( - BooleanProperty, - ColorProperty, - OptionProperty, - StringProperty, - VariableListProperty, -) +from kivy.properties import BooleanProperty, OptionProperty, ObjectProperty from kivy.uix.behaviors import ButtonBehavior from kivymd import uix_path from kivymd.uix.behaviors import RectangularRippleBehavior from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.fitimage import FitImage -from kivymd.uix.label import MDLabel from kivymd.uix.relativelayout import MDRelativeLayout with open( @@ -95,12 +150,39 @@ with open( Builder.load_string(kv_file.read()) -class SmartTileImage(RectangularRippleBehavior, ButtonBehavior, FitImage): - """Implements the tile image.""" +class MDSmartTileImage(RectangularRippleBehavior, ButtonBehavior, FitImage): + """ + Implements the tile image. + + .. versionchanged:: 2.0.0 + + The `SmartTileImage` class has been renamed to `MDSmartTileImage`. + + For more information, see in the + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and + :class:`~kivymd.uix.fitimage.fitimage.FitImage` + classes documentation. + """ + + _smart_tile = ObjectProperty() + _overlay_container = ObjectProperty() -class SmartTileOverlayBox(MDBoxLayout): - """Implements a container for custom widgets to be added to the tile.""" +class MDSmartTileOverlayContainer(MDBoxLayout): + """ + Implements a container for custom widgets to be added to the tile. + + .. versionchanged:: 2.0.0 + + The `SmartTileOverlayBox` class has been renamed to + `MDSmartTileOverlayContainer`. + + For more information, see in the + :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. + """ + + _smart_tile = ObjectProperty() class MDSmartTile(MDRelativeLayout): @@ -108,73 +190,33 @@ class MDSmartTile(MDRelativeLayout): A tile for more complex needs. For more information, see in the - :class:`~kivymd.uix.relativelayout.MDRelativeLayout` class documentation. + :class:`~kivymd.uix.relativelayout.MDRelativeLayout` + class documentation. Includes an image, a container to place overlays and a box that can act as a header or a footer, as described in the Material Design specs. :Events: `on_press` - Called when the button is pressed. + Fired when the button is pressed. `on_release` - Called when the button is released (i.e. the touch/click that + Fired when the button is released (i.e. the touch/click that pressed the button goes away). """ - box_radius = VariableListProperty([0], length=4) - """ - Box radius. - - .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDSmartTile: - radius: 24 - box_radius: [0, 0, 24, 24] - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-box-radius.png - :align: center - - :attr:`box_radius` is an :class:`~kivy.properties.VariableListProperty` - and defaults to `[0, 0, 0, 0]`. - """ - - box_color = ColorProperty((0, 0, 0, 0.5)) - """ - Sets the color in (r, g, b, a) or string format and opacity for the - information box. - - .. code-block:: kv - - MDSmartTile: - radius: 24 - box_radius: [0, 0, 24, 24] - box_color: 0, 1, 0, .5 - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-box-color.png - :align: center - - :attr:`box_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `(0, 0, 0, 0.5)`. - """ - - box_position = OptionProperty("footer", options=["footer", "header"]) + overlay_mode = OptionProperty("footer", options=["footer", "header"]) """ Determines weather the information box acts as a header or footer to the image. Available are options: `'footer'`, `'header'`. - .. code-block:: kv + .. versionchanged:: 2.0.0 - MDSmartTile: - radius: 24 - box_radius: [24, 24, 0, 0] - box_position: "header" + The `box_position` attribute has been renamed to `overlay_mode`. - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-box-position.png + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/image-list-overlay-mode.png :align: center - :attr:`box_position` is a :class:`~kivy.properties.OptionProperty` + :attr:`overlay_mode` is a :class:`~kivy.properties.OptionProperty` and defaults to `'footer'`. """ @@ -182,98 +224,42 @@ class MDSmartTile(MDRelativeLayout): """ Determines if the `header/footer` overlaps on top of the image or not. - .. code-block:: kv - - MDSmartTile: - radius: [24, 24, 0, 0] - box_radius: [0, 0, 24, 24] - overlap: False - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-overlap.png + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/image-list-overlap.png :align: center :attr:`overlap` is a :class:`~kivy.properties.BooleanProperty` and defaults to `True`. """ - lines = OptionProperty(1, options=[1, 2]) - """ - Number of lines in the `header/footer`. As per `Material Design specs`, - only 1 and 2 are valid values. Available are options: `1`, `2`. - This parameter just increases the height of the container for custom - elements. - - .. code-block:: kv - - MDSmartTile: - radius: 24 - box_radius: [0, 0, 24, 24] - lines: 2 - source: "cats.jpg" - pos_hint: {"center_x": .5, "center_y": .5} - size_hint: None, None - size: "320dp", "320dp" - - MDIconButton: - icon: "heart-outline" - theme_icon_color: "Custom" - icon_color: 1, 0, 0, 1 - pos_hint: {"center_y": .5} - on_release: self.icon = "heart" if self.icon == "heart-outline" else "heart-outline" - - TwoLineListItem: - text: "[color=#ffffff][b]My cats[/b][/color]" - secondary_text: "[color=#808080][b]Julia and Julie[/b][/color]" - pos_hint: {"center_y": .5} - _no_ripple_effect: True - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-smart-tile-lines.png - :align: center - - :attr:`lines` is a :class:`~kivy.properties.OptionProperty` - and defaults to `1`. - """ - - source = StringProperty() - """ - Path to tile image. See :attr:`~kivy.uix.image.Image.source`. - - :attr:`source` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - mipmap = BooleanProperty(False) - """ - Indicate if you want OpenGL mipmapping to be applied to the texture. - Read :ref:`mipmap` for more information. - - .. versionadded:: 1.0.0 - - :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ - _no_ripple_effect = BooleanProperty(False) + _overlay_container = ObjectProperty() + _image = ObjectProperty() - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, **kwargs): + super().__init__(**kwargs) self.register_event_type("on_release") self.register_event_type("on_press") def on_release(self, *args): """ - Called when the button is released (i.e. the touch/click that + Fired when the button is released (i.e. the touch/click that pressed the button goes away). """ def on_press(self, *args): - """Called when the button is pressed.""" + """Fired when the button is pressed.""" def add_widget(self, widget, *args, **kwargs): - if isinstance(widget, (SmartTileImage, SmartTileOverlayBox)): + def set_overlay_container(_widget): + _widget._overlay_container = self._overlay_container + + if isinstance(widget, MDSmartTileOverlayContainer): + widget._smart_tile = self + self._overlay_container = widget + return super().add_widget(widget, *args, **kwargs) + elif isinstance(widget, MDSmartTileImage): + self._image = widget + widget._smart_tile = self + widget._overlay_container = self._overlay_container + Clock.schedule_once(lambda x: set_overlay_container(widget), 0.5) return super().add_widget(widget, *args, **kwargs) - else: - if isinstance(widget, MDLabel): - widget.shorten = True - widget.shorten_from = "right" - Clock.schedule_once(lambda x: self.ids.box.add_widget(widget)) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/__init__.cpython-311.pyc index 9bb1425..1fec410 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/label.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/label.cpython-311.pyc index 12bb3fd..a11c520 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/label.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/__pycache__/label.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.kv index 7fba348..e6b747a 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.kv @@ -2,67 +2,40 @@ - disabled_color: self.theme_cls.disabled_hint_text_color text_size: (self.width if not self.adaptive_width else None) \ if not self.adaptive_size else None, \ None + color: + self.text_color \ + if self.text_color else \ + self.theme_cls.onSurfaceColor + disabled_color: + app.theme_cls.onSurfaceColor[:-1] + \ + [self.label_opacity_value_disabled_text] + font_size: + self.theme_cls.font_styles[self.font_style][self.role]["font-size"] \ + if self.theme_font_size == "Primary" else self.font_size + line_height: + self.theme_cls.font_styles[self.font_style][self.role]["line-height"] \ + if self.theme_line_height == "Primary" else self.line_height + font_name: + self.theme_cls.font_styles[self.font_style][self.role]["font-name"] \ + if self.theme_font_name == "Primary" else self.font_name -: - canvas: - Color: - rgba: (1, 1, 1, 1) if self.source else (0, 0, 0, 0) - Rectangle: - group: "rectangle" - source: self.source if self.source else None - pos: - self.pos \ - if not self.source else \ - (self.x - self._size[0] / 2, self.y) - size: - self._size \ - if self.source else \ - self.size - + font_style: "Icon" - text: u"{}".format(md_icons[root.icon]) if root.icon in md_icons else "blank" - source: None if root.icon in md_icons else root.icon - - # Badge icon. - MDLabel: - id: badge - font_style: "Icon" - adaptive_size: True - opposite_icon_color: True - color: root.badge_icon_color - text: - u"{}".format(md_icons[root.badge_icon]) \ - if root.badge_icon in md_icons else \ - "" - pos: - root.x + root.width / 2 + self.width / 2 - dp(6), \ - root.y + self.texture_size[1] / 2 + dp(6) - font_size: - ( \ - root.font_size / 1.5 \ - if not root.badge_font_size else \ - root.badge_font_size \ - ) \ - if root.badge_icon and root.badge_icon != "blank" else 0 - - canvas.before: - Color: - rgba: - ( \ - root.badge_bg_color \ - if root.badge_bg_color else \ - app.theme_cls.error_color \ - ) \ - if root.badge_icon else \ - (0, 0, 0, 0) - RoundedRectangle: - group: "badge" - radius: [self.width / 2,] - pos: self.pos - size: self.size + source: None if self.icon in md_icons else self.icon + adaptive_size: True + text: + ( \ + u"{}".format(md_icons[self.icon]) \ + if self.icon in md_icons else \ + "blank" \ + ) \ + if self.font_name == "Icons" else self.icon + color: + self.icon_color \ + if self.icon_color else \ + self.theme_cls.onSurfaceVariantColor diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.py index 73bd46b..5c9dfa6 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/label/label.py @@ -2,7 +2,7 @@ Components/Label ================ -.. rubric:: The :class:`MDLabel` widget is for rendering text. +.. rubric:: The `MDLabel` widget is for rendering text. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/label.png :align: center @@ -11,12 +11,12 @@ Components/Label - MDIcon_ .. MDLabel: + MDLabel ------- -Class :class:`MDLabel` inherited from the :class:`~kivy.uix.label.Label` class -but for :class:`MDLabel` the ``text_size`` parameter is ``(self.width, None)`` -and default is positioned on the left: +Example +------- .. tabs:: @@ -30,20 +30,21 @@ and default is positioned on the left: KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor MDLabel: text: "MDLabel" + halign: "center" ''' - class Test(MDApp): + class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" return Builder.load_string(KV) - Test().run() + Example().run() .. tab:: Declarative Python style @@ -59,83 +60,24 @@ and default is positioned on the left: class Test(MDApp): def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" return ( MDScreen( MDLabel( - text="MDLabel" - ) + text="MDLabel", + halign="center", + ), + md_bg_color=self.theme_cls.backgroundColor, ) ) Test().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-to-left.png - :align: center - -.. Note:: See :attr:`~kivy.uix.label.Label.halign` - and :attr:`~kivy.uix.label.Label.valign` attributes - of the :class:`~kivy.uix.label.Label` class - -.. code-block:: kv - - MDLabel: - text: "MDLabel" - halign: "center" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-to-center.png - :align: center - -:class:`~MDLabel` color: ------------------------- - -:class:`~MDLabel` provides standard color themes for label color management: - -.. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - from kivymd.uix.label import MDLabel - - KV = ''' - MDBoxLayout: - orientation: "vertical" - ''' - - - class Test(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - screen = Builder.load_string(KV) - - # Names of standard color themes. - for name_theme in [ - "Primary", - "Secondary", - "Hint", - "Error", - "ContrastParentBackground", - ]: - screen.add_widget( - MDLabel( - text=name_theme, - halign="center", - theme_text_color=name_theme, - ) - ) - return screen - - - Test().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-theme-text-color.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/label-example.png :align: center To use a custom color for :class:`~MDLabel`, use a theme `'Custom'`. -After that, you can specify the desired color in the ``rgba`` format -in the ``text_color`` parameter: +After that, you can specify the desired color in the ``text_color`` parameter: .. code-block:: kv @@ -143,53 +85,93 @@ in the ``text_color`` parameter: text: "Custom color" halign: "center" theme_text_color: "Custom" - text_color: "blue" + text_color: "red" .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-custom-color.png :align: center :class:`~MDLabel` provides standard font styles for labels. To do this, specify the name of the desired style in the :attr:`~MDLabel.font_style` -parameter: +and :attr:`~MDLabel.role` parameters: + +.. code-block:: kv + + MDLabel: + text: "Display, role - 'large'" + font_style: "Display" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-font-style-display-large.png + :align: center + +.. code-block:: kv + + MDLabel: + text: "Display, role - 'small'" + font_style: "Display" + role: "small" + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-font-style-display-small.png + :align: center + +.. seealso:: + + `Material Design spec, Typography `_ + + +All styles +---------- .. code-block:: python from kivy.lang import Builder - from kivymd.app import MDApp - from kivymd.uix.label import MDLabel from kivymd.font_definitions import theme_font_styles + from kivymd.app import MDApp KV = ''' - MDScrollView: + MDScreen: + md_bg_color: self.theme_cls.backgroundColor - MDList: - id: box - spacing: "8dp" + MDRecycleView: + id: rv + key_viewclass: 'viewclass' + key_size: 'height' + + RecycleBoxLayout: + padding: dp(10) + spacing: dp(10) + default_size: None, dp(48) + default_size_hint: 1, None + size_hint_y: None + height: self.minimum_height + orientation: "vertical" ''' - class Test(MDApp): + class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" - screen = Builder.load_string(KV) + return Builder.load_string(KV) - # Names of standard font styles. - for name_style in theme_font_styles[:-1]: - screen.ids.box.add_widget( - MDLabel( - text=f"{name_style} style", - halign="center", - font_style=name_style, - adaptive_height=True, - ) - ) - return screen + def on_start(self): + for style in theme_font_styles: + if style != "Icon": + for role in theme_font_styles[style]: + font_size = int(theme_font_styles[style][role]["font-size"]) + self.root.ids.rv.data.append( + { + "viewclass": "MDLabel", + "text": f"{style} {role} {font_size} sp", + "adaptive_height": "True", + "font_style": style, + "role": role, + } + ) - Test().run() + Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-label-font-style.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/label-font-style-preview.png :align: center Highlighting and copying labels @@ -210,11 +192,12 @@ You can highlight labels by double tap on the label: KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor MDLabel: adaptive_size: True pos_hint: {"center_x": .5, "center_y": .5} - text: "MDLabel" + text: "Do a double click on me" allow_selection: True padding: "4dp", "4dp" ''' @@ -223,7 +206,6 @@ You can highlight labels by double tap on the label: class Example(MDApp): def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" return Builder.load_string(KV) @@ -233,7 +215,7 @@ You can highlight labels by double tap on the label: .. code-block:: python - from kivy.lang.builder import Builder + from kivy.clock import Clock from kivymd.app import MDApp from kivymd.uix.label import MDLabel @@ -241,18 +223,23 @@ You can highlight labels by double tap on the label: class Example(MDApp): + def on_start(self): + def on_start(dt): + self.root.md_bg_color = self.theme_cls.backgroundColor + + Clock.schedule_once(on_start) + def build(self): self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" return ( MDScreen( MDLabel( adaptive_size=True, - pos_hint={"center_x": .5, "center_y": .5}, - text="MDLabel", + pos_hint={"center_x": 0.5, "center_y": 0.5}, + text="Do a double click on me", allow_selection=True, padding=("4dp", "4dp"), - ) + ), ) ) @@ -345,32 +332,31 @@ Example of copying/cutting labels using the context menu from kivy.lang.builder import Builder from kivy.metrics import dp + from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText from kivymd.app import MDApp from kivymd.uix.label import MDLabel from kivymd.uix.menu import MDDropdownMenu - from kivymd.toast import toast KV = ''' MDBoxLayout: orientation: "vertical" spacing: "12dp" padding: "24dp" + md_bg_color: self.theme_cls.backgroundColor - MDScrollView: - - MDBoxLayout: - id: box - orientation: "vertical" - padding: "24dp" - spacing: "12dp" - adaptive_height: True + MDBoxLayout: + id: box + orientation: "vertical" + padding: "24dp" + spacing: "12dp" + adaptive_height: True MDTextField: max_height: "200dp" - mode: "fill" + mode: "filled" multiline: True - MDWidget: + Widget: ''' data = [ @@ -381,34 +367,37 @@ Example of copying/cutting labels using the context menu "Nisl rhoncus mattis rhoncus urna neque. Orci nulla pellentesque " "dignissim enim. Ac auctor augue mauris augue neque gravida in fermentum. " "Lacus suspendisse faucibus interdum posuere." - ] + def toast(text): + MDSnackbar( + MDSnackbarText( + text=text, + ), + y=dp(24), + pos_hint={"center_x": 0.5}, + size_hint_x=0.3, + ).open() + + class CopyLabel(MDLabel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.allow_selection = True self.adaptive_height = True - self.theme_text_color = "Custom" - self.text_color = self.theme_cls.text_color class Example(MDApp): context_menu = None def build(self): - self.theme_cls.theme_style = "Dark" - self.theme_cls.primary_palette = "Orange" return Builder.load_string(KV) def on_start(self): for text in data: copy_label = CopyLabel(text=text) - copy_label.bind( - on_selection=self.open_context_menu, - on_cancel_selection=self.restore_text_color, - ) + copy_label.bind(on_selection=self.open_context_menu) self.root.ids.box.add_widget(copy_label) def click_item_context_menu( @@ -424,24 +413,17 @@ Example of copying/cutting labels using the context menu if self.context_menu: self.context_menu.dismiss() - def restore_text_color(self, instance_label: CopyLabel) -> None: - instance_label.text_color = self.theme_cls.text_color - def open_context_menu(self, instance_label: CopyLabel) -> None: instance_label.text_color = "black" menu_items = [ { "text": "Copy text", - "viewclass": "OneLineListItem", - "height": dp(48), "on_release": lambda: self.click_item_context_menu( "copy", instance_label ), }, { "text": "Cut text", - "viewclass": "OneLineListItem", - "height": dp(48), "on_release": lambda: self.click_item_context_menu( "cut", instance_label ), @@ -459,6 +441,7 @@ Example of copying/cutting labels using the context menu :align: center .. MDIcon: + MDIcon ------- @@ -481,7 +464,6 @@ The :class:`~MDIcon` class is inherited from MDIcon: icon: "gmail" - pos_hint: {"center_x": .5, "center_y": .5} .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon.png :align: center @@ -493,11 +475,87 @@ MDIcon with badge icon MDIcon: icon: "gmail" - badge_icon: "numeric-10" - pos_hint: {"center_x": .5, "center_y": .5} + + MDBadge: + text: "10+" .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon-badge.png :align: center + +MDIcon with a custom font icon +------------------------------ + +You can use custom fonts to display icons. Such as for example +`Material Symbols `_. You can find the +necessary fonts in the +`materialsymbols-python `_ +repository + +.. code-block:: python + + from kivy.core.text import LabelBase + from kivy.lang import Builder + from kivy.metrics import sp + + from kivymd.app import MDApp + + KV = ''' + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDIcon: + icon: "music_video" + theme_font_name: "Custom" + font_name: "MaterialSymbols" + pos_hint: {"center_x": .5, "center_y": .58} + + MDButton: + pos_hint: {"center_x": .5, "center_y": .47} + + MDButtonIcon: + icon: "music_video" + theme_font_name: "Custom" + font_name: "MaterialSymbols" + + MDButtonText: + text: "Elevated" + ''' + + + class Example(MDApp): + def build(self): + self.theme_cls.theme_style = "Dark" + + LabelBase.register( + name="MaterialSymbols", + fn_regular="Material_Symbols_Outlined-20-200-1_200.ttf", + ) + + self.theme_cls.font_styles["MaterialSymbols"] = { + "large": { + "line-height": 1.64, + "font-name": "MaterialSymbols", + "font-size": sp(57), + }, + "medium": { + "line-height": 1.52, + "font-name": "MaterialSymbols", + "font-size": sp(45), + }, + "small": { + "line-height": 1.44, + "font-name": "MaterialSymbols", + "font-size": sp(36), + }, + } + + return Builder.load_string(KV) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-icon-castom-font.png + :align: center """ from __future__ import annotations @@ -505,45 +563,34 @@ from __future__ import annotations __all__ = ("MDLabel", "MDIcon") import os -from typing import Union from kivy.animation import Animation from kivy.clock import Clock from kivy.core.clipboard import Clipboard from kivy.core.window import Window -from kivy.graphics import Color, Rectangle +from kivy.graphics import Color, SmoothRoundedRectangle from kivy.lang import Builder -from kivy.metrics import sp + from kivy.properties import ( - AliasProperty, BooleanProperty, ColorProperty, - ListProperty, - NumericProperty, ObjectProperty, - OptionProperty, StringProperty, + VariableListProperty, + OptionProperty, ) from kivy.uix.label import Label from kivymd import uix_path from kivymd.theming import ThemableBehavior -from kivymd.theming_dynamic_text import get_contrast_text_color from kivymd.uix import MDAdaptiveWidget -from kivymd.uix.behaviors import DeclarativeBehavior, TouchBehavior -from kivymd.uix.floatlayout import MDFloatLayout +from kivymd.uix.behaviors import ( + DeclarativeBehavior, + TouchBehavior, + BackgroundColorBehavior, +) +from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior -__MDLabel_colors__ = { - "Primary": "text_color", - "Secondary": "secondary_text_color", - "Hint": "disabled_hint_text_color", - "Error": "error_color", - "OP": { - "Primary": "opposite_text_color", - "Secondary": "opposite_secondary_text_color", - "Hint": "opposite_disabled_hint_text_color", - }, -} with open( os.path.join(uix_path, "label", "label.kv"), encoding="utf-8" @@ -554,80 +601,68 @@ with open( class MDLabel( DeclarativeBehavior, ThemableBehavior, + BackgroundColorBehavior, Label, MDAdaptiveWidget, TouchBehavior, + StateLayerBehavior, ): """ Label class. For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and :class:`~kivy.uix.label.Label` and :class:`~kivymd.uix.MDAdaptiveWidget` and - :class:`~kivymd.uix.behaviors.TouchBehavior` + :class:`~kivymd.uix.behaviors.touch_behavior.TouchBehavior` and + :class:`~kivymd.uix.behaviors.state_layer_behavior.StateLayerBehavior` classes documentation. :Events: `on_ref_press` - Called when the user clicks on a word referenced with a + Fired when the user clicks on a word referenced with a ``[ref]`` tag in a text markup. `on_copy` - Called when double-tapping on the label. + Fired when double-tapping on the label. `on_selection` - Called when double-tapping on the label. + Fired when double-tapping on the label. `on_cancel_selection` - Called when the highlighting is removed from the label text. + Fired when the highlighting is removed from the label text. """ - font_style = StringProperty("Body1") + font_style = StringProperty("Body") """ Label font style. - Available vanilla font_style are: `'H1'`, `'H2'`, `'H3'`, `'H4'`, `'H5'`, - `'H6'`, `'Subtitle1'`, `'Subtitle2'`, `'Body1'`, `'Body2'`, `'Button'`, - `'Caption'`, `'Overline'`, `'Icon'`. + .. versionchanged:: 2.0.0 + + Available vanilla font_style are: `'Display'`, `'Headline'`, `'Title'`, + `'Label'`, `'Body'``. :attr:`font_style` is an :class:`~kivy.properties.StringProperty` - and defaults to `'Body1'`. + and defaults to `'Body'`. """ - _capitalizing = BooleanProperty(False) - - def _get_text(self): - if self._capitalizing: - return self._text.upper() - return self._text - - def _set_text(self, value): - self._text = value - - _text = StringProperty() - - text = AliasProperty(_get_text, _set_text, bind=["_text", "_capitalizing"]) - """Text of the label.""" - - theme_text_color = OptionProperty( - "Primary", - allownone=True, - options=[ - "Primary", - "Secondary", - "Hint", - "Error", - "Custom", - "ContrastParentBackground", - ], - ) + role = OptionProperty("large", options=["large", "medium", "small"]) """ - Label color scheme name. + Role of font style. - Available options are: `'Primary'`, `'Secondary'`, `'Hint'`, `'Error'`, - `'Custom'`, `'ContrastParentBackground'`. + .. versionadded:: 2.0.0 - :attr:`theme_text_color` is an :class:`~kivy.properties.OptionProperty` - and defaults to `None`. + Available options are: `'large'`, `'medium'`, `'small'`. + + :attr:`role` is an :class:`~kivy.properties.StringProperty` + and defaults to `'large'`. + """ + + text = StringProperty() + """ + Text of the label. + + :attr:`text` is an :class:`~kivy.properties.StringProperty` + and defaults to `''`. """ text_color = ColorProperty(None) @@ -690,70 +725,48 @@ class MDLabel( and defaults to `False`. """ - _text_color_str = StringProperty() + radius = VariableListProperty([0], length=4) + """ + Label radius. - parent_background = ColorProperty(None) - can_capitalize = BooleanProperty(True) - canvas_bg = ObjectProperty() + :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` + and defaults to `[0, 0, 0, 0]`. + """ + + _canvas_bg = ObjectProperty(allownone=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.bind( - font_style=self.update_font_style, - can_capitalize=self.update_font_style, - ) - self.theme_cls.bind(theme_style=self._do_update_theme_color) self.register_event_type("on_copy") self.register_event_type("on_selection") self.register_event_type("on_cancel_selection") - self.on_theme_text_color(None, self.theme_text_color) - self.update_font_style(None, "") - self.on_opposite_colors(None, self.opposite_colors) - Clock.schedule_once(self.check_font_styles) - - def check_font_styles(self, interval: Union[int, float] = 0) -> bool: - if self.font_style not in list(self.theme_cls.font_styles.keys()): - raise ValueError( - f"MDLabel.font_style is set to an invalid option '{self.font_style}'." - f"Must be one of: {list(self.theme_cls.font_styles)}" - ) - else: - return True - - def update_font_style(self, instance_label, font_style: str) -> None: - if self.check_font_styles() is True: - font_info = self.theme_cls.font_styles[self.font_style] - self.font_name = font_info[0] - if self.font_style in list(self.theme_cls.font_styles.keys())[0:14]: - self.font_size = sp(font_info[1]) - - if font_info[2] and self.can_capitalize: - self._capitalizing = True - else: - self._capitalizing = False - - # TODO: Add letter spacing change - # self.letter_spacing = font_info[3] def do_selection(self) -> None: if not self.is_selected: self.md_bg_color = ( - self.theme_cls.primary_light + self.theme_cls.secondaryContainerColor if not self.color_selection else self.color_selection ) def cancel_selection(self) -> None: if self.is_selected: + self.canvas.before.remove_group("md-label-selection-color") + self.canvas.before.remove_group( + "md-label-selection-color-rectangle" + ) self.md_bg_color = ( - self.theme_cls.bg_normal + self.parent.md_bg_color if not self.color_deselection else self.color_deselection ) self.dispatch("on_cancel_selection") self.is_selected = False + self._canvas_bg = None def on_double_tap(self, touch, *args) -> None: + """Fired by double-clicking on the widget.""" + if self.allow_copy and self.collide_point(*touch.pos): Clipboard.copy(self.text) self.dispatch("on_copy") @@ -762,73 +775,44 @@ class MDLabel( self.dispatch("on_selection") self.is_selected = True - def on_window_touch(self, *args): + def on_window_touch(self, *args) -> None: + """Fired at the on_touch_down event.""" + if self.is_selected: self.cancel_selection() def on_copy(self, *args) -> None: """ - Called when double-tapping on the label. + Fired when double-tapping on the label. .. versionadded:: 1.2.0 """ def on_selection(self, *args) -> None: """ - Called when double-tapping on the label. + Fired when double-tapping on the label. .. versionadded:: 1.2.0 """ def on_cancel_selection(self, *args) -> None: """ - Called when the highlighting is removed from the label text. + Fired when the highlighting is removed from the label text. .. versionadded:: 1.2.0 """ def on_allow_selection(self, instance_label, selection: bool) -> None: + """Fired when the :attr:`allow_selection` value changes.""" + if selection: Window.bind(on_touch_down=self.on_window_touch) else: Window.unbind(on_touch_down=self.on_window_touch) - def on_theme_text_color( - self, instance_label, theme_text_color: str - ) -> None: - op = self.opposite_colors - if op: - self._text_color_str = __MDLabel_colors__.get("OP", "").get( - theme_text_color, "" - ) - else: - self._text_color_str = __MDLabel_colors__.get(theme_text_color, "") - if self._text_color_str: - self._do_update_theme_color() - else: - # 'Custom' and 'ContrastParentBackground' lead here, as well as the - # generic None value it's not yet been set - self._text_color_str = "" - if theme_text_color == "Custom" and self.text_color: - color = self.text_color - elif ( - theme_text_color == "ContrastParentBackground" - and self.parent_background - ): - color = get_contrast_text_color(self.parent_background) - else: - color = [0, 0, 0, 1] + def on_text_color(self, instance_label, color: list | str) -> None: + """Fired when the :attr:`text_color` value changes.""" - if self.theme_cls.theme_style_switch_animation: - Animation( - color=color, - d=self.theme_cls.theme_style_switch_animation_duration, - t="linear", - ).start(self) - else: - self.color = color - - def on_text_color(self, instance_label, color: Union[list, str]) -> None: if self.theme_text_color == "Custom": if self.theme_cls.theme_style_switch_animation: Animation( @@ -839,96 +823,61 @@ class MDLabel( else: self.color = self.text_color - def on_opposite_colors(self, *args) -> None: - self.on_theme_text_color(self, self.theme_text_color) + def on_md_bg_color(self, instance_label, color: list | str) -> None: + """Fired when the :attr:`md_bg_color` value changes.""" - def on_md_bg_color(self, instance_label, color: Union[list, str]) -> None: - self.canvas.remove_group("Background_instruction") - self.canvas.before.clear() - with self.canvas.before: - Color(rgba=color) - self.canvas_bg = Rectangle(pos=self.pos, size=self.size) - self.bind(pos=self.update_canvas_bg_pos) + def on_md_bg_color(*args) -> None: + from kivymd.uix.selectioncontrol import MDCheckbox + from kivymd.uix.tooltip import MDTooltipPlain + + if not issubclass( + self.__class__, (MDCheckbox, MDIcon, MDTooltipPlain) + ): + self.canvas.remove_group("Background_instruction") + + # FIXME: IndexError + # try: + # self.canvas.before.clear() + # except IndexError: + # pass + + with self.canvas.before: + Color(rgba=color, group="md-label-selection-color") + self._canvas_bg = SmoothRoundedRectangle( + pos=self.pos, + size=self.size, + radius=self.radius, + group="md-label-selection-color-rectangle", + ) + self.bind(pos=self.update_canvas_bg_pos) + + Clock.schedule_once(on_md_bg_color) def on_size(self, instance_label, size: list) -> None: - if self.canvas_bg: - self.canvas_bg.size = size + """Fired when the parent window of the application is resized.""" + + if self._canvas_bg: + self._canvas_bg.size = size def update_canvas_bg_pos(self, instance_label, pos: list) -> None: - if self.canvas_bg: - self.canvas_bg.pos = pos - - def _do_update_theme_color(self, *args): - if self._text_color_str: - if not self.disabled: - color = getattr(self.theme_cls, self._text_color_str) - else: - color = getattr(self.theme_cls, "disabled_hint_text_color") - - if self.theme_cls.theme_style_switch_animation: - Animation( - color=color, - d=self.theme_cls.theme_style_switch_animation_duration, - t="linear", - ).start(self) - else: - self.color = color + if self._canvas_bg: + self._canvas_bg.pos = pos -class MDIcon(MDFloatLayout, MDLabel): +class MDIcon(MDLabel): """ Icon class. - For more information, see in the :class:`~MDLabel` and - :class:`~kivymd.uix.floatlayout.MDFloatLayout` classes documentation. + For more information, see in the + :class:`~MDLabel` class documentation. """ - icon = StringProperty("android") + icon = StringProperty("blank") """ Label icon name. :attr:`icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `'android'`. - """ - - badge_icon = StringProperty() - """ - Label badge icon name. - - .. versionadded:: 1.0.0 - - :attr:`badge_icon` is an :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - badge_icon_color = ColorProperty([1, 1, 1, 1]) - """ - Badge icon color in (r, g, b, a) or string format. - - .. versionadded:: 1.0.0 - - :attr:`badge_icon_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - badge_bg_color = ColorProperty(None) - """ - Badge icon background color in (r, g, b, a) or string format. - - .. versionadded:: 1.0.0 - - :attr:`badge_bg_color` is an :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - badge_font_size = NumericProperty() - """ - Badge font size. - - .. versionadded:: 1.0.0 - - :attr:`badge_font_size` is an :class:`~kivy.properties.NumericProperty` - and defaults to `0`. + and defaults to `'blank'`. """ source = StringProperty(None, allownone=True) @@ -939,16 +888,33 @@ class MDIcon(MDFloatLayout, MDLabel): and defaults to `None`. """ - _size = ListProperty((0, 0)) + icon_color = ColorProperty(None) + """ + Icon color in (r, g, b, a) or string format. - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - Clock.schedule_once(self.adjust_size) + .. versionadded:: 2.0.0 - def adjust_size(self, *args) -> None: - from kivymd.uix.selectioncontrol import MDCheckbox + :attr:`icon_color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ - if not isinstance(self, MDCheckbox): - self.size_hint = (None, None) - self._size = self.texture_size[1], self.texture_size[1] - self.adaptive_size = True + icon_color_disabled = ColorProperty(None) + """ + The icon color in (r, g, b, a) or string format of the button when + the button is disabled. + + .. versionadded:: 2.0.0 + + :attr:`icon_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + # kivymd.uix.badge.badge.MDBadge object. + _badge = ObjectProperty() + + def add_widget(self, widget, index=0, canvas=None): + from kivymd.uix.badge import MDBadge + + if isinstance(widget, MDBadge): + self._badge = widget + return super().add_widget(widget) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__init__.py index a0e061c..096715a 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__init__.py @@ -1,33 +1,16 @@ # NOQA F401 from .list import ( - BaseListItem, - CheckboxLeftWidget, - IconLeftWidget, - IconLeftWidgetWithoutTouch, - IconRightWidget, - IconRightWidgetWithoutTouch, - ILeftBody, - ILeftBodyTouch, - ImageLeftWidget, - ImageLeftWidgetWithoutTouch, - ImageRightWidget, - ImageRightWidgetWithoutTouch, - IRightBody, - IRightBodyTouch, MDList, - OneLineAvatarIconListItem, - OneLineAvatarListItem, - OneLineIconListItem, - OneLineListItem, - OneLineRightIconListItem, - ThreeLineAvatarIconListItem, - ThreeLineAvatarListItem, - ThreeLineIconListItem, - ThreeLineListItem, - ThreeLineRightIconListItem, - TwoLineAvatarIconListItem, - TwoLineAvatarListItem, - TwoLineIconListItem, - TwoLineListItem, - TwoLineRightIconListItem, + MDListItem, + BaseListItem, + BaseListItemText, + BaseListItemIcon, + MDListItemLeadingIcon, + MDListItemTrailingIcon, + MDListItemHeadlineText, + MDListItemTertiaryText, + MDListItemLeadingAvatar, + MDListItemSupportingText, + MDListItemTrailingCheckbox, + MDListItemTrailingSupportingText, ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/__init__.cpython-311.pyc index 6f1b10c..3ed52d0 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/list.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/list.cpython-311.pyc index 84febf7..f95b637 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/list.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/__pycache__/list.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.kv index 467d1c8..2682a45 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.kv @@ -1,173 +1,153 @@ -#:import m_res kivymd.material_resources - - cols: 1 adaptive_height: True padding: 0, self._list_vertical_padding - - size_hint_y: None - - canvas: + + # Divider. + canvas.after: Color: rgba: ( \ - self.theme_cls.divider_color \ - if root.divider is not None \ - else (0, 0, 0, 0) \ - ) \ - if not root.divider_color \ - else \ - root.divider_color - - Line: - points: ( \ - root.x ,root.y, root.x + self.width, root.y) \ - if root.divider == "Full" else \ - (root.x + root._txt_left_pad, root.y, \ - root.x + self.width - root._txt_left_pad-root._txt_right_pad, \ - root.y \ - ) - Color: - rgba: root.bg_color if root.bg_color else (0, 0, 0, 0) - RoundedRectangle: - pos: self.pos - size: self.size - radius: root.radius + self.theme_cls.surfaceVariantColor \ + if not self.disabled else \ + self.theme_cls.onSurfaceColor \ + ) \ + if self.theme_divider_color == "Primary" else \ + self.divider_color + ) \ + + if self.divider else self.theme_cls.transparentColor + Line: + width: 1 + points: self.x ,self.y, self.x + self.width, self.y + + size_hint_y: None + spacing: "16dp" + padding: + "16dp", \ + "12dp" if len(text_container.children) == 3 else "8dp", \ + "24dp", \ + "12dp" if len(text_container.children) == 3 else "8dp" + # FIXME: The design of the material suggests specifying the + # background color of the disabled widget as the "onSurface" + # color when hovering the mouse cursor. But this color is very + # dark/light. So I chose the color "onSurfaceColor" color with 12 + # percent transparency. + md_bg_color: + self.theme_cls.surfaceColor \ + if self.theme_bg_color == "Primary" else \ + self.md_bg_color + height: + { \ + 0: "100dp", \ + 1: "56dp", \ + 2: "72dp", \ + 3: "88dp", \ + } \ + [len(text_container.children)] + on_disabled: + if leading_container.children: \ + leading_container.children[0].disabled = args[1] + BoxLayout: - id: _text_container - orientation: "vertical" - pos: root.pos - padding: - root._txt_left_pad, root._txt_top_pad, \ - root._txt_right_pad, root._txt_bot_pad + id: leading_container + size_hint_x: None + width: 0 - MDLabel: - id: _lbl_primary - text: root.text - font_style: root.font_style - theme_text_color: root.theme_text_color - text_color: root.text_color + AnchorLayout: + anchor_y: "center" + + BoxLayout: + id: text_container + orientation: "vertical" size_hint_y: None - height: self.texture_size[1] - markup: True - shorten_from: "right" - shorten: True - - MDLabel: - id: _lbl_secondary - text: "" if root._num_lines == 1 else root.secondary_text - font_style: root.secondary_font_style - theme_text_color: root.secondary_theme_text_color - text_color: root.secondary_text_color - size_hint_y: None - height: 0 if root._num_lines == 1 else self.texture_size[1] - shorten: True - shorten_from: "right" - markup: True - - MDLabel: - id: _lbl_tertiary - text: "" if root._num_lines == 1 else root.tertiary_text - font_style: root.tertiary_font_style - theme_text_color: root.tertiary_theme_text_color - text_color: root.tertiary_text_color - size_hint_y: None - height: 0 if root._num_lines == 1 else self.texture_size[1] - shorten: True - shorten_from: "right" - markup: True - - - + height: self.minimum_height + spacing: "2dp" + on_children: + if leading_container.children: \ + leading_container.children[0].pos_hint = {"top": 1} \ + if len(args[1]) == 3 else {"center_y": .5} BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height / 2 - self.height / 2 - size: dp(40), dp(40) + id: trailing_container + size_hint_x: None + width: 0 + on_children: + if text_container.children and self.children: \ + self.children[0].pos_hint = {"top": 1} \ + if len(text_container.children) == 3 else {"center_y": .5} - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(40), dp(40) + + size_hint: None, None + size: "24dp", "24dp" + text_color: + ( \ + self.theme_cls.onSurfaceVariantColor \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color \ + if self.icon_color else \ + self.theme_cls.transparentColor \ + ) \ + ) \ + if not self.disabled else self.disabled_color + disabled_color: + self.theme_cls.onSurfaceColor[:-1] + \ + [self.icon_button_standard_opacity_value_disabled_icon] \ + if not self.icon_color_disabled else self.icon_color_disabled - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height / 2 - self.height / 2 - size: dp(48), dp(48) + + adaptive_width: True + font_style: "Label" + role: "small" - - - BoxLayout: - id: _left_container - size_hint: None, None - x: root.x + dp(16) - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(48), dp(48) + + size_hint: None, None + size: "40dp", "40dp" + radius: self.height / 2 + # FIXME: The design of the material suggests specifying the + # background color of the disabled widget as the "onSurface" + # color when hovering the mouse cursor. But this color is very + # dark/light. So I chose the color "onSurfaceColor" color with 12 + # percent transparency. + md_bg_color: + self.theme_cls.primaryContainerColor \ + if not self.disabled else \ + self.theme_cls.onSurfaceColor[:-1] \ + + ( \ + [self._list_item.list_opacity_value_disabled_leading_avatar] \ + if self._list_item else [0] \ + ) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height / 2 - self.height / 2 - size: dp(48), dp(48) + + adaptive_height: True + markup: True + shorten_from: "right" + font_style: "Body" + role: "medium" + shorten: True + text_color: + self.theme_cls.onSurfaceVariantColor \ + if root.theme_text_color == "Primary" else \ + ( \ + root.text_color \ + if root.text_color else \ + self.theme_cls.onSurfaceVariantColor \ + ) - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height / 2 - self.height / 2 - size: dp(48), dp(48) - - - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height / 2 - self.height / 2 - size: dp(48), dp(48) - - - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height / 2 - self.height / 2 - size: dp(48), dp(48) - - - - - BoxLayout: - id: _right_container - size_hint: None, None - x: root.x + root.width - m_res.HORIZ_MARGINS - self.width - y: root.y + root.height - root._txt_top_pad - self.height - dp(5) - size: dp(48), dp(48) + + font_style: "Body" + role: "large" + bold: True + # FIXME: `RecursionError: maximum recursion depth exceeded while calling + # a Python object` when use `text_color` property. + -text_color: self.theme_cls.onSurfaceColor if root.theme_text_color == "Primary" else (root.text_color if root.text_color else self.theme_cls.onSurfaceColor) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.py index 035ca8a..290e858 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/list/list.py @@ -4,146 +4,51 @@ Components/List .. seealso:: - `Material Design spec, Lists `_ + `Material Design spec, Lists `_ .. rubric:: Lists are continuous, vertical indexes of text or images. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/lists.png :align: center -The class :class:`~MDList` in combination with a :class:`~BaseListItem` like -:class:`~OneLineListItem` will create a list that expands as items are added to -it, working nicely with `Kivy's` :class:`~kivy.uix.scrollview.ScrollView`. - -Due to the variety in sizes and controls in the `Material Design spec`, -this module suffers from a certain level of complexity to keep the widgets -compliant, flexible and performant. - -For this `KivyMD` provides list items that try to cover the most common usecases, -when those are insufficient, there's a base class called :class:`~BaseListItem` -which you can use to create your own list items. This documentation will only -cover the provided ones, for custom implementations please refer to this -module's source code. - -`KivyMD` provides the following list items classes for use: - -Text only ListItems -------------------- - -- OneLineListItem_ -- TwoLineListItem_ -- ThreeLineListItem_ - -ListItems with widget containers --------------------------------- - -These widgets will take other widgets that inherit from :class:`~ILeftBody`, -:class:`ILeftBodyTouch`, :class:`~IRightBody` or :class:`~IRightBodyTouch` and -put them in their corresponding container. - -As the name implies, :class:`~ILeftBody` and :class:`~IRightBody` will signal -that the widget goes into the left or right container, respectively. - -:class:`~ILeftBodyTouch` and :class:`~IRightBodyTouch` do the same thing, -except these widgets will also receive touch events that occur within their -surfaces. - -`KivyMD` provides base classes such as :class:`~ImageLeftWidget`, -:class:`~ImageRightWidget`, :class:`~IconRightWidget`, :class:`~IconLeftWidget`, -based on the above classes. - -.. rubric:: Allows the use of items with custom widgets on the left. - -- OneLineAvatarListItem_ -- TwoLineAvatarListItem_ -- ThreeLineAvatarListItem_ - -- OneLineIconListItem_ -- TwoLineIconListItem_ -- ThreeLineIconListItem_ - -.. rubric:: It allows the use of elements with custom widgets on the left - and the right. - -- OneLineAvatarIconListItem_ -- TwoLineAvatarIconListItem_ -- ThreeLineAvatarIconListItem_ - -- OneLineRightIconListItem_ -- TwoLineRightIconListItem_ -- ThreeLineRightIconListItem_ +- Use lists to help users find a specific item and act on it; +- Order list items in logical ways (like alphabetical or numerical); +- Three sizes: one-line, two-line, and three-line; +- Keep items short and easy to scan; +- Show icons, text, and actions in a consistent format; Usage ----- -.. tabs:: +.. code-block:: kv - .. tab:: Declarative KV style + MDListItem: - .. code-block:: python + MDListItemLeadingIcon: # MDListItemLeadingAvatar - from kivy.lang import Builder + MDListItemHeadlineText: - from kivymd.app import MDApp - from kivymd.uix.list import OneLineListItem + MDListItemSupportingText: - KV = ''' - MDScrollView: + MDListItemTertiaryText: - MDList: - id: container - ''' + MDListItemTrailingIcon: # MDListItemTrailingCheckbox +Anatomy +------- - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - def on_start(self): - for i in range(20): - self.root.ids.container.add_widget( - OneLineListItem(text=f"Single-line item {i}") - ) - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.list import OneLineListItem - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return ( - MDScrollView( - MDList( - id="container" - ) - ) - ) - - def on_start(self): - for i in range(20): - self.root.ids.container.add_widget( - OneLineListItem(text=f"Single-line item {i}") - ) - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/lists.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/lists-anatomy.png :align: center -Events of List --------------- +Example: +======== + +One line list item +------------------ .. tabs:: - .. tab:: Declarative KV style + .. tab:: Declarative KV styles .. code-block:: python @@ -152,824 +57,318 @@ Events of List from kivymd.app import MDApp KV = ''' - MDScrollView: + MDScreen: + md_bg_color: self.theme_cls.backgroundColor - MDList: + MDListItem: + pos_hint: {"center_x": .5, "center_y": .5} + size_hint_x: .8 - OneLineAvatarIconListItem: - on_release: print("Click!") - - IconLeftWidget: - icon: "github" - - OneLineAvatarIconListItem: - on_release: print("Click 2!") - - IconLeftWidget: - icon: "gitlab" + MDListItemHeadlineText: + text: "Headline" ''' class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" return Builder.load_string(KV) Example().run() - .. tab:: Declarative python style + .. tab:: Declarative Python styles .. code-block:: python + from kivymd.uix.list import MDListItem, MDListItemHeadlineText + from kivymd.uix.screen import MDScreen from kivymd.app import MDApp - from kivymd.uix.scrollview import MDScrollView - from kivymd.uix.list import MDList, OneLineAvatarIconListItem, IconLeftWidget class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" return ( - MDScrollView( - MDList( - OneLineAvatarIconListItem( - IconLeftWidget( - icon="github" - ), - on_release=lambda x: print("Click!") + MDScreen( + MDListItem( + MDListItemHeadlineText( + text="Headline", ), - OneLineAvatarIconListItem( - IconLeftWidget( - icon="gitlab" - ), - on_release=lambda x: print("Click 2!") - ), - ) + pos_hint={"center_x": .5, "center_y": .5}, + size_hint_x=0.8, + ), + md_bg_color=self.theme_cls.backgroundColor, ) ) Example().run() -.. OneLineListItem: -OneLineListItem ---------------- - -.. code-block:: kv - - OneLineListItem: - text: "Single-line item" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/OneLineListItem.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/headline-list.gif :align: center -.. TwoLineListItem: -TwoLineListItem ---------------- - -.. code-block:: kv - - TwoLineListItem: - text: "Two-line item" - secondary_text: "Secondary text here" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/TwoLineListItem.png - :align: center - -.. ThreeLineListItem: -ThreeLineListItem ------------------ - -.. code-block:: kv - - ThreeLineListItem: - text: "Three-line item" - secondary_text: "This is a multi-line label where you can" - tertiary_text: "fit more text than usual" - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/ThreeLineListItem.png - :align: center - -.. OneLineAvatarListItem: -OneLineAvatarListItem ---------------------- +Two line list item +------------------ .. tabs:: - .. tab:: Declarative KV style + .. tab:: Declarative KV styles .. code-block:: kv - OneLineAvatarListItem: - text: "Single-line item with avatar" + MDListItem: - ImageLeftWidget: - source: "kivymd/images/logo/kivymd-icon-256.png" + MDListItemHeadlineText: + text: "Headline" - .. tab:: Declarative python style + MDListItemSupportingText: + text: "Supporting text" + + .. tab:: Declarative Python styles .. code-block:: python - OneLineAvatarListItem( - ImageLeftWidget( - source="kivymd/images/logo/kivymd-icon-256.png" + MDListItem( + MDListItemHeadlineText( + text="Headline", + ), + MDListItemSupportingText( + text="Supporting text", ), - text="Single-line item with avatar", ) -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/OneLineAvatarListItem.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/headline-supporting-list.png :align: center -.. TwoLineAvatarListItem: -TwoLineAvatarListItem ---------------------- +Three line list item +-------------------- .. tabs:: - .. tab:: Declarative KV style + .. tab:: Declarative KV styles .. code-block:: kv - TwoLineAvatarListItem: - text: "Two-line item with avatar" - secondary_text: "Secondary text here" + MDListItem: - ImageLeftWidget: - source: "kivymd/images/logo/kivymd-icon-256.png" + MDListItemHeadlineText: + text: "Headline" - .. tab:: Declarative python style + MDListItemSupportingText: + text: "Supporting text" + + MDListItemTertiaryText: + text: "Tertiary text" + + .. tab:: Declarative Python styles .. code-block:: python - OneLineAvatarListItem( - ImageLeftWidget( - source="kivymd/images/logo/kivymd-icon-256.png" + MDListItem( + MDListItemHeadlineText( + text="Headline", + ), + MDListItemSupportingText( + text="Supporting text", + ), + MDListItemTertiaryText( + text="Tertiary text", ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", ) -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/TwoLineAvatarListItem.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/headline-supporting-tertiary-list.png :align: center -.. ThreeLineAvatarListItem: -ThreeLineAvatarListItem ------------------------ - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - ThreeLineAvatarListItem: - text: "Three-line item with avatar" - secondary_text: "Secondary text here" - tertiary_text: "fit more text than usual" - - ImageLeftWidget: - source: "kivymd/images/logo/kivymd-icon-256.png" - - .. tab:: Declarative python style - - .. code-block:: python - - OneLineAvatarListItem( - ImageLeftWidget( - source="kivymd/images/logo/kivymd-icon-256.png" - ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", - tertiary_text: "fit more text than usual" - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/ThreeLineAvatarListItem.png - :align: center - -.. OneLineRightIconListItem: -OneLineRightIconListItem ------------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - OneLineRightIconListItem: - text: "Single-line item with avatar" - - ImageRightWidget: - source: "kivymd/images/logo/kivymd-icon-256.png" - - .. tab:: Declarative python style - - .. code-block:: python - - OneLineRightIconListItem( - ImageRightWidget( - source="kivymd/images/logo/kivymd-icon-256.png" - ), - text="Single-line item with avatar", - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/OneLineRightIconListItem.png - :align: center - -.. TwoLineRightIconListItem: -TwoLineRightIconListItem ------------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - TwoLineRightIconListItem: - text: "Single-line item with avatar" - secondary_text: "Secondary text here" - - ImageRightWidget: - source: "kivymd/images/logo/kivymd-icon-256.png" - - .. tab:: Declarative python style - - .. code-block:: python - - TwoLineRightIconListItem( - ImageRightWidget( - source="kivymd/images/logo/kivymd-icon-256.png" - ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/TwoLineRightIconListItem.png - :align: center - -.. ThreeLineRightIconListItem: -ThreeLineRightIconListItem --------------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - ThreeLineRightIconListItem: - text: "Single-line item with avatar" - secondary_text: "Secondary text here" - tertiary_text: "fit more text than usual" - - ImageRightWidget: - source: "kivymd/images/logo/kivymd-icon-256.png" - - .. tab:: Declarative python style - - .. code-block:: python - - ThreeLineRightIconListItem( - ImageRightWidget( - source="kivymd/images/logo/kivymd-icon-256.png" - ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", - tertiary_text: "fit more text than usual", - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/ThreeLineRightIconListItem.png - :align: center - -.. OneLineIconListItem: -OneLineIconListItem -------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - OneLineIconListItem: - text: "Single-line item with avatar" - - IconLeftWidget: - icon: "language-python" - - .. tab:: Declarative python style - - .. code-block:: python - - OneLineIconListItem( - IconLeftWidget( - icon="language-python" - ), - text="Single-line item with avatar" - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/OneLineIconListItem.png - :align: center - -.. TwoLineIconListItem: -TwoLineIconListItem -------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - TwoLineIconListItem: - text: "Two-line item with avatar" - secondary_text: "Secondary text here" - - IconLeftWidget: - icon: "language-python" - - .. tab:: Declarative python style - - .. code-block:: python - - TwoLineIconListItem( - IconLeftWidget( - icon="language-python" - ), - text="Single-line item with avatar", - secondary_text: "Secondary text here" - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/TwoLineIconListItem.png - :align: center - -.. ThreeLineIconListItem: -ThreeLineIconListItem ---------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - ThreeLineIconListItem: - text: "Three-line item with avatar" - secondary_text: "Secondary text here" - tertiary_text: "fit more text than usual" - - IconLeftWidget: - icon: "language-python" - - .. tab:: Declarative python style - - .. code-block:: python - - ThreeLineIconListItem( - IconLeftWidget( - icon="language-python" - ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", - tertiary_text: "fit more text than usual", - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/ThreeLineIconListItem.png - :align: center - -.. OneLineAvatarIconListItem: -OneLineAvatarIconListItem -------------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - OneLineAvatarIconListItem: - text: "One-line item with avatar" - - IconLeftWidget: - icon: "plus" - - IconRightWidget: - icon: "minus" - - .. tab:: Declarative python style - - .. code-block:: python - - OneLineAvatarIconListItem( - IconLeftWidget( - icon="plus" - ), - IconRightWidget( - icon="minus" - ), - text="Single-line item with avatar", - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/OneLineAvatarIconListItem.png - :align: center - -.. TwoLineAvatarIconListItem: -TwoLineAvatarIconListItem -------------------------- - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: kv - - TwoLineAvatarIconListItem: - text: "Two-line item with avatar" - secondary_text: "Secondary text here" - - IconLeftWidget: - icon: "plus" - - IconRightWidget: - icon: "minus" - - .. tab:: Declarative python style - - .. code-block:: python - - TwoLineAvatarIconListItem( - IconLeftWidget( - icon="plus" - ), - IconRightWidget( - icon="minus" - ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", - ) - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/TwoLineAvatarIconListItem.png - :align: center - -.. ThreeLineAvatarIconListItem: -ThreeLineAvatarIconListItem +List item with leading icon --------------------------- .. tabs:: - .. tab:: Declarative KV style + .. tab:: Declarative KV styles .. code-block:: kv - ThreeLineAvatarIconListItem: - text: "Three-line item with avatar" - secondary_text: "Secondary text here" - tertiary_text: "fit more text than usual" + MDListItem: - IconLeftWidget: - icon: "plus" + MDListItemLeadingIcon: + icon: "account" - IconRightWidget: - icon: "minus" + MDListItemHeadlineText: + text: "Headline" - .. tab:: Declarative python style + MDListItemSupportingText: + text: "Supporting text" + + MDListItemTertiaryText: + text: "Tertiary text" + + .. tab:: Declarative Python styles .. code-block:: python - ThreeLineAvatarIconListItem( - IconLeftWidget( - icon="plus" + MDListItem( + MDListItemLeadingIcon( + icon="account", ), - IconRightWidget( - icon="minus" + MDListItemHeadlineText( + text="Headline", + ), + MDListItemSupportingText( + text="Supporting text", + ), + MDListItemTertiaryText( + text="Tertiary text", ), - text="Single-line item with avatar", - secondary_text: "Secondary text here", - tertiary_text: "fit more text than usual", ) -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/ThreeLineAvatarIconListItem.png +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/headline-supporting-tertiary-leading-icon-list.png :align: center -Custom list item ----------------- +List item with trailing icon +---------------------------- .. tabs:: - .. tab:: Declarative KV style - - .. code-block:: python - - from kivy.lang import Builder - from kivy.properties import StringProperty - - from kivymd.app import MDApp - from kivymd.uix.list import IRightBodyTouch, OneLineAvatarIconListItem - from kivymd.uix.selectioncontrol import MDCheckbox - from kivymd.icon_definitions import md_icons - - - KV = ''' - : - - IconLeftWidget: - icon: root.icon - - RightCheckbox: - - - MDScrollView: - - MDList: - id: scroll - ''' - - - class ListItemWithCheckbox(OneLineAvatarIconListItem): - '''Custom list item.''' - - icon = StringProperty("android") - - - class RightCheckbox(IRightBodyTouch, MDCheckbox): - '''Custom right container.''' - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - def on_start(self): - icons = list(md_icons.keys()) - for i in range(30): - self.root.ids.scroll.add_widget( - ListItemWithCheckbox(text=f"Item {i}", icon=icons[i]) - ) - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.list import IRightBodyTouch, OneLineAvatarIconListItem - from kivymd.uix.selectioncontrol import MDCheckbox - from kivymd.uix.scrollview import MDScrollView - from kivymd.uix.list import MDList - from kivymd.icon_definitions import md_icons - - - class RightCheckbox(IRightBodyTouch, MDCheckbox): - '''Custom right container.''' - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return ( - MDScrollView( - MDList( - id="scroll" - ) - ) - ) - - def on_start(self): - icons = list(md_icons.keys()) - for i in range(30): - self.root.ids.scroll.add_widget( - OneLineAvatarIconListItem( - IconLeftWidget( - icon=icons[i] - ), - RightCheckbox(), - text=f"Item {i}", - ) - ) - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/custom-list-item.png - :align: center - -.. tabs:: - - .. tab:: Declarative KV style - - .. code-block:: python - - from kivy.lang import Builder - - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.list import IRightBodyTouch - - KV = ''' - OneLineAvatarIconListItem: - text: "One-line item with avatar" - on_size: - self.ids._right_container.width = container.width - self.ids._right_container.x = container.width - - IconLeftWidget: - icon: "cog" - - YourContainer: - id: container - - MDIconButton: - icon: "minus" - - MDIconButton: - icon: "plus" - ''' - - - class YourContainer(IRightBodyTouch, MDBoxLayout): - adaptive_width = True - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - - Example().run() - - .. tab:: Declarative python style - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.list import IRightBodyTouch - from kivymd.uix.button import MDIconButton - from kivymd.uix.list import OneLineAvatarIconListItem, IconLeftWidget - - - class YourContainer(IRightBodyTouch, MDBoxLayout): - adaptive_width = True - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return ( - OneLineAvatarIconListItem( - IconLeftWidget( - icon="cog" - ), - YourContainer( - MDIconButton( - icon="minus" - ), - MDIconButton( - icon="plus" - ), - id="container" - ), - text="One-line item with avatar" - ) - ) - - def on_start(self): - container = self.root.ids.container - self.root.ids._right_container.width = container.width - container.x = container.width - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/custom-list-right-container.png - :align: center - -Behavior --------- - -When using the `AvatarListItem` and `IconListItem` classes, when an icon is clicked, -the event of this icon is triggered: - -.. tabs:: - - .. tab:: Declarative KV style + .. tab:: Declarative KV styles .. code-block:: kv - OneLineIconListItem: - text: "Single-line item with icon" + MDListItem: - IconLeftWidget: - icon: "language-python" + MDListItemLeadingIcon: + icon: "account" - .. tab:: Declarative python style + MDListItemHeadlineText: + text: "Headline" + + MDListItemSupportingText: + text: "Supporting text" + + MDListItemTertiaryText: + text: "Tertiary text" + + MDListItemTrailingIcon: + icon: "trash-can-outline" + + .. tab:: Declarative Python styles .. code-block:: python - OneLineIconListItem( - IconLeftWidget( - icon="language-python" + MDListItem( + MDListItemLeadingIcon( + icon="account", + ), + MDListItemHeadlineText( + text="Headline", + ), + MDListItemSupportingText( + text="Supporting text", + ), + MDListItemTertiaryText( + text="Tertiary text", + ), + MDListItemTrailingIcon( + icon="trash-can-outline", ), - text="Single-line item with avatar", ) -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/list-icon-trigger.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/headline-supporting-tertiary-leading-trailing-icon-list.png :align: center -You can disable the icon event using the `WithoutTouch` classes: +List item with trailing check +----------------------------- .. tabs:: - .. tab:: Declarative KV style + .. tab:: Declarative KV styles .. code-block:: kv - OneLineIconListItem: - text: "Single-line item with icon" + MDListItem: - IconLeftWidgetWithoutTouch: - icon: "language-python" + MDListItemLeadingIcon: + icon: "account" - .. tab:: Declarative python style + MDListItemHeadlineText: + text: "Headline" + + MDListItemSupportingText: + text: "Supporting text" + + MDListItemTertiaryText: + text: "Tertiary text" + + MDListItemTrailingCheckbox: + + .. tab:: Declarative Python styles .. code-block:: python - OneLineIconListItem( - IconLeftWidgetWithoutTouch( - icon="language-python" + MDListItem( + MDListItemLeadingIcon( + icon="account", + ), + MDListItemHeadlineText( + text="Headline", + ), + MDListItemSupportingText( + text="Supporting text", + ), + MDListItemTertiaryText( + text="Tertiary text", + ), + MDListItemTrailingCheckbox( ), - text="Single-line item with avatar", ) -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/list-icon-without-trigger.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/headline-supporting-tertiary-leading-trailing-check-list.png :align: center """ +from __future__ import annotations + __all__ = ( + "BaseListItemText", "BaseListItem", + "BaseListItemIcon", "MDList", - "ILeftBodyTouch", - "IRightBodyTouch", - "OneLineListItem", - "TwoLineListItem", - "ThreeLineListItem", - "OneLineAvatarListItem", - "TwoLineAvatarListItem", - "ThreeLineAvatarListItem", - "OneLineIconListItem", - "TwoLineIconListItem", - "ThreeLineIconListItem", - "OneLineRightIconListItem", - "TwoLineRightIconListItem", - "ThreeLineRightIconListItem", - "OneLineAvatarIconListItem", - "TwoLineAvatarIconListItem", - "ThreeLineAvatarIconListItem", - "ImageLeftWidget", - "ImageRightWidget", - "IconRightWidget", - "IconLeftWidget", - "CheckboxLeftWidget", - "IconLeftWidgetWithoutTouch", - "IconRightWidgetWithoutTouch", - "ImageRightWidgetWithoutTouch", - "ImageLeftWidgetWithoutTouch", + "MDListItem", + "MDListItemHeadlineText", + "MDListItemSupportingText", + "MDListItemTrailingSupportingText", + "MDListItemLeadingIcon", + "MDListItemTrailingIcon", + "MDListItemTrailingCheckbox", + "MDListItemLeadingAvatar", + "MDListItemTertiaryText", ) import os +from kivy import Logger +from kivy.clock import Clock from kivy.lang import Builder -from kivy.metrics import dp from kivy.properties import ( + NumericProperty, + ObjectProperty, BooleanProperty, ColorProperty, - ListProperty, - NumericProperty, - OptionProperty, - StringProperty, - VariableListProperty, ) from kivy.uix.behaviors import ButtonBehavior -from kivy.uix.floatlayout import FloatLayout +from kivy.uix.boxlayout import BoxLayout -import kivymd.material_resources as m_res +from kivymd.uix.selectioncontrol import MDCheckbox from kivymd import uix_path from kivymd.theming import ThemableBehavior from kivymd.uix.behaviors import ( CircularRippleBehavior, DeclarativeBehavior, RectangularRippleBehavior, + BackgroundColorBehavior, ) -from kivymd.uix.button import MDIconButton +from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior from kivymd.uix.fitimage import FitImage from kivymd.uix.gridlayout import MDGridLayout -from kivymd.uix.selectioncontrol import MDCheckbox +from kivymd.uix.label import MDLabel, MDIcon with open( os.path.join(uix_path, "list", "list.kv"), encoding="utf-8" @@ -979,14 +378,14 @@ with open( class MDList(MDGridLayout): """ - ListItem container. Best used in conjunction with a - :class:`kivy.uix.ScrollView`. + ListItem container. + Best used in conjunction with a :class:`kivy.uix.ScrollView`. When adding (or removing) a widget, it will resize itself to fit its children, plus top and bottom paddings as described by the `MD` spec. For more information, see in the - :class:`~kivymd.uix.gridlayout.MDGridLayout` classes documentation. + :class:`~kivymd.uix.gridlayout.MDGridLayout` class documentation. """ _list_vertical_padding = NumericProperty("8dp") @@ -998,638 +397,230 @@ class MDList(MDGridLayout): class BaseListItem( DeclarativeBehavior, - ThemableBehavior, + BackgroundColorBehavior, RectangularRippleBehavior, ButtonBehavior, - FloatLayout, + ThemableBehavior, + StateLayerBehavior, ): """ - Base class to all ListItems. Not supposed to be instantiated on its own. + Base class for list items. For more information, see in the - :class:`~kivymd.uix.behaviors.DeclarativeBehavior` and - :class:`~kivymd.theming.ThemableBehavior` and - :class:`~kivymd.uix.behaviors.RectangularRippleBehavior` and + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~kivy.uix.floatlayout.FloatLayout` classes documentation. + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.behaviors.state_layer_behavior.StateLayerBehavior` + classes documentation. """ - text = StringProperty() + divider = BooleanProperty(False) """ - Text shown in the first line. + Should I use divider for a list item. - :attr:`text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - text_color = ColorProperty(None) - """ - Text color in (r, g, b, a) or string format used - if :attr:`~theme_text_color` is set to `'Custom'`. - - :attr:`text_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - font_style = StringProperty("Subtitle1") - """ - Text font style. - See `font-definitions `_ - for more information. - - :attr:`font_style` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Subtitle1'`. - """ - - theme_text_color = StringProperty("Primary", allownone=True) - """ - The name of the color scheme for for the primary text. - - :attr:`theme_text_color` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Primary'`. - """ - - secondary_text = StringProperty() - """ - Text shown in the second line. - - :attr:`secondary_text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - tertiary_text = StringProperty() - """ - The text is displayed on the third line. - - :attr:`tertiary_text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - secondary_text_color = ColorProperty(None) - """ - Text color in (r, g, b, a) or string format used for secondary text - if :attr:`~secondary_theme_text_color` is set to `'Custom'`. - - :attr:`secondary_text_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - tertiary_text_color = ColorProperty(None) - """ - Text color in (r, g, b, a) or string format used for tertiary text - if :attr:`~tertiary_theme_text_color` is set to 'Custom'. - - :attr:`tertiary_text_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - secondary_theme_text_color = StringProperty("Secondary", allownone=True) - """ - The name of the color scheme for for the secondary text. - - :attr:`secondary_theme_text_color` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Secondary'`. - """ - - tertiary_theme_text_color = StringProperty("Secondary", allownone=True) - """ - The name of the color scheme for for the tertiary text. - - :attr:`tertiary_theme_text_color` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Secondary'`. - """ - - secondary_font_style = StringProperty("Body1") - """ - Font style for secondary line. - See `font-definitions `_ - for more information. - - :attr:`secondary_font_style` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Body1'`. - """ - - tertiary_font_style = StringProperty("Body1") - """ - Font style for tertiary line. - See `font-definitions `_ - for more information. - - :attr:`tertiary_font_style` is a :class:`~kivy.properties.StringProperty` - and defaults to `'Body1'`. - """ - - divider = OptionProperty( - "Full", options=["Full", "Inset", None], allownone=True - ) - """ - Divider mode. Available options are: `'Full'`, `'Inset'` - and default to `'Full'`. - - :attr:`divider` is a :class:`~kivy.properties.OptionProperty` - and defaults to `'Full'`. + :attr:`divider` is an :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. """ divider_color = ColorProperty(None) """ - Divider color in (r, g, b, a) or string format. - - .. versionadded:: 1.0.0 + The divider color in (r, g, b, a) or string format. :attr:`divider_color` is a :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ - bg_color = ColorProperty(None) + md_bg_color_disabled = ColorProperty(None) """ - Background color for list item in (r, g, b, a) or string format. + The background color in (r, g, b, a) or string format of the list item when + the list item is disabled. - :attr:`bg_color` is a :class:`~kivy.properties.ColorProperty` + :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ - radius = VariableListProperty([0], length=4) + +class BaseListItemText(MDLabel): """ - Canvas radius. + Base class for text labels of a list item. - .. code-block:: python - - # Top left corner slice. - MDBoxLayout: - md_bg_color: app.theme_cls.primary_color - radius: [25, 0, 0, 0] - - :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` - and defaults to `[0, 0, 0, 0]`. + For more information, see in the :class:`~kivymd.uix.label.label.MDLabel` + class documentation. """ - _txt_left_pad = NumericProperty("16dp") - _txt_top_pad = NumericProperty() - _txt_bot_pad = NumericProperty() - _txt_right_pad = NumericProperty(m_res.HORIZ_MARGINS) - _num_lines = 3 - _no_ripple_effect = BooleanProperty(False) - _touchable_widgets = ListProperty() - def on_touch_down(self, touch): - if self.propagate_touch_to_touchable_widgets(touch, "down"): - return - super().on_touch_down(touch) +class BaseListItemIcon(MDIcon): + """ + Base class for leading/trailing icon of list item. - def on_touch_move(self, touch, *args): - if self.propagate_touch_to_touchable_widgets(touch, "move", *args): - return - super().on_touch_move(touch, *args) + For more information, see in the :class:`~kivymd.uix.label.label.MDIcon` + class documentation. + """ - def on_touch_up(self, touch): - if self.propagate_touch_to_touchable_widgets(touch, "up"): - return - super().on_touch_up(touch) + icon_color = ColorProperty(None) + """ + Icon color in (r, g, b, a) or string format. - def propagate_touch_to_touchable_widgets(self, touch, touch_event, *args): - triggered = False - for i in self._touchable_widgets: - if i.collide_point(touch.x, touch.y): - triggered = True - if touch_event == "down": - i.on_touch_down(touch) - elif touch_event == "move": - i.on_touch_move(touch, *args) - elif touch_event == "up": - i.on_touch_up(touch) - return triggered + :attr:`icon_color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ - def add_widget(self, widget): - if issubclass(widget.__class__, ILeftBody): - self.ids._left_container.add_widget(widget) - elif issubclass(widget.__class__, ILeftBodyTouch): - self.ids._left_container.add_widget(widget) - self._touchable_widgets.append(widget) - elif issubclass(widget.__class__, IRightBody): - self.ids._right_container.add_widget(widget) - elif issubclass(widget.__class__, IRightBodyTouch): - self.ids._right_container.add_widget(widget) - self._touchable_widgets.append(widget) + icon_color_disabled = ColorProperty(None) + """ + The icon color in (r, g, b, a) or string format of the list item when + the list item is disabled. + + :attr:`icon_color_disabled` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + +class MDListItemHeadlineText(BaseListItemText): + """ + Implements a class for headline text of list item. + + For more information, see in the :class:`~BaseListItemText` + class documentation. + """ + + +class MDListItemSupportingText(BaseListItemText): + """ + Implements a class for secondary text of list item. + + For more information, see in the :class:`~BaseListItemText` + class documentation. + """ + + +class MDListItemTertiaryText(BaseListItemText): + """ + Implements a class for tertiary text of list item. + + For more information, see in the :class:`~BaseListItemText` + class documentation. + """ + + +class MDListItemTrailingSupportingText(BaseListItemText): + """ + Implements a class for trailing text of list item. + + For more information, see in the :class:`~BaseListItemText` + class documentation. + """ + + +class MDListItemLeadingIcon(BaseListItemIcon): + """ + Implements a class for leading icon class. + + For more information, see in the :class:`~BaseListItemIcon` + class documentation. + """ + + +class MDListItemLeadingAvatar( + ThemableBehavior, CircularRippleBehavior, ButtonBehavior, FitImage +): + """ + Implements a class for leading avatar class. + + For more information, see in the + :class:`~kivymd.theming.ThemableBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and + :class:`~kivy.uix.behaviors.ButtonBehavior` and + :class:`~kivymd.uix.fitimage.fitimage.FitImage` + classes documentation. + """ + + _list_item = ObjectProperty() + + +class MDListItemTrailingIcon(BaseListItemIcon): + """ + Implements a class for trailing icon class. + + For more information, see in the :class:`~BaseListItemIcon` + class documentation. + """ + + +class MDListItemTrailingCheckbox(MDCheckbox): + """ + Implements a class for trailing checkbox class. + + For more information, see in the + :class:`~kivymd.uix.selectioncontrol.selectioncontrol.MDCheckbox` + class documentation. + """ + + +class MDListItem(BaseListItem, BoxLayout): + """ + Implements a list item. + + For more information, see in the + :class:`~BaseListItem` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. + """ + + def add_widget(self, widget, *args, **kwargs): + if isinstance( + widget, + ( + MDListItemHeadlineText, + MDListItemSupportingText, + MDListItemTertiaryText, + ), + ): + if len(self.ids.text_container.children) < 3: + self.ids.text_container.add_widget(widget) + elif len(self.ids.text_container.children) > 3: + self._set_warnings(widget) + elif isinstance( + widget, (MDListItemLeadingIcon, MDListItemLeadingAvatar) + ): + if not self.ids.leading_container.children: + widget._list_item = self + self.ids.leading_container.add_widget(widget) + Clock.schedule_once( + lambda x: self._set_with_container( + self.ids.leading_container, widget + ) + ) + else: + self._set_warnings(widget) + elif isinstance( + widget, + ( + MDListItemTrailingIcon, + MDListItemTrailingCheckbox, + MDListItemTrailingSupportingText, + ), + ): + if not self.ids.trailing_container.children: + self.ids.trailing_container.add_widget(widget) + Clock.schedule_once( + lambda x: self._set_with_container( + self.ids.trailing_container, widget + ) + ) + else: + self._set_warnings(widget) else: return super().add_widget(widget) - def remove_widget(self, widget): - super().remove_widget(widget) - if widget in self._touchable_widgets: - self._touchable_widgets.remove(widget) - - -class ILeftBody: - """ - Pseudo-interface for widgets that go in the left container for - ListItems that support it. - - Implements nothing and requires no implementation, for annotation only. - """ - - -class ILeftBodyTouch: - """ - Same as :class:`~ILeftBody`, but allows the widget to receive touch - events instead of triggering the ListItem's ripple effect. - """ - - -class IRightBody: - """ - Pseudo-interface for widgets that go in the right container for - ListItems that support it. - - Implements nothing and requires no implementation, for annotation only. - """ - - -class IRightBodyTouch: - """ - Same as :class:`~IRightBody`, but allows the widget to receive touch - events instead of triggering the ``ListItem``'s ripple effect - """ - - -class OneLineListItem(BaseListItem): - """ - A one line list item. - - For more information, see in the :class:`~BaseListItem` - classes documentation. - """ - - _txt_top_pad = NumericProperty("16dp") - _txt_bot_pad = NumericProperty("15dp") - _height = NumericProperty() - _num_lines = 1 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.height = dp(48) if not self._height else self._height - - -class TwoLineListItem(BaseListItem): - """ - A two line list item. - - For more information, see in the :class:`~BaseListItem` - classes documentation. - """ - - _txt_top_pad = NumericProperty("20dp") - _txt_bot_pad = NumericProperty("15dp") - _height = NumericProperty() - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.height = dp(72) if not self._height else self._height - - -class ThreeLineListItem(BaseListItem): - """ - A three line list item. - - For more information, see in the :class:`~BaseListItem` - classes documentation. - """ - - _txt_top_pad = NumericProperty("16dp") - _txt_bot_pad = NumericProperty("15dp") - _height = NumericProperty() - _num_lines = 3 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.height = dp(88) if not self._height else self._height - - -class OneLineAvatarListItem(BaseListItem): - """ - A one line list item with left image. - - For more information, see in the :class:`~BaseListItem` - classes documentation. - """ - - _txt_left_pad = NumericProperty("72dp") - _txt_top_pad = NumericProperty("20dp") - _txt_bot_pad = NumericProperty("19dp") - _height = NumericProperty() - _num_lines = 1 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.height = dp(56) if not self._height else self._height - - -class TwoLineAvatarListItem(OneLineAvatarListItem): - """ - A two line list item with left image. - - For more information, see in the :class:`~OneLineAvatarListItem` - classes documentation. - """ - - _txt_top_pad = NumericProperty("20dp") - _txt_bot_pad = NumericProperty("15dp") - _height = NumericProperty() - _num_lines = 2 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.height = dp(72) if not self._height else self._height - - -class ThreeLineAvatarListItem(ThreeLineListItem): - """ - A three line list item with left image. - - For more information, see in the :class:`~ThreeLineListItem` - classes documentation. - """ - - _txt_left_pad = NumericProperty("72dp") - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - -class OneLineIconListItem(OneLineListItem): - """ - A one line list item with left icon. - - For more information, see in the :class:`~OneLineListItem` - classes documentation. - """ - - _txt_left_pad = NumericProperty("72dp") - - -class TwoLineIconListItem(OneLineIconListItem): - """ - A two line list item with left icon. - - For more information, see in the :class:`~OneLineIconListItem` - classes documentation. - """ - - _txt_top_pad = NumericProperty("20dp") - _txt_bot_pad = NumericProperty("15dp") - _height = NumericProperty() - _num_lines = 2 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.height = dp(72) if not self._height else self._height - - -class ThreeLineIconListItem(ThreeLineListItem): - """ - A three line list item with left icon. - - For more information, see in the :class:`~ThreeLineListItem` - classes documentation. - """ - - _txt_left_pad = NumericProperty("72dp") - - -class OneLineRightIconListItem(OneLineListItem): - """ - A one line list item with right icon/image. - - For more information, see in the :class:`~OneLineListItem` - classes documentation. - """ - - _txt_right_pad = NumericProperty("40dp") - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._txt_right_pad = dp(40) + m_res.HORIZ_MARGINS - - -class TwoLineRightIconListItem(OneLineRightIconListItem): - """ - A two line list item with right icon/image. - - For more information, see in the :class:`~OneLineRightIconListItem` - classes documentation. - """ - - _txt_top_pad = NumericProperty("20dp") - _txt_bot_pad = NumericProperty("15dp") - _height = NumericProperty() - _num_lines = 2 - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.height = dp(72) if not self._height else self._height - - -class ThreeLineRightIconListItem(ThreeLineListItem): - """ - A three line list item with right icon/image. - - For more information, see in the :class:`~ThreeLineRightIconListItem` - classes documentation. - """ - - _txt_right_pad = NumericProperty("40dp") - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self._txt_right_pad = dp(40) + m_res.HORIZ_MARGINS - - -class OneLineAvatarIconListItem(OneLineAvatarListItem): - """ - A one line list item with left/right icon/image/widget. - - For more information, see in the :class:`~OneLineAvatarListItem` - classes documentation. - """ - - _txt_right_pad = NumericProperty("40dp") - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._txt_right_pad = dp(40) + m_res.HORIZ_MARGINS - - -class TwoLineAvatarIconListItem(TwoLineAvatarListItem): - """ - A two line list item with left/right icon/image/widget. - - For more information, see in the :class:`~TwoLineAvatarListItem` - classes documentation. - """ - - _txt_right_pad = NumericProperty("40dp") - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._txt_right_pad = dp(40) + m_res.HORIZ_MARGINS - - -class ThreeLineAvatarIconListItem(ThreeLineAvatarListItem): - """ - A three line list item with left/right icon/image/widget. - - For more information, see in the :class:`~ThreeLineAvatarListItem` - classes documentation. - """ - - _txt_right_pad = NumericProperty("40dp") - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._txt_right_pad = dp(40) + m_res.HORIZ_MARGINS - - -class TouchBehavior: - def on_release(self): - if issubclass(self.parent.parent.__class__, BaseListItem): - self.parent.parent.dispatch("on_release") - - -class ImageLeftWidget( - CircularRippleBehavior, ButtonBehavior, ILeftBodyTouch, FitImage -): - """ - The widget implements the left image for use in ListItem classes. - - For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~ILeftBodyTouch` and - :class:`~kivymd.uix.fitimage.FitImage` classes documentation. - """ - - -class ImageLeftWidgetWithoutTouch( - CircularRippleBehavior, TouchBehavior, ButtonBehavior, ILeftBody, FitImage -): - """ - Disables the image event. - The widget implements the left image for use in `ListItem` classes. - - For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~TouchBehavior` and - :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~ILeftBody` and - :class:`~kivymd.uix.fitimage.FitImage` classes documentation. - - .. versionadded:: 1.0.0 - """ - - _no_ripple_effect = True - - -class ImageRightWidget( - CircularRippleBehavior, ButtonBehavior, IRightBodyTouch, FitImage -): - """ - The widget implements the right image for use in ListItem classes. - - For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~IRightBodyTouch` and - :class:`~kivymd.uix.fitimage.FitImage` classes documentation. - """ - - -class ImageRightWidgetWithoutTouch( - CircularRippleBehavior, TouchBehavior, ButtonBehavior, IRightBody, FitImage -): - """ - Disables the image event. - The widget implements the right image for use in `ListItem` classes. - - For more information, see in the - :class:`~kivymd.uix.behaviors.CircularRippleBehavior` and - :class:`~TouchBehavior` and - :class:`~kivy.uix.behaviors.ButtonBehavior` and - :class:`~IRightBody` and - :class:`~kivymd.uix.fitimage.FitImage` classes documentation. - - .. versionadded:: 1.0.0 - """ - - _no_ripple_effect = True - - -class IconRightWidget(IRightBodyTouch, MDIconButton): - """ - The widget implements the right icon for use in ListItem classes. - - For more information, see in the - :class:`~IRightBodyTouch` and - :class:`~kivymd.uix.button.MDIconButton` - classes documentation. - """ - - pos_hint = {"center_y": 0.5} - - -class IconRightWidgetWithoutTouch(TouchBehavior, IRightBody, MDIconButton): - """ - Disables the icon event. - The widget implements the right icon for use in ListItem classes. - - For more information, see in the - :class:`~TouchBehavior` and - :class:`~IRightBody` and - :class:`~kivymd.uix.button.MDIconButton` - classes documentation. - - .. versionadded:: 1.0.0 - """ - - pos_hint = {"center_y": 0.5} - _no_ripple_effect = True - - -class IconLeftWidget(ILeftBodyTouch, MDIconButton): - """ - The widget implements the left icon for use in ListItem classes. - - For more information, see in the - :class:`~ILeftBodyTouch` and - :class:`~kivymd.uix.button.MDIconButton` - classes documentation. - """ - - pos_hint = {"center_y": 0.5} - - -class IconLeftWidgetWithoutTouch(TouchBehavior, ILeftBody, MDIconButton): - """ - Disables the icon event. - The widget implements the left icon for use in ListItem classes. - - For more information, see in the - :class:`~TouchBehavior` and - :class:`~ILeftBody` and - :class:`~kivymd.uix.button.MDIconButton` - classes documentation. - - .. versionadded:: 1.0.0 - """ - - pos_hint = {"center_y": 0.5} - _no_ripple_effect = True - - -class CheckboxLeftWidget(ILeftBodyTouch, MDCheckbox): - """ - The widget implements the left checkbox element for use in ListItem classes. - - For more information, see in the - :class:`~ILeftBodyTouch` and - :class:`~kivymd.uix.selectioncontrol.MDCheckbox` - classes documentation. - """ + def _set_warnings(self, widget): + Logger.warning( + f"KivyMD: " + f"Do not use more than one <{widget.__class__.__name__}> " + f"widget. This is contrary to the material design rules " + f"of version 3" + ) + + def _set_with_container(self, container, widget): + container.width = widget.width diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc index 9b80d34..5ea72d7 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/menu.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/menu.cpython-311.pyc index db07c88..b96e3aa 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/menu.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/__pycache__/menu.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.kv index a53c071..8a52ba4 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.kv @@ -22,7 +22,6 @@ MDLabel: text: root.text pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" size_hint_x: None @@ -34,25 +33,26 @@ + container.padding[2] \ + container.spacing \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color MDTrailingTextContainer: id: trailing_container text: root.trailing_text adaptive_width: True - theme_text_color: "Custom" if root.trailing_text_color else "Primary" + theme_text_color: "Custom" text_color: - root.trailing_text_color \ - if root.trailing_text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.trailing_text_color else \ + root.trailing_text_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -74,16 +74,15 @@ size_hint: None, None size: "48dp", "48dp" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.leading_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.leading_icon_color \ - if root.leading_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.leading_icon_color else \ + root.leading_icon_color MDLabel: text: root.text pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" size_hint_x: None @@ -97,10 +96,11 @@ + container.spacing \ + dp(18) \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color Widget: @@ -108,16 +108,16 @@ id: trailing_container text: root.trailing_text adaptive_width: True - theme_text_color: "Custom" if root.trailing_text_color else "Primary" + theme_text_color: "Custom" text_color: - root.trailing_text_color \ - if root.trailing_text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.trailing_text_color else \ + root.trailing_text_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -140,7 +140,6 @@ size_hint_x: None shorten_from: "right" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" width: @@ -152,10 +151,11 @@ + container.spacing \ + dp(18) \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color Widget: @@ -165,16 +165,16 @@ size: "48dp", "48dp" pos_hint: {"center_y": .5} icon: root.trailing_icon - theme_text_color: "Custom" if root.trailing_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.trailing_icon_color \ - if root.trailing_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.trailing_icon_color else \ + root.trailing_icon_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -190,21 +190,21 @@ size_hint: None, None size: "48dp", "48dp" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.trailing_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.trailing_icon_color \ - if root.trailing_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.trailing_icon_color else \ + root.trailing_icon_color MDLabel: text: root.trailing_text adaptive_size: True pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.trailing_text_color else "Primary" + theme_text_color: "Custom" text_color: - root.trailing_text_color \ - if root.trailing_text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color @@ -222,7 +222,6 @@ size_hint_x: None shorten_from: "right" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" width: @@ -233,10 +232,11 @@ + container.padding[2] \ + container.spacing \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color MDTrailingIconTextContainer: id: trailing_container @@ -245,10 +245,10 @@ trailing_text_color: root.trailing_text_color trailing_icon_color: root.trailing_icon_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -263,18 +263,18 @@ text: root.text valign: "center" padding_x: "12dp" - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -296,16 +296,15 @@ size_hint: None, None size: "48dp", "48dp" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.leading_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.leading_icon_color \ - if root.leading_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.leading_icon_color else \ + root.leading_icon_color MDLabel: text: root.text pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" size_hint_x: None @@ -319,10 +318,11 @@ + container.spacing \ + dp(18) \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color Widget: @@ -333,10 +333,10 @@ trailing_icon_color: root.trailing_icon_color trailing_text_color: root.trailing_text_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -358,11 +358,11 @@ size_hint: None, None size: "48dp", "48dp" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.leading_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.leading_icon_color \ - if root.leading_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.leading_icon_color else \ + root.leading_icon_color MDLabel: id: label @@ -371,7 +371,6 @@ size_hint_x: None shorten_from: "right" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" width: @@ -384,10 +383,11 @@ + container.spacing \ + dp(18) \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color Widget: @@ -397,16 +397,16 @@ size: "48dp", "48dp" pos_hint: {"center_y": .5} icon: root.trailing_icon - theme_text_color: "Custom" if root.trailing_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.trailing_icon_color \ - if root.trailing_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.trailing_icon_color else \ + root.trailing_icon_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -428,11 +428,11 @@ size_hint: None, None size: "48dp", "48dp" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.leading_icon_color else "Primary" + theme_text_color: "Custom" text_color: - root.leading_icon_color \ - if root.leading_icon_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.leading_icon_color else \ + root.leading_icon_color MDLabel: id: label @@ -441,7 +441,6 @@ size_hint_x: None shorten_from: "right" pos_hint: {"center_y": .5} - theme_text_color: "Custom" if root.text_color else "Primary" shorten: True shorten_from: "right" width: @@ -452,15 +451,16 @@ + container.padding[2] \ + container.spacing \ ) + theme_text_color: "Custom" text_color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + app.theme_cls.onSurfaceVariantColor \ + if not root.text_color else \ + root.text_color - MDSeparator: + MDDivider: md_bg_color: ( \ - self.theme_cls.divider_color \ + app.theme_cls.outlineVariantColor \ if not root.divider_color \ else root.divider_color \ ) \ @@ -470,14 +470,18 @@ orientation: "vertical" - elevation: root.elevation - shadow_radius: root.shadow_radius - shadow_softness: root.shadow_softness - shadow_offset: root.shadow_offset - shadow_color: root.shadow_color - shadow_color: root.shadow_color - radius: root.radius size_hint: None, None + focus_behavior: False + style: "elevated" + elevation_level: 2 + shadow_softness: 1.5 + shadow_radius: 4 + theme_bg_color: root.theme_bg_color +# md_bg_color: +# app.theme_cls.surfaceContainerColor \ +# if root.theme_bg_color == "Primary" else \ +# root.md_bg_color + MDBoxLayout: id: content_header diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.py index 012eef4..eabdc9c 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/menu/menu.py @@ -205,6 +205,7 @@ You can use the following parameters to customize the menu items: :align: center .. Header: + Header ------ @@ -338,6 +339,7 @@ for both the righthand and lefthand menus. :align: center .. Position: + Position ======== @@ -405,50 +407,49 @@ Center position .. code-block:: python from kivy.lang import Builder - from kivy.metrics import dp - from kivymd.app import MDApp from kivymd.uix.menu import MDDropdownMenu + from kivymd.app import MDApp KV = ''' - MDScreen: + MDScreen + md_bg_color: self.theme_cls.backgroundColor MDDropDownItem: - id: drop_item - pos_hint: {'center_x': .5, 'center_y': .5} - text: 'Item 0' - on_release: app.menu.open() + pos_hint: {"center_x": .5, "center_y": .5} + on_release: app.open_drop_item_menu(self) + + MDDropDownItemText: + id: drop_text + text: "Item" ''' - class Test(MDApp): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.screen = Builder.load_string(KV) + class Example(MDApp, CommonApp): + drop_item_menu: MDDropdownMenu = None + + def open_drop_item_menu(self, item): menu_items = [ { - "text": f"Item {i}", - "on_release": lambda x=f"Item {i}": self.set_item(x), + "text": f"{i}", + "on_release": lambda x=f"Item {i}": self.menu_callback(x), } for i in range(5) ] - self.menu = MDDropdownMenu( - caller=self.screen.ids.drop_item, - items=menu_items, - position="center", - ) - self.menu.bind() + if not self.drop_item_menu: + self.drop_item_menu = MDDropdownMenu( + caller=item, items=menu_items, position="center" + ) + self.drop_item_menu.open() - def set_item(self, text_item): - self.screen.ids.drop_item.set_item(text_item) - self.menu.dismiss() + def menu_callback(self, text_item): + self.root.ids.drop_text.text = text_item + self.drop_item_menu.dismiss() def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" - return self.screen + return Builder.load_string(KV) - Test().run() + Example().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/menu-position-center.gif :align: center @@ -636,14 +637,14 @@ from kivy.properties import ( ) from kivy.uix.recycleview import RecycleView -import kivymd.material_resources as m_res from kivymd import uix_path from kivymd.uix.behaviors import StencilBehavior, RectangularRippleBehavior from kivymd.uix.behaviors.motion_behavior import MotionDropDownMenuBehavior from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.card import MDCard from kivymd.uix.label import MDLabel -from kivymd.uix.list import IRightBody + +# from kivymd.uix.list import IRightBody with open( os.path.join(uix_path, "menu", "menu.kv"), encoding="utf-8" @@ -672,7 +673,7 @@ class BaseDropdownItem(RectangularRippleBehavior, ButtonBehavior, MDBoxLayout): .. versionadded:: 1.2.0 For more information, see in the - :class:`~kivymd.uix.behaviors.RectangularRippleBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and :class:`~kivymd.uix.boxlayout.MDBoxLayout` classes. """ @@ -762,7 +763,7 @@ class BaseDropdownItem(RectangularRippleBehavior, ButtonBehavior, MDBoxLayout): """ -class MDTrailingTextContainer(BaseDropdownItem, IRightBody, MDLabel): +class MDTrailingTextContainer(BaseDropdownItem, MDLabel): """ Implements a container for trailing text. @@ -775,7 +776,7 @@ class MDTrailingTextContainer(BaseDropdownItem, IRightBody, MDLabel): """ -class MDTrailingIconTextContainer(BaseDropdownItem, IRightBody, MDBoxLayout): +class MDTrailingIconTextContainer(BaseDropdownItem, MDBoxLayout): """ Implements a container for trailing icons and trailing text. @@ -877,9 +878,9 @@ class MDDropdownMenu(MotionDropDownMenuBehavior, StencilBehavior, MDCard): Dropdown menu class. For more information, see in the - :class:`~kivymd.uix.behaviors.MotionDropDownMenuBehavior` and - :class:`~kivymd.uix.behaviors.StencilBehavior` and - :class:`~kivymd.uix.card.MDCard` + :class:`~kivymd.uix.behaviors.motion_behavior.MotionDropDownMenuBehavior` and + :class:`~kivymd.uix.behaviors.stencil_behavior.StencilBehavior` and + :class:`~kivymd.uix.card.card.MDCard` classes documentation. :Events: @@ -1058,42 +1059,6 @@ class MDDropdownMenu(MotionDropDownMenuBehavior, StencilBehavior, MDCard): and defaults to `'[dp(7)]'`. """ - elevation = NumericProperty(m_res.DROP_DOWN_MENU_ELEVATION) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.elevation` - attribute. - - :attr:`elevation` is an :class:`~kivy.properties.NumericProperty` - and defaults to `2`. - """ - - shadow_radius = VariableListProperty([6], length=4) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_radius` - attribute. - - :attr:`shadow_radius` is an :class:`~kivy.properties.VariableListProperty` - and defaults to `[6]`. - """ - - shadow_softness = NumericProperty(m_res.DROP_DOWN_MENU_SOFTNESS) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_softness` - attribute. - - :attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty` - and defaults to `6`. - """ - - shadow_offset = ListProperty(m_res.DROP_DOWN_MENU_OFFSET) - """ - See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_offset` - attribute. - - :attr:`shadow_offset` is an :class:`~kivy.properties.ListProperty` - and defaults to `(0, -2)`. - """ - _items = [] _start_coords = [] _tar_x = 0 @@ -1381,6 +1346,9 @@ class MDDropdownMenu(MotionDropDownMenuBehavior, StencilBehavior, MDCard): items.append(data) self._items = items + # Update items in view + if hasattr(self, "menu"): + self.menu.data = self._items def on_header_cls( self, instance_dropdown_menu, instance_user_menu_header @@ -1424,13 +1392,13 @@ if __name__ == "__main__": from kivy.metrics import dp from kivymd.app import MDApp - from kivymd.uix.button import MDRaisedButton + from kivymd.uix.button import MDButton, MDButtonText from kivymd.uix.screen import MDScreen class Test(MDApp): def __init__(self, **kwargs): super().__init__(**kwargs) - self.screen = MDScreen() + self.screen = MDScreen(md_bg_color=self.theme_cls.backgroundColor) menu_items = [{"text": f"Item {i}"} for i in range(55)] self.menu = MDDropdownMenu(items=menu_items, width_mult=4) @@ -1452,7 +1420,13 @@ if __name__ == "__main__": ] for pos_hint in pos_hints: self.screen.add_widget( - MDRaisedButton(pos_hint=pos_hint, on_release=self.open_menu) + MDButton( + MDButtonText( + text="Press me", + ), + pos_hint=pos_hint, + on_release=self.open_menu, + ) ) def build(self): diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__init__.py new file mode 100644 index 0000000..a492e02 --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__init__.py @@ -0,0 +1,7 @@ +# NOQA F401 +from .navigationbar import ( + MDNavigationBar, + MDNavigationItem, + MDNavigationItemLabel, + MDNavigationItemIcon, +) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..a19eb78 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__pycache__/navigationbar.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__pycache__/navigationbar.cpython-311.pyc new file mode 100644 index 0000000..b7af579 Binary files /dev/null and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/__pycache__/navigationbar.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/navigationbar.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/navigationbar.kv new file mode 100644 index 0000000..8695e3d --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/navigationbar.kv @@ -0,0 +1,133 @@ + + size_hint_y: None + height: "80dp" + elevation_level: 0 + md_bg_color: + self.theme_cls.surfaceContainerColor \ + if root.theme_bg_color == "Primary" else \ + root.md_bg_color + + + + size_hint: None, None + size: "24sp", "24sp" + # theme_text_color: "Custom" + icon_color: + ( \ + ( \ + self.theme_cls.onSecondaryContainerColor \ + if self.parent.parent.active else \ + self.theme_cls.onSurfaceVariantColor \ + ) \ + if self.theme_icon_color == "Primary" else \ + ( \ + self.icon_color_active if self.icon_color_active else \ + ( \ + self.theme_cls.onSecondaryContainerColor \ + if self.parent.parent.active else \ + self.theme_cls.onSurfaceVariantColor \ + ) \ + ) \ + if self.parent.parent.active else \ + ( \ + self.icon_color_normal if self.icon_color_normal else \ + ( \ + self.theme_cls.onSecondaryContainerColor \ + if self.parent.parent.active else \ + self.theme_cls.onSurfaceVariantColor \ + ) \ + ) \ + ) \ + if self.parent else self.theme_cls.transparentColor + on_icon: + if self.icon not in md_icons.keys(): \ + self.size_hint = (None, None); \ + self.width = self.font_size; \ + self.height = self.font_size + + canvas.before: + Color: + rgba: + ( \ + ( \ + self.theme_cls.secondaryContainerColor \ + if not self.parent.parent.indicator_color else \ + self.parent.parent.indicator_color \ + ) \ + if self.parent.parent.active else \ + self.theme_cls.transparentColor \ + ) \ + if self.parent else self.theme_cls.transparentColor + RoundedRectangle: + radius: [dp(16), ] + size: + ( \ + (self.parent.parent._selected_region_width, dp(32)) \ + ) \ + if self.parent else (0, dp(32)) + pos: + ( \ + (self.center_x - self.parent.parent._selected_region_width / 2, \ + self.center_y - dp(16)) \ + ) \ + if self.parent else (0, 0) + + + + adaptive_size: True + role: "medium" + text_color: + ( \ + ( \ + self.theme_cls.onSecondaryContainerColor \ + if self.parent.parent.active else \ + self.theme_cls.onSurfaceVariantColor \ + ) \ + if self.theme_text_color == "Primary" else \ + ( \ + self.text_color_active if self.text_color_active else \ + ( \ + self.theme_cls.onSecondaryContainerColor \ + if self.parent.parent.active else \ + self.theme_cls.onSurfaceVariantColor \ + ) \ + ) \ + if self.parent.parent.active else \ + ( \ + self.text_color_normal if self.text_color_normal else \ + ( \ + self.theme_cls.onSecondaryContainerColor \ + if self.parent.parent.active else \ + self.theme_cls.onSurfaceVariantColor \ + ) \ + ) \ + ) \ + if self.parent else self.theme_cls.transparentColor + + + + + MDNavigationItemIconContainer: + id: icon_container + size_hint: None, None + size: self.minimum_size + pos_hint: {"center_x": .5} + y: + ( \ + (root.parent.height - (self.height + dp(16))) \ + if len(label_container.children) else \ + (root.parent.height / 2 - self.height / 2) \ + ) \ + if root.parent else 0 + + MDNavigationItemLabelContainer: + id: label_container + size_hint: None, None + size: self.minimum_size + pos_hint: {"center_x": .5} + y: + "16dp" \ + if len(icon_container.children) else \ + ( \ + (root.parent.height / 2 - self.height / 2) if root.parent else 0 \ + ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/navigationbar.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/navigationbar.py new file mode 100644 index 0000000..e2f45cc --- /dev/null +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationbar/navigationbar.py @@ -0,0 +1,624 @@ +""" +Components/Navigation bar +========================= + +.. seealso:: + + `Material Design 3 spec, Navigation bar `_ + +.. rubric:: Bottom navigation bars allow movement between primary destinations in an app: + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation.png + :align: center + +Usage +----- + +.. code-block:: kv + + + + MDNavigationBar: + + MDNavigationItem: + + MDNavigationItemIcon: + + MDNavigationItemLabel: + + [...] + +Anatomy +======= + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigationbar-item-anatomy.png + :align: center + +Example +------- + +.. tabs:: + + .. tab:: Declarative KV style + + .. code-block:: python + + from kivy.lang import Builder + from kivy.properties import StringProperty + + from kivymd.app import MDApp + from kivymd.uix.navigationbar import MDNavigationBar, MDNavigationItem + from kivymd.uix.screen import MDScreen + + + class BaseMDNavigationItem(MDNavigationItem): + icon = StringProperty() + text = StringProperty() + + + class BaseScreen(MDScreen): + image_size = StringProperty() + + + KV = ''' + + + MDNavigationItemIcon: + icon: root.icon + + MDNavigationItemLabel: + text: root.text + + + + + FitImage: + source: f"https://picsum.photos/{root.image_size}/{root.image_size}" + size_hint: .9, .9 + pos_hint: {"center_x": .5, "center_y": .5} + radius: dp(24) + + + MDBoxLayout: + orientation: "vertical" + md_bg_color: self.theme_cls.backgroundColor + + MDScreenManager: + id: screen_manager + + BaseScreen: + name: "Screen 1" + image_size: "1024" + + BaseScreen: + name: "Screen 2" + image_size: "800" + + BaseScreen: + name: "Screen 3" + image_size: "600" + + + MDNavigationBar: + on_switch_tabs: app.on_switch_tabs(*args) + + BaseMDNavigationItem + icon: "gmail" + text: "Screen 1" + active: True + + BaseMDNavigationItem + icon: "twitter" + text: "Screen 2" + + BaseMDNavigationItem + icon: "linkedin" + text: "Screen 3" + ''' + + + class Example(MDApp): + def on_switch_tabs( + self, + bar: MDNavigationBar, + item: MDNavigationItem, + item_icon: str, + item_text: str, + ): + self.root.ids.screen_manager.current = item_text + + def build(self): + return Builder.load_string(KV) + + + Example().run() + + .. tab:: Declarative python style + + .. code-block:: python + + from kivy.metrics import dp + from kivy.properties import StringProperty + + from kivymd.uix.fitimage import FitImage + from kivymd.uix.screen import MDScreen + from kivymd.uix.screenmanager import MDScreenManager + from kivymd.uix.boxlayout import MDBoxLayout + from kivymd.uix.navigationbar import ( + MDNavigationBar, + MDNavigationItem, + MDNavigationItemLabel, + MDNavigationItemIcon, + ) + from kivymd.app import MDApp + + + class BaseMDNavigationItem(MDNavigationItem): + icon = StringProperty() + text = StringProperty() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.add_widget(MDNavigationItemIcon(icon=self.icon)) + self.add_widget(MDNavigationItemLabel(text=self.text)) + + + class BaseScreen(MDScreen): + image_size = StringProperty() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.add_widget( + FitImage( + source=f"https://picsum.photos/{self.image_size}/{self.image_size}", + size_hint=(0.9, 0.9), + pos_hint={"center_x": 0.5, "center_y": 0.5}, + radius=dp(24), + ), + ) + + + class Example(MDApp): + def on_switch_tabs( + self, + bar: MDNavigationBar, + item: MDNavigationItem, + item_icon: str, + item_text: str, + ): + self.root.get_ids().screen_manager.current = item_text + + def build(self): + return MDBoxLayout( + MDScreenManager( + BaseScreen( + name="Screen 1", + image_size="1024", + ), + BaseScreen( + name="Screen 2", + image_size="800", + ), + BaseScreen( + name="Screen 3", + image_size="600", + ), + id="screen_manager", + ), + MDNavigationBar( + BaseMDNavigationItem( + icon="gmail", + text="Screen 1", + active=True, + ), + BaseMDNavigationItem( + icon="twitter", + text="Screen 2", + ), + BaseMDNavigationItem( + icon="linkedin", + text="Screen 3", + ), + on_switch_tabs=self.on_switch_tabs, + ), + orientation="vertical", + md_bg_color=self.theme_cls.backgroundColor, + ) + + + Example().run() + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigationbar-usage.gif + :align: center + +API break +========= + +1.2.0 version +------------- + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + + + class Example(MDApp): + def build(self): + return Builder.load_string( + ''' + MDScreen: + + MDBottomNavigation: + + MDBottomNavigationItem: + name: 'screen 1' + text: 'Mail' + icon: 'gmail' + badge_icon: "numeric-10" + + MDLabel: + text: 'Screen 1' + halign: 'center' + + MDBottomNavigationItem: + name: 'screen 2' + text: 'Twitter' + icon: 'twitter' + + MDLabel: + text: 'Screen 2' + halign: 'center' + ''' + ) + + + Example().run() + +2.0.0 version +------------- + +MDNavigationBar in version 2.0.0 no longer provides a screen manager for +content placement. You have to implement it yourself. This is due to the fact +that when using MDNavigationBar and MDTabs widgets at the same time, there +were conflicts between their screen managers. + +.. code-block:: python + + from kivy.lang import Builder + from kivy.properties import StringProperty + + from kivymd.app import MDApp + from kivymd.uix.navigationbar import MDNavigationBar, MDNavigationItem + from kivymd.uix.screen import MDScreen + + + class BaseMDNavigationItem(MDNavigationItem): + icon = StringProperty() + text = StringProperty() + + + class BaseScreen(MDScreen): + ... + + + KV = ''' + + + MDNavigationItemIcon: + icon: root.icon + + MDNavigationItemLabel: + text: root.text + + + + + MDLabel: + text: root.name + halign: "center" + + + MDBoxLayout: + orientation: "vertical" + md_bg_color: self.theme_cls.backgroundColor + + MDScreenManager: + id: screen_manager + + BaseScreen: + name: "Screen 1" + + BaseScreen: + name: "Screen 2" + + + MDNavigationBar: + on_switch_tabs: app.on_switch_tabs(*args) + + BaseMDNavigationItem + icon: "gmail" + text: "Screen 1" + active: True + + BaseMDNavigationItem + icon: "twitter" + text: "Screen 2" + ''' + + + class Example(MDApp): + def on_switch_tabs( + self, + bar: MDNavigationBar, + item: MDNavigationItem, + item_icon: str, + item_text: str, + ): + self.root.ids.screen_manager.current = item_text + + def build(self): + return Builder.load_string(KV) + + + Example().run() +""" + +from __future__ import annotations + +__all__ = ( + "MDNavigationItem", + "MDNavigationBar", + "MDNavigationItemLabel", + "MDNavigationItemIcon", +) + +import os + +from kivy.animation import Animation +from kivy.clock import Clock +from kivy.lang import Builder +from kivy.metrics import dp +from kivy.properties import ( + BooleanProperty, + ColorProperty, + NumericProperty, + StringProperty, +) +from kivy.uix.behaviors import ButtonBehavior +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.relativelayout import RelativeLayout + +from kivymd.uix.label import MDLabel, MDIcon +from kivymd.uix.boxlayout import MDBoxLayout +from kivymd import uix_path +from kivymd.uix.behaviors import ( + DeclarativeBehavior, + CommonElevationBehavior, + RectangularRippleBehavior, +) +from kivymd.utils.set_bars_colors import set_bars_colors + +with open( + os.path.join(uix_path, "navigationbar", "navigationbar.kv"), + encoding="utf-8", +) as kv_file: + Builder.load_string(kv_file.read()) + + +class MDNavigationItemLabel(MDLabel): + """ + Implements a text label for the :class:`~MDNavigationItem` class. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivymd.uix.label.label.MDLabel` class documentation. + """ + + text_color_active = ColorProperty(None) + """ + Item icon color in (r, g, b, a) or string format. + + :attr:`text_color_active` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + text_color_normal = ColorProperty(None) + """ + Item icon color in (r, g, b, a) or string format. + + :attr:`text_color_normal` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + +class MDNavigationItemIcon(MDIcon): + """ + Implements a icon for the :class:`~MDNavigationItem` class. + + .. versionadded:: 2.0.0 + + For more information, see in the + :class:`~kivymd.uix.label.label.MDIcon` class documentation. + """ + + icon_color_active = ColorProperty(None) + """ + Item icon color in (r, g, b, a) or string format. + + :attr:`icon_color_active` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + icon_color_normal = ColorProperty(None) + """ + Item icon color in (r, g, b, a) or string format. + + :attr:`icon_color_normal` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + +class MDNavigationItem( + DeclarativeBehavior, + RectangularRippleBehavior, + ButtonBehavior, + RelativeLayout, +): + """ + Bottom item class. + + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and + :class:`~kivy.uix.anchorlayout.AnchorLayout` and + :class:`~kivy.uix.behaviors.ButtonBehavior` + classes documentation. + + .. versionchanged:: 2.0.0 + Rename class from `MDBottomNavigationItem` to `MDNavigationItem`. + """ + + active = BooleanProperty(False) + """ + Indicates if the bar item is active or inactive. + + :attr:`active` is a :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + indicator_color = ColorProperty(None) + """ + The background color in (r, g, b, a) or string format of the highlighted + item. + + .. versionadded:: 1.0.0 + + .. versionchanged:: 2.0.0 + Rename property from `selected_color_background` to `indicator_color`. + + :attr:`indicator_color` is an :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + indicator_transition = StringProperty("in_out_sine") + """ + Animation type of the active element indicator. + + :attr:`indicator_transition` is an :class:`~kivy.properties.StringProperty` + and defaults to `'in_out_sine'`. + """ + + indicator_duration = NumericProperty(0.1) + """ + Duration of animation of the active element indicator. + + :attr:`indicator_duration` is an :class:`~kivy.properties.NumericProperty` + and defaults to `0.1`. + """ + + _selected_region_width = NumericProperty(dp(0)) + + def on_active(self, instance, value) -> None: + """Fired when the values of :attr:`active` change.""" + + def on_active(*args): + Animation( + _selected_region_width=dp(64) if value else 0, + t=self.indicator_transition, + d=self.indicator_duration, + ).start(self) + + Clock.schedule_once(on_active) + + def on_release(self) -> None: + """Fired when clicking on a panel item.""" + + self.parent.set_active_item(self) + + def add_widget(self, widget, *args, **kwargs): + if isinstance(widget, MDNavigationItemLabel): + self.ids.label_container.add_widget(widget) + elif isinstance(widget, MDNavigationItemIcon): + self.ids.icon_container.add_widget(widget) + elif isinstance( + widget, + (MDNavigationItemIconContainer, MDNavigationItemLabelContainer), + ): + return super().add_widget(widget) + + +class MDNavigationBar(CommonElevationBehavior, MDBoxLayout): + """ + A navigation bar class. + + For more information, see in the + :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and + :class:`~kivymd.uix.boxlayout.MDBoxLayout` + classes documentation. + + :Events: + :attr:`on_switch_tabs` + Fired when switching tabs. + + .. versionadded:: 1.0.0 + + .. versionchanged:: 2.0.0 + Rename class from `MDBottomNavigation` to `MDNavigationBar`. + """ + + set_bars_color = BooleanProperty(False) + """ + If `True` the background color of the navigation bar will be set + automatically according to the current color of the toolbar. + + .. versionadded:: 1.0.0 + + :attr:`set_bars_color` is an :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + def __init__(self, *args, **kwargs): + self.register_event_type("on_switch_tabs") + super().__init__(*args, **kwargs) + Clock.schedule_once(self.set_status_bar_color) + + def set_active_item(self, item: MDNavigationItem) -> None: + """Sets the currently active element on the panel.""" + + for widget in self.children: + if item is widget: + widget.active = True + self.dispatch( + "on_switch_tabs", + widget, + widget.ids.icon_container.children[0].icon + if len(widget.ids.icon_container.children) + else "", + widget.ids.label_container.children[0].text + if len(widget.ids.label_container.children) + else "", + ) + else: + widget.active = False + + def set_status_bar_color(self, interval: int | float) -> None: + """Sets the color of the lower system navigation bar.""" + + if self.set_bars_color: + set_bars_colors(self.md_bg_color, None, self.theme_cls.theme_style) + + def on_switch_tabs( + self, item: MDNavigationItem, item_icon: str, item_text: str + ) -> None: + """Fired when switching tabs.""" + + +class MDNavigationItemIconContainer(BoxLayout): + pass + + +class MDNavigationItemLabelContainer(BoxLayout): + pass diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__init__.py index 1e859f9..db6485f 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__init__.py @@ -4,6 +4,9 @@ from .navigationdrawer import ( MDNavigationDrawerDivider, MDNavigationDrawerHeader, MDNavigationDrawerItem, + MDNavigationDrawerItemLeadingIcon, + MDNavigationDrawerItemText, + MDNavigationDrawerItemTrailingText, MDNavigationDrawerLabel, MDNavigationDrawerMenu, MDNavigationLayout, diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc index bc99a6d..0adf094 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc index 9a6e7e0..2f8adf8 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/__pycache__/navigationdrawer.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.kv index dbb484a..702fce1 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.kv @@ -1,134 +1,83 @@ #:import Window kivy.core.window.Window -#:import m_res kivymd.material_resources -: + + type: "filled" size_hint_x: None - width: Window.width - dp(56) if Window.width <= dp(376) else dp(320) - md_bg_color: self.theme_cls.bg_light - padding: + width: Window.width - dp(56) if Window.width <= dp(360) else dp(320) + theme_bg_color: "Custom" + shadow_radius: self.radius + md_bg_color: + self.theme_cls.surfaceContainerLowColor \ + if not self.background_color else \ + self.background_color x: (self.width * (self.open_progress - 1)) \ if self.anchor == "left" \ else (Window.width - self.width * self.open_progress) - canvas: - Clear - Color: - rgba: self.md_bg_color - RoundedRectangle: - size: self.size - pos: self.pos - source: root.background - radius: root.radius - adaptive_height: True - - MDLabel: - text: root.text - adaptive_size: True - markup: True - - - - adaptive_height: True - - MDSeparator: - color: root.color if root.color else app.theme_cls.divider_color - - - - adaptive_height: True - - FitImage: - id: logo - source: root.source - size_hint: None, None - size: label_box.height, label_box.height - - MDBoxLayout: - id: label_box - orientation: "vertical" - adaptive_height: True - - MDLabel: - id: title - adaptive_height: True - halign: root.title_halign - text: root.title - font_style: root.title_font_style - font_size: root.title_font_size - color: - root.title_color \ - if root.title_color else \ - app.theme_cls.text_color - - MDLabel: - id: text - adaptive_height: True - text: root.text - halign: root.text_halign - font_style: root.text_font_style - font_size: root.text_font_size - color: - root.text_color \ - if root.text_color else \ - app.theme_cls.text_color + padding: "20dp", "0dp", "16dp", "16dp" + text_color: + self.theme_cls.onSurfaceColor \ + if self.theme_text_color == "Primary" else \ + self.text_color - radius: self.height / 2 if self.radius == [0, 0, 0, 0] else self.radius - divider: None - theme_text_color: "Custom" - text_color: self.text_color if not self.selected else self.selected_color - _txt_left_pad: "56dp" - on_size: - self.ids._left_container.x = "4dp" - self.ids._right_container.width = right_label.texture_size[0] - on_release: - if not self.selected: self._text_color = self.text_color - self._text_right_color = root.text_right_color if root.text_right_color else app.theme_cls.text_color - self._drawer_menu.reset_active_color(self) + radius: self.height / 2 + ripple_color: self.theme_cls.onSecondaryContainerColor[:-1] + [0.12] + theme_bg_color: "Custom" + md_bg_color: + self.theme_cls.surfaceContainerLowColor \ + if not self.inactive_indicator_color else \ + self.inactive_indicator_color - IconLeftWidgetWithoutTouch: - icon: root.icon - theme_icon_color: "Custom" - icon_color: - ( \ - app.theme_cls.text_color \ - if not root.icon_color else \ - root.icon_color \ - ) \ - if not root.selected else \ - root.selected_color - MDLabel: - id: right_label - text: root.right_text - pos_hint: {"center_y": .5} - adaptive_size: True - markup: True - color: - ( \ - root.text_right_color \ - if root.text_right_color else \ - app.theme_cls.text_color \ - ) \ - if not root.selected else \ - root.selected_color - x: - root.x \ - + root.width \ - - m_res.HORIZ_MARGINS \ - - root.ids._right_container.width - dp(24) \ - - self.texture_size[0] \ - + dp(24) + + text_color: + self.theme_cls.onSurfaceVariantColor \ + if self.theme_text_color == "Primary" else \ + self.text_color + + + + font_style: "Label" + role: "large" + text_color: + self.theme_cls.onSurfaceVariantColor \ + if self.theme_text_color == "Primary" else \ + self.text_color + + + + icon_color: + self.theme_cls.onSurfaceVariantColor \ + if self.theme_icon_color == "Primary" else \ + self.icon_color + + + + size_hint_y: None + height: self.minimum_height + + + + padding: 0, "4dp", 0, "4dp" + size_hint_y: None + height: self.minimum_height + + MDDivider: - MDList: + GridLayout: id: menu + cols: 1 + size_hint_y: None + height: self.minimum_height spacing: root.spacing + diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.py index ac2eac3..369869e 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationdrawer/navigationdrawer.py @@ -4,19 +4,22 @@ Components/NavigationDrawer .. seealso:: - `Material Design 2 spec, Navigation drawer `_ and - `Material Design 3 spec, Navigation drawer `_ + `Material Design, Navigation drawer `_ .. rubric:: Navigation drawers provide access to destinations in your app. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer.png :align: center +- Use navigation drawers in expanded layouts and modal navigation drawers in compact and medium layouts +- Can be open or closed by default +- Two types: standard and modal + When using the class :class:`~MDNavigationDrawer` skeleton of your `KV` markup should look like this: -Anatomy -------- +Usage +----- .. code-block:: kv @@ -32,8 +35,8 @@ Anatomy MDNavigationDrawer: - # This custom rule should implement what will be appear in your - # MDNavigationDrawer. + # This custom rule should implement what will be displayed in + # your MDNavigationDrawer. ContentNavigationDrawer: A simple example @@ -47,11 +50,11 @@ A simple example from kivy.lang import Builder - from kivymd.uix.boxlayout import MDBoxLayout from kivymd.app import MDApp KV = ''' MDScreen: + md_bg_color: self.theme_cls.backgroundColor MDNavigationLayout: @@ -59,31 +62,39 @@ A simple example MDScreen: - MDTopAppBar: - title: "Navigation Drawer" - elevation: 4 - pos_hint: {"top": 1} - md_bg_color: "#e7e4c0" - specific_text_color: "#4a4939" - left_action_items: - [['menu', lambda x: nav_drawer.set_state("open")]] + MDButton: + pos_hint: {"center_x": .5, "center_y": .5} + on_release: nav_drawer.set_state("toggle") + MDButtonText: + text: "Open Drawer" MDNavigationDrawer: id: nav_drawer - radius: (0, 16, 16, 0) + radius: 0, dp(16), dp(16), 0 - ContentNavigationDrawer: + MDNavigationDrawerMenu: + + MDNavigationDrawerLabel: + text: "Mail" + + MDNavigationDrawerItem: + + MDNavigationDrawerItemLeadingIcon: + icon: "account" + + MDNavigationDrawerItemText: + text: "Inbox" + + MDNavigationDrawerItemTrailingText: + text: "24" + + MDNavigationDrawerDivider: ''' - class ContentNavigationDrawer(MDBoxLayout): - pass - - class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" return Builder.load_string(KV) @@ -93,454 +104,416 @@ A simple example .. code-block:: python - from kivymd.app import MDApp - from kivymd.uix.boxlayout import MDBoxLayout - from kivymd.uix.navigationdrawer import MDNavigationLayout, MDNavigationDrawer - from kivymd.uix.screen import MDScreen + from kivy.metrics import dp + + from kivymd.uix.button import MDButton, MDButtonText from kivymd.uix.screenmanager import MDScreenManager - from kivymd.uix.toolbar import MDTopAppBar - - - class ContentNavigationDrawer(MDBoxLayout): - pass + from kivymd.uix.navigationdrawer import ( + MDNavigationLayout, + MDNavigationDrawer, + MDNavigationDrawerMenu, + MDNavigationDrawerLabel, + MDNavigationDrawerItem, + MDNavigationDrawerItemLeadingIcon, + MDNavigationDrawerItemText, + MDNavigationDrawerItemTrailingText, + MDNavigationDrawerDivider, + ) + from kivymd.uix.screen import MDScreen + from kivymd.app import MDApp class Example(MDApp): def build(self): - self.theme_cls.theme_style = "Dark" - return( - MDScreen( - MDNavigationLayout( - MDScreenManager( - MDScreen( - MDTopAppBar( - title="Navigation Drawer", - elevation=4, - pos_hint={"top": 1}, - md_bg_color="#e7e4c0", - specific_text_color="#4a4939", - left_action_items=[ - ['menu', lambda x: self.nav_drawer_open()] - ], - ) - - ) - ), - MDNavigationDrawer( - ContentNavigationDrawer(), - id="nav_drawer", - radius=(0, 16, 16, 0), + return MDScreen( + MDNavigationLayout( + MDScreenManager( + MDScreen( + MDButton( + MDButtonText( + text="Open Drawer", + ), + on_release=lambda x: self.root.get_ids().nav_drawer.set_state( + "toggle" + ), + pos_hint={"center_x": 0.5, "center_y": 0.5}, + ), ), ), + MDNavigationDrawer( + MDNavigationDrawerMenu( + MDNavigationDrawerLabel( + text="Mail", + ), + MDNavigationDrawerItem( + MDNavigationDrawerItemLeadingIcon( + icon="account", + ), + MDNavigationDrawerItemText( + text="Inbox", + ), + MDNavigationDrawerItemTrailingText( + text="24", + ), + ), + MDNavigationDrawerDivider( + ), + ), + id="nav_drawer", + radius=(0, dp(16), dp(16), 0), + ), ), + md_bg_color=self.theme_cls.backgroundColor, ) - def nav_drawer_open(self, *args): - nav_drawer = self.root.children[0].ids.nav_drawer - nav_drawer.set_state("open") - Example().run() -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer.gif +Anatomy +------- + +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-anatomy.png :align: center .. Note:: :class:`~MDNavigationDrawer` is an empty :class:`~kivymd.uix.card.MDCard` panel. -Standard content for the navigation bar ---------------------------------------- +Item anatomy +------------ -.. tabs:: +.. code-block:: kv - .. tab:: Declarative KV styles + MDNavigationDrawerItem: - .. code-block:: python + MDNavigationDrawerItemLeadingIcon: + icon: "account" - from kivy.lang import Builder + MDNavigationDrawerItemText: + text: "Inbox" - from kivymd.app import MDApp + MDNavigationDrawerItemTrailingText: + text: "24" - KV = ''' - - focus_color: "#e7e4c0" - text_color: "#4a4939" - icon_color: "#4a4939" - ripple_color: "#c5bdd2" - selected_color: "#0c6c4d" - - - - text_color: "#4a4939" - icon_color: "#4a4939" - focus_behavior: False - selected_color: "#4a4939" - _no_ripple_effect: True - - - MDScreen: - - MDNavigationLayout: - - MDScreenManager: - - MDScreen: - - MDTopAppBar: - title: "Navigation Drawer" - elevation: 4 - pos_hint: {"top": 1} - md_bg_color: "#e7e4c0" - specific_text_color: "#4a4939" - left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]] - - MDNavigationDrawer: - id: nav_drawer - radius: (0, 16, 16, 0) - - MDNavigationDrawerMenu: - - MDNavigationDrawerHeader: - title: "Header title" - title_color: "#4a4939" - text: "Header text" - spacing: "4dp" - padding: "12dp", 0, 0, "56dp" - - MDNavigationDrawerLabel: - text: "Mail" - - DrawerClickableItem: - icon: "gmail" - right_text: "+99" - text_right_color: "#4a4939" - text: "Inbox" - - DrawerClickableItem: - icon: "send" - text: "Outbox" - - MDNavigationDrawerDivider: - - MDNavigationDrawerLabel: - text: "Labels" - - DrawerLabelItem: - icon: "information-outline" - text: "Label" - - DrawerLabelItem: - icon: "information-outline" - text: "Label" - ''' - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) - - - Example().run() - - .. tab:: Declarative python styles - - .. code-block:: python - - from kivymd.app import MDApp - from kivymd.uix.navigationdrawer import ( - MDNavigationLayout, - MDNavigationDrawer, - MDNavigationDrawerMenu, - MDNavigationDrawerHeader, - MDNavigationDrawerLabel, - MDNavigationDrawerDivider, - MDNavigationDrawerItem, - ) - from kivymd.uix.screen import MDScreen - from kivymd.uix.screenmanager import MDScreenManager - from kivymd.uix.toolbar import MDTopAppBar - - - class BaseNavigationDrawerItem(MDNavigationDrawerItem): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.radius = 24 - self.text_color = "#4a4939" - self.icon_color = "#4a4939" - self.focus_color = "#e7e4c0" - - - class DrawerLabelItem(BaseNavigationDrawerItem): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.focus_behavior = False - self._no_ripple_effect = True - self.selected_color = "#4a4939" - - - class DrawerClickableItem(BaseNavigationDrawerItem): - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.ripple_color = "#c5bdd2" - self.selected_color = "#0c6c4d" - - - class Example(MDApp): - def build(self): - self.theme_cls.theme_style = "Dark" - return( - MDScreen( - MDNavigationLayout( - MDScreenManager( - MDScreen( - MDTopAppBar( - title="Navigation Drawer", - elevation=4, - pos_hint={"top": 1}, - md_bg_color="#e7e4c0", - specific_text_color="#4a4939", - left_action_items=[ - ['menu', lambda x: self.nav_drawer_open()] - ], - ) - - ) - ), - MDNavigationDrawer( - MDNavigationDrawerMenu( - MDNavigationDrawerHeader( - title="Header title", - title_color="#4a4939", - text="Header text", - spacing="4dp", - padding=("12dp", 0, 0, "56dp"), - ), - MDNavigationDrawerLabel( - text="Mail", - ), - DrawerClickableItem( - icon="gmail", - right_text="+99", - text_right_color="#4a4939", - text="Inbox", - ), - DrawerClickableItem( - icon="send", - text="Outbox", - ), - MDNavigationDrawerDivider(), - MDNavigationDrawerLabel( - text="Labels", - ), - DrawerLabelItem( - icon="information-outline", - text="Label", - ), - DrawerLabelItem( - icon="information-outline", - text="Label", - ), - ), - id="nav_drawer", - radius=(0, 16, 16, 0), - ) - ) - ) - ) - - def nav_drawer_open(self, *args): - nav_drawer = self.root.children[0].ids.nav_drawer - nav_drawer.set_state("open") - - - Example().run() - -.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-standatd-content.gif +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-item-anatomy.png :align: center -Switching screens in the ``ScreenManager`` and using the common ``MDTopAppBar`` ------------------------------------------------------------------------------ +Type drawer +=========== -.. tabs:: +Standard +-------- - .. tab:: Declarative KV styles +.. code-block:: kv - .. code-block:: python + MDNavigationDrawer: + drawer_type: "standard" - from kivy.lang import Builder - from kivy.properties import ObjectProperty +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-type-standard.gif + :align: center - from kivymd.app import MDApp - from kivymd.uix.scrollview import MDScrollView +Modal +----- - KV = ''' - +.. code-block:: kv - MDList: + MDNavigationDrawer: + drawer_type: "modal" - OneLineListItem: - text: "Screen 1" - on_press: - root.nav_drawer.set_state("close") - root.screen_manager.current = "scr 1" +.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-type-modal.gif + :align: center - OneLineListItem: - text: "Screen 2" - on_press: - root.nav_drawer.set_state("close") - root.screen_manager.current = "scr 2" +Anchoring screen edge for drawer +================================ + + Left + ---- + + .. code-block:: kv + + MDNavigationDrawer: + anchor: "left" + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-ancjor-left.png + :align: center + + Right + ----- + + .. code-block:: kv + + MDNavigationDrawer: + anchor: "right" + + .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-ancjor-right.png + :align: center + +API break +========= + +1.2.0 version +------------- + +.. code-block:: python + + from kivy.lang import Builder + + from kivymd.app import MDApp + + KV = ''' + + focus_color: "#e7e4c0" + text_color: "#4a4939" + icon_color: "#4a4939" + ripple_color: "#c5bdd2" + selected_color: "#0c6c4d" - MDScreen: - - MDTopAppBar: - pos_hint: {"top": 1} - elevation: 4 - title: "MDNavigationDrawer" - left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]] - - MDNavigationLayout: - - MDScreenManager: - id: screen_manager - - MDScreen: - name: "scr 1" - - MDLabel: - text: "Screen 1" - halign: "center" - - MDScreen: - name: "scr 2" - - MDLabel: - text: "Screen 2" - halign: "center" - - MDNavigationDrawer: - id: nav_drawer - radius: (0, 16, 16, 0) - - ContentNavigationDrawer: - screen_manager: screen_manager - nav_drawer: nav_drawer - ''' + + text_color: "#4a4939" + icon_color: "#4a4939" + focus_behavior: False + selected_color: "#4a4939" + _no_ripple_effect: True - class ContentNavigationDrawer(MDScrollView): - screen_manager = ObjectProperty() - nav_drawer = ObjectProperty() + MDScreen: + + MDNavigationLayout: + + MDScreenManager: + + MDScreen: + + MDRaisedButton: + text: "Open Drawer" + pos_hint: {"center_x": .5, "center_y": .5} + on_release: nav_drawer.set_state("toggle") + + MDNavigationDrawer: + id: nav_drawer + radius: (0, dp(16), dp(16), 0) + + MDNavigationDrawerMenu: + + MDNavigationDrawerHeader: + title: "Header title" + title_color: "#4a4939" + text: "Header text" + spacing: "4dp" + padding: "12dp", 0, 0, "56dp" + + MDNavigationDrawerLabel: + text: "Mail" + + DrawerClickableItem: + icon: "gmail" + right_text: "+99" + text_right_color: "#4a4939" + text: "Inbox" + + DrawerClickableItem: + icon: "send" + text: "Outbox" + + MDNavigationDrawerDivider: + + MDNavigationDrawerLabel: + text: "Labels" + + DrawerLabelItem: + icon: "information-outline" + text: "Label" + + DrawerLabelItem: + icon: "information-outline" + text: "Label" + ''' - class Example(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" - return Builder.load_string(KV) + class Example(MDApp): + def build(self): + return Builder.load_string(KV) - Example().run() + Example().run() - .. tab:: Declarative python styles +2.2.0 version +------------- - .. code-block:: python +.. code-block:: python - from kivymd.app import MDApp - from kivymd.uix.label import MDLabel - from kivymd.uix.list import MDList, OneLineListItem - from kivymd.uix.navigationdrawer import MDNavigationLayout, MDNavigationDrawer - from kivymd.uix.screen import MDScreen - from kivymd.uix.screenmanager import MDScreenManager - from kivymd.uix.scrollview import MDScrollView - from kivymd.uix.toolbar import MDTopAppBar + from kivy.lang import Builder + from kivy.properties import StringProperty, ColorProperty + + from kivymd.app import MDApp + from kivymd.uix.boxlayout import MDBoxLayout + from kivymd.uix.navigationdrawer import ( + MDNavigationDrawerItem, MDNavigationDrawerItemTrailingText + ) + + KV = ''' + + active_indicator_color: "#e7e4c0" + + MDNavigationDrawerItemLeadingIcon: + icon: root.icon + theme_icon_color: "Custom" + icon_color: "#4a4939" + + MDNavigationDrawerItemText: + text: root.text + theme_text_color: "Custom" + text_color: "#4a4939" - class Example(MDApp): - def build(self): - self.theme_cls.primary_palette = "Orange" - self.theme_cls.theme_style = "Dark" - return ( - MDScreen( - MDTopAppBar( - pos_hint={"top": 1}, - elevation=4, - title="MDNavigationDrawer", - left_action_items=[["menu", lambda x: self.nav_drawer_open()]], - ), - MDNavigationLayout( - MDScreenManager( - MDScreen( - MDLabel( - text="Screen 1", - halign="center", - ), - name="scr 1", - ), - MDScreen( - MDLabel( - text="Screen 2", - halign="center", - ), - name="scr 2", - ), - id="screen_manager", - ), - MDNavigationDrawer( - MDScrollView( - MDList( - OneLineListItem( - text="Screen 1", - on_press=self.switch_screen, - ), - OneLineListItem( - text="Screen 2", - on_press=self.switch_screen, - ), - ), - ), - id="nav_drawer", - radius=(0, 16, 16, 0), - ), - id="navigation_layout", - ) - ) - ) + + adaptive_height: True + padding: "18dp", 0, 0, "12dp" - def switch_screen(self, instance_list_item: OneLineListItem): - self.root.ids.navigation_layout.ids.screen_manager.current = { - "Screen 1": "scr 1", "Screen 2": "scr 2" - }[instance_list_item.text] - self.root.children[0].ids.nav_drawer.set_state("close") + MDNavigationDrawerItemLeadingIcon: + icon: root.icon + theme_icon_color: "Custom" + icon_color: "#4a4939" + pos_hint: {"center_y": .5} - def nav_drawer_open(self): - nav_drawer = self.root.children[0].ids.nav_drawer - nav_drawer.set_state("open") + MDNavigationDrawerLabel: + text: root.text + theme_text_color: "Custom" + text_color: "#4a4939" + pos_hint: {"center_y": .5} + padding: "6dp", 0, "16dp", 0 + theme_line_height: "Custom" + line_height: 0 - Example().run() + MDScreen: + md_bg_color: self.theme_cls.backgroundColor + + MDNavigationLayout: + + MDScreenManager: + + MDScreen: + + MDButton: + pos_hint: {"center_x": .5, "center_y": .5} + on_release: nav_drawer.set_state("toggle") + + MDButtonText: + text: "Open Drawer" + + MDNavigationDrawer: + id: nav_drawer + radius: 0, dp(16), dp(16), 0 + + MDNavigationDrawerMenu: + + MDNavigationDrawerHeader: + orientation: "vertical" + padding: 0, 0, 0, "12dp" + adaptive_height: True + + MDLabel: + text: "Header title" + theme_text_color: "Custom" + theme_line_height: "Custom" + line_height: 0 + text_color: "#4a4939" + adaptive_height: True + padding_x: "16dp" + font_style: "Display" + role: "small" + + MDLabel: + text: "Header text" + padding_x: "18dp" + adaptive_height: True + font_style: "Title" + role: "large" + + MDNavigationDrawerDivider: + + DrawerItem: + icon: "gmail" + text: "Inbox" + trailing_text: "+99" + trailing_text_color: "#4a4939" + + DrawerItem: + icon: "send" + text: "Outbox" + + MDNavigationDrawerDivider: + + MDNavigationDrawerLabel: + text: "Labels" + padding_y: "12dp" + + DrawerLabel: + icon: "information-outline" + text: "Label" + + DrawerLabel: + icon: "information-outline" + text: "Label" + ''' + + + class DrawerLabel(MDBoxLayout): + icon = StringProperty() + text = StringProperty() + + + class DrawerItem(MDNavigationDrawerItem): + icon = StringProperty() + text = StringProperty() + trailing_text = StringProperty() + trailing_text_color = ColorProperty() + + _trailing_text_obj = None + + def on_trailing_text(self, instance, value): + self._trailing_text_obj = MDNavigationDrawerItemTrailingText( + text=value, + theme_text_color="Custom", + text_color=self.trailing_text_color, + ) + self.add_widget(self._trailing_text_obj) + + def on_trailing_text_color(self, instance, value): + self._trailing_text_obj.text_color = value + + + class Example(MDApp): + def build(self): + return Builder.load_string(KV) + + + Example().run() """ __all__ = ( "MDNavigationLayout", "MDNavigationDrawer", "MDNavigationDrawerItem", + "MDNavigationDrawerItemLeadingIcon", + "MDNavigationDrawerItemTrailingText", + "MDNavigationDrawerItemText", "MDNavigationDrawerMenu", "MDNavigationDrawerHeader", "MDNavigationDrawerLabel", "MDNavigationDrawerDivider", + "BaseNavigationDrawerItem", ) import os -from typing import Union from kivy.animation import Animation, AnimationTransition -from kivy.clock import Clock from kivy.core.window import Window from kivy.graphics.context_instructions import Color from kivy.graphics.vertex_instructions import Rectangle from kivy.lang import Builder +from kivy.metrics import dp from kivy.properties import ( AliasProperty, BooleanProperty, @@ -551,16 +524,24 @@ from kivy.properties import ( StringProperty, VariableListProperty, ) +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.floatlayout import FloatLayout +from kivy.uix.gridlayout import GridLayout from kivy.uix.screenmanager import ScreenManager +from kivymd.uix.appbar import MDTopAppBar +from kivymd.uix.behaviors import DeclarativeBehavior +from kivymd.uix.label import MDLabel from kivymd import uix_path from kivymd.uix.behaviors.focus_behavior import FocusBehavior -from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.card import MDCard -from kivymd.uix.floatlayout import MDFloatLayout -from kivymd.uix.list import MDList, OneLineAvatarIconListItem +from kivymd.uix.list import ( + MDListItem, + MDListItemLeadingIcon, + MDListItemSupportingText, + MDListItemTrailingSupportingText, +) from kivymd.uix.scrollview import MDScrollView -from kivymd.uix.toolbar import MDTopAppBar with open( os.path.join(uix_path, "navigationdrawer", "navigationdrawer.kv"), @@ -573,10 +554,33 @@ class NavigationDrawerContentError(Exception): pass -class MDNavigationLayout(MDFloatLayout): +class BaseNavigationDrawerItem: + """ + Implement the base class for the menu list item. + + .. versionadded:: 2.0.0 + """ + + selected = BooleanProperty(False) + """ + Is the item selected. + + :attr:`selected` is a :class:`~kivy.properties.BooleanProperty` + and defaults to `False`. + """ + + # kivymd.uix.navigationdrawer.MDNavigationDrawerMenu object. + _drawer_menu = ObjectProperty() + # kivymd.uix.navigationdrawer.MDNavigationDrawerItem object. + _drawer_item = ObjectProperty() + + +class MDNavigationLayout(DeclarativeBehavior, FloatLayout): """ For more information, see in the - :class:`~kivymd.uix.floatlayout.MDFloatLayout` class documentation. + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.floatlayout.FloatLayout` + classes documentation. """ _scrim_color = ObjectProperty(None) @@ -593,15 +597,21 @@ class MDNavigationLayout(MDFloatLayout): manager = self._screen_manager if not drawer or not manager: return - if drawer.type == "standard": + if drawer.drawer_type == "standard": manager.size_hint_x = None if drawer.anchor == "left": - manager.x = drawer.width + drawer.x - manager.width = self.width - manager.x + if ( + self._navigation_drawer.__class__.__name__ + != "MDBottomSheet" + ): + manager.x = drawer.width + drawer.x + manager.width = self.width - manager.x + else: + manager.width = self.width - manager.x else: manager.x = 0 manager.width = drawer.x - elif drawer.type == "modal": + elif drawer.drawer_type == "modal": manager.size_hint_x = None manager.x = 0 if drawer.anchor == "left": @@ -634,7 +644,8 @@ class MDNavigationLayout(MDFloatLayout): """ if not isinstance( - widget, (MDNavigationDrawer, ScreenManager, MDTopAppBar) + widget, + (MDNavigationDrawer, ScreenManager, MDTopAppBar), ): raise NavigationDrawerContentError( "The MDNavigationLayout must contain " @@ -656,323 +667,141 @@ class MDNavigationLayout(MDFloatLayout): return super().add_widget(widget) -class MDNavigationDrawerLabel(MDBoxLayout): +class MDNavigationDrawerLabel(MDLabel): """ - Implements a label for a menu for :class:`~MDNavigationDrawer` class. + Implements a label class. - For more information, see in the :class:`~kivymd.uix.boxlayout.MDBoxLayout` + For more information, see in the :class:`~kivymd.uix.label.label.MDLabel` class documentation. .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDNavigationDrawer: - - MDNavigationDrawerMenu: - - MDNavigationDrawerLabel: - text: "Mail" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-label.png - :align: center - """ - - text = StringProperty() - """ - Text label. - - :attr:`text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - padding = VariableListProperty(["20dp", 0, 0, "8dp"]) - """ - Padding between layout box and children: [padding_left, padding_top, - padding_right, padding_bottom]. - - Padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. - - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` - and defaults to `['20dp', 0, 0, '8dp']`. """ -class MDNavigationDrawerDivider(MDBoxLayout): +class MDNavigationDrawerDivider(BoxLayout): """ - Implements a divider for a menu for :class:`~MDNavigationDrawer` class. + Implements a divider class. - For more information, see in the :class:`~kivymd.uix.boxlayout.MDBoxLayout` - class documentation. + For more information, see in the + :class:`~kivy.uix.boxlayout.BoxLayout` class documentation. .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDNavigationDrawer: - - MDNavigationDrawerMenu: - - MDNavigationDrawerLabel: - text: "Mail" - - MDNavigationDrawerDivider: - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-divider.png - :align: center - """ - - padding = VariableListProperty(["20dp", "12dp", 0, "12dp"]) - """ - Padding between layout box and children: [padding_left, padding_top, - padding_right, padding_bottom]. - - Padding also accepts a two argument form [padding_horizontal, - padding_vertical] and a one argument form [padding]. - - :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` - and defaults to `['20dp', '12dp', 0, '12dp']`. - """ - - color = ColorProperty(None) - """ - Divider color in (r, g, b, a) or string format. - - :attr:`color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. """ -class MDNavigationDrawerHeader(MDBoxLayout): +class MDNavigationDrawerHeader(DeclarativeBehavior, BoxLayout): """ - Implements a header for a menu for :class:`~MDNavigationDrawer` class. + Implements a header class. - For more information, see in the :class:`~kivymd.uix.boxlayout.MDBoxLayout` - class documentation. + For more information, see in the + :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and + :class:`~kivy.uix.boxlayout.BoxLayout` + classes documentation. .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDNavigationDrawer: - - MDNavigationDrawerMenu: - - MDNavigationDrawerHeader: - title: "Header title" - text: "Header text" - spacing: "4dp" - padding: "12dp", 0, 0, "56dp" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-header.png - :align: center """ - source = StringProperty() - """ - Image logo path. - .. code-block:: kv - - MDNavigationDrawer: - - MDNavigationDrawerMenu: - - MDNavigationDrawerHeader: - title: "Header title" - text: "Header text" - source: "logo.png" - spacing: "4dp" - padding: "12dp", 0, 0, "56dp" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-header-source.png - :align: center - - :attr:`source` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - title = StringProperty() - """ - Title shown in the first line. - - :attr:`title` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - title_halign = StringProperty("left") - """ - Title halign first line. - - :attr:`title_halign` is a :class:`~kivy.properties.StringProperty` - and defaults to `'left'`. - """ - - title_color = ColorProperty(None) - """ - Title text color in (r, g, b, a) or string format. - - :attr:`title_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - title_font_style = StringProperty("H4") - """ - Title shown in the first line. - - :attr:`title_font_style` is a :class:`~kivy.properties.StringProperty` - and defaults to `'H4'`. - """ - - title_font_size = StringProperty("34sp") - """ - Title shown in the first line. - - :attr:`title_font_size` is a :class:`~kivy.properties.StringProperty` - and defaults to `'34sp'`. - """ - - text = StringProperty() - """ - Text shown in the second line. - - :attr:`text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - text_halign = StringProperty("left") - """ - Text halign first line. - - :attr:`text_halign` is a :class:`~kivy.properties.StringProperty` - and defaults to `'left'`. - """ - - text_color = ColorProperty(None) - """ - Title text color in (r, g, b, a) or string format. - - :attr:`text_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `None`. - """ - - text_font_style = StringProperty("H6") - """ - Title shown in the first line. - - :attr:`text_font_style` is a :class:`~kivy.properties.StringProperty` - and defaults to `'H6'`. - """ - - text_font_size = StringProperty("20sp") - """ - Title shown in the first line. - - :attr:`text_font_size` is a :class:`~kivy.properties.StringProperty` - and defaults to `'20sp'`. - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - Clock.schedule_once(self.check_content) - - def check_content(self, interval: Union[int, float]) -> None: - """Removes widgets that the user has not added to the container.""" - - if not self.title: - self.ids.label_box.remove_widget(self.ids.title) - if not self.text: - self.ids.label_box.remove_widget(self.ids.text) - if not self.source: - self.remove_widget(self.ids.logo) - - -class MDNavigationDrawerItem(OneLineAvatarIconListItem, FocusBehavior): +class MDNavigationDrawerItem( + MDListItem, FocusBehavior, BaseNavigationDrawerItem +): """ Implements an item for the :class:`~MDNavigationDrawer` menu list. For more information, see in the - :class:`~kivymd.uix.list.OneLineAvatarIconListItem` and - :class:`~kivymd.uix.behaviors.FocusBehavior` - class documentation. + :class:`~kivymd.uix.list.list.MDListItem` and + :class:`~kivymd.uix.behaviors.focus_behavior.FocusBehavior` and + :class:`~BaseNavigationDrawerItem` + classes documentation. .. versionadded:: 1.0.0 - - .. code-block:: kv - - MDNavigationDrawer: - - MDNavigationDrawerMenu: - - MDNavigationDrawerHeader: - title: "Header title" - text: "Header text" - spacing: "4dp" - padding: "12dp", 0, 0, "56dp" - - MDNavigationDrawerItem - icon: "gmail" - right_text: "+99" - text: "Inbox" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-item.png - :align: center """ - selected = BooleanProperty(False) + active_indicator_color = ColorProperty(None) """ - Is the item selected. + The active indicator color in (r, g, b, a) or string format. - :attr:`selected` is a :class:`~kivy.properties.BooleanProperty` - and defaults to `False`. - """ + .. versionadded:: 2.0.0 - icon = StringProperty() - """ - Icon item. - - :attr:`icon` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - icon_color = ColorProperty(None) - """ - Icon color in (r, g, b, a) or string format item. - - :attr:`icon_color` is a :class:`~kivy.properties.ColorProperty` + :attr:`active_indicator_color` is a :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ - selected_color = ColorProperty([0, 0, 0, 1]) + inactive_indicator_color = ColorProperty(None) """ - The color in (r, g, b, a) or string format of the icon and text of the - selected item. + The inactive indicator color in (r, g, b, a) or string format. - :attr:`selected_color` is a :class:`~kivy.properties.ColorProperty` - and defaults to `[0, 0, 0, 1]`. - """ + .. versionadded:: 2.0.0 - right_text = StringProperty() - """ - Right text item. - - :attr:`right_text` is a :class:`~kivy.properties.StringProperty` - and defaults to `''`. - """ - - text_right_color = ColorProperty(None) - """ - Right text color item in (r, g, b, a) or string format. - - :attr:`text_right_color` is a :class:`~kivy.properties.ColorProperty` + :attr:`inactive_indicator_color` is a :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ - _text_color = None - _text_right_color = None - # kivymd.uix.navigationdrawer.navigationdrawer.MDNavigationDrawerMenu - _drawer_menu = ObjectProperty() + def add_widget(self, widget, *args, **kwargs): + if isinstance( + widget, + ( + MDNavigationDrawerItemLeadingIcon, + MDNavigationDrawerItemText, + MDNavigationDrawerItemTrailingText, + ), + ): + widget._drawer_item = self + return super().add_widget(widget) + + def on_release(self, *args) -> None: + """ + Fired when the item is released + (i.e. the touch/click that pressed the item goes away). + """ + + self.selected = not self.selected + self._drawer_menu.update_items_color(self) + + +class MDNavigationDrawerItemLeadingIcon( + MDListItemLeadingIcon, BaseNavigationDrawerItem +): + """ + Implements the leading icon for the menu list item. + + For more information, see in the + :class:`~kivymd.uix.list.list.MDListItemLeadingIcon` and + :class:`~BaseNavigationDrawerItem` + classes documentation. + + .. versionadded:: 2.0.0 + """ + + +class MDNavigationDrawerItemText( + MDListItemSupportingText, BaseNavigationDrawerItem +): + """ + Implements the text for the menu list item. + + For more information, see in the + :class:`~kivymd.uix.list.list.MDListItemSupportingText` and + :class:`~BaseNavigationDrawerItem` + classes documentation. + + .. versionadded:: 2.0.0 + """ + + +class MDNavigationDrawerItemTrailingText( + MDListItemTrailingSupportingText, BaseNavigationDrawerItem +): + """ + Implements the supporting text for the menu list item. + + For more information, see in the + :class:`~kivymd.uix.list.list.MDListItemTrailingSupportingText` and + :class:`~BaseNavigationDrawerItem` + classes documentation. + + .. versionadded:: 2.0.0 + """ class MDNavigationDrawerMenu(MDScrollView): @@ -1004,63 +833,59 @@ class MDNavigationDrawerMenu(MDScrollView): """ def add_widget(self, widget, *args, **kwargs): - if isinstance(widget, MDList): + if isinstance(widget, GridLayout): return super().add_widget(widget, *args, **kwargs) else: if isinstance(widget, MDNavigationDrawerItem): widget._drawer_menu = self self.ids.menu.add_widget(widget) - def reset_active_color(self, item: MDNavigationDrawerItem) -> None: + def update_items_color(self, item: MDNavigationDrawerItem) -> None: for widget in self.ids.menu.children: if issubclass(widget.__class__, MDNavigationDrawerItem): - if widget != item: - widget.selected = False + if widget is not item: + widget.md_bg_color = ( + widget.theme_cls.surfaceContainerLowColor + if not widget.inactive_indicator_color + else widget.inactive_indicator_color + ) else: - widget.selected = True - - if ( - issubclass(widget.__class__, MDNavigationDrawerItem) - and widget != item - ): - if widget._text_color: - widget.text_color = widget._text_color + widget.md_bg_color = ( + widget.theme_cls.secondaryContainerColor + if not widget.active_indicator_color + else widget.active_indicator_color + ) class MDNavigationDrawer(MDCard): - type = OptionProperty("modal", options=("standard", "modal")) + """ + Navigation drawer class. + + For more information, see in the :class:`~kivymd.uix.card.card.MDCard` + class documentation. + + :Events: + + .. versionadded:: 2.0.0 + + `on_open`: + Fired when the navigation drawer is opened. + `on_close`: + Fired when the navigation drawer is closed. + """ + + drawer_type = OptionProperty("modal", options=("standard", "modal")) """ Type of drawer. Modal type will be on top of screen. Standard type will be at left or right of screen. Also it automatically disables :attr:`close_on_click` and :attr:`enable_swiping` to prevent closing drawer for standard type. - For more information, see in the :class:`~kivymd.uix.card.MDCard` - class documentation. + .. versionchanged:: 2.0.0 - Standard - -------- + Rename from `type` to `drawer_type`. - .. code-block:: kv - - MDNavigationDrawer: - type: "standard" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-standard.gif - :align: center - - Modal - ----- - - .. code-block:: kv - - MDNavigationDrawer: - type: "modal" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-modal.gif - :align: center - - :attr:`type` is a :class:`~kivy.properties.OptionProperty` + :attr:`drawer_type` is a :class:`~kivy.properties.OptionProperty` and defaults to `'modal'`. """ @@ -1069,28 +894,6 @@ class MDNavigationDrawer(MDCard): Anchoring screen edge for drawer. Set it to `'right'` for right-to-left languages. Available options are: `'left'`, `'right'`. - Left - ---- - - .. code-block:: kv - - MDNavigationDrawer: - anchor: "left" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-type-left.png - :align: center - - Right - ----- - - .. code-block:: kv - - MDNavigationDrawer: - anchor: "right" - - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-type-right.png - :align: center - :attr:`anchor` is a :class:`~kivy.properties.OptionProperty` and defaults to `'left'`. """ @@ -1102,20 +905,11 @@ class MDNavigationDrawer(MDCard): multiplied with :attr:`_scrim_alpha`. Set fourth channel to 0 if you want to disable scrim. - .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-scrim-color.png - :align: center - - .. code-block:: kv - - MDNavigationDrawer: - scrim_color: 0, 0, 0, .8 - # scrim_color: 0, 0, 0, .2 - :attr:`scrim_color` is a :class:`~kivy.properties.ColorProperty` and defaults to `[0, 0, 0, 0.5]`. """ - padding = VariableListProperty([16, 16, 12, 16]) + padding = VariableListProperty([dp(16), dp(16), dp(12), dp(16)]) """ Padding between layout box and children: [padding_left, padding_top, padding_right, padding_bottom]. @@ -1128,13 +922,13 @@ class MDNavigationDrawer(MDCard): .. code-block:: kv MDNavigationDrawer: - padding: 56, 56, 12, 16 + padding: "56dp" .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-drawer-padding.png :align: center :attr:`padding` is a :class:`~kivy.properties.VariableListProperty` and - defaults to '[16, 16, 12, 16]'. + defaults to '[dp(16), dp(16), dp(12), dp(16)]'. """ close_on_click = BooleanProperty(True) @@ -1215,7 +1009,7 @@ class MDNavigationDrawer(MDCard): def _get_scrim_alpha(self): _scrim_alpha = 0 - if self.type == "modal": + if self.drawer_type == "modal": _scrim_alpha = self._scrim_alpha_transition(self.open_progress) if ( isinstance(self.parent, MDNavigationLayout) @@ -1288,8 +1082,42 @@ class MDNavigationDrawer(MDCard): and defaults to `0.2`. """ + background_color = ColorProperty(None) + """ + The drawer background color in (r, g, b, a) or string format. + + .. versionadded:: 2.0.0 + + :attr:`background_color` is a :class:`~kivy.properties.ColorProperty` + and defaults to `None`. + """ + + theme_elevation_level = "Custom" + """ + Drawer elevation level scheme name. + + .. versionadded:: 2.0.0 + + Available options are: `'Primary'`, `'Custom'`. + + :attr:`theme_elevation_level` is an :class:`~kivy.properties.OptionProperty` + and defaults to `'Custom'`. + """ + + elevation_level = 1 + """ + Drawer elevation level (values from 0 to 5) + + .. versionadded:: 2.2.0 + + :attr:`elevation_level` is an :class:`~kivy.properties.BoundedNumericProperty` + and defaults to `2`. + """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.register_event_type("on_open") + self.register_event_type("on_close") self.bind( open_progress=self.update_status, status=self.update_status, @@ -1297,6 +1125,9 @@ class MDNavigationDrawer(MDCard): ) Window.bind(on_keyboard=self._handle_keyboard) + def set_properties_widget(self) -> None: + pass + def set_state(self, new_state="toggle", animation=True) -> None: """ Change state of the side panel. @@ -1310,26 +1141,30 @@ class MDNavigationDrawer(MDCard): Animation.cancel_all(self, "open_progress") self.status = "opening_with_animation" if animation: - Animation( + anim = Animation( open_progress=1.0, d=self.opening_time * (1 - self.open_progress), t=self.opening_transition, - ).start(self) + ) + anim.bind(on_complete=self._check_state) + anim.start(self) else: self.open_progress = 1 else: # "close" Animation.cancel_all(self, "open_progress") self.status = "closing_with_animation" if animation: - Animation( + anim = Animation( open_progress=0.0, d=self.closing_time * self.open_progress, t=self.closing_transition, - ).start(self) + ) + anim.bind(on_complete=self._check_state) + anim.start(self) else: self.open_progress = 0 - def update_status(self, *_) -> None: + def update_status(self, *args) -> None: status = self.status if status == "closed": self.state = "close" @@ -1365,7 +1200,7 @@ class MDNavigationDrawer(MDCard): for child in self.children[:]: if child.dispatch("on_touch_down", touch): return True - if self.type == "standard" and not self.collide_point( + if self.drawer_type == "standard" and not self.collide_point( touch.ox, touch.oy ): return False @@ -1412,26 +1247,44 @@ class MDNavigationDrawer(MDCard): touch.ox, touch.oy ): self.set_state("close", animation=True) - elif self.type == "standard" and not self.collide_point( + elif self.drawer_type == "standard" and not self.collide_point( touch.ox, touch.oy ): return False elif self.status == "closed": return False - return True + return super().on_touch_up(touch) def on_radius(self, instance_navigation_drawer, radius_value: list) -> None: + """Fired when the :attr:`radius` value changes.""" + self._radius = radius_value - def on_type(self, instance_navigation_drawer, drawer_type: str) -> None: - if self.type == "standard": + def on_drawer_type( + self, instance_navigation_drawer, drawer_type: str + ) -> None: + """Fired when the :attr:`drawer_type` value changes.""" + + if self.drawer_type == "standard": self.enable_swiping = False self.close_on_click = False else: self.enable_swiping = True self.close_on_click = True + def on_open(self, *args) -> None: + """Fired when the navigation drawer is opened.""" + + def on_close(self, *args) -> None: + """Fired when the navigation drawer is closed.""" + def _handle_keyboard(self, window, key, *largs): if key == 27 and self.status == "opened" and self.close_on_click: self.set_state("close") return True + + def _check_state(self, *args): + if self.state == "open": + self.dispatch("on_open") + elif self.state == "close": + self.dispatch("on_close") diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__init__.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__init__.py index 7d3ff75..9076b4c 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__init__.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__init__.py @@ -2,6 +2,8 @@ from .navigationrail import ( MDNavigationRail, MDNavigationRailFabButton, + MDNavigationRailItemIcon, + MDNavigationRailItemLabel, MDNavigationRailItem, MDNavigationRailMenuButton, ) diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc index d216bbf..0c4e8e3 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/__init__.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc index d109f17..85ca0cc 100644 Binary files a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc and b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/__pycache__/navigationrail.cpython-311.pyc differ diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.kv b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.kv index e2623bb..712afdb 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.kv +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.kv @@ -1,157 +1,109 @@ - pos_hint: {"center_x": .5, "top": 1} + pos_hint: {"center_x": .5} + theme_icon_color: "Custom" + icon_color: self.theme_cls.onSurfaceVariantColor type: "standard" pos_hint: {"center_x": .5} - - - - size_hint: None, 1 - width: "80dp" - - PanelRoot: - id: box_buttons - - PanelItems: - id: box_items - orientation: "vertical" - spacing: "12dp" - adaptive_size: True - pos_hint: {"center_x": .5} + theme_bg_color: "Custom" + md_bg_color: self.theme_cls.primaryColor + theme_icon_color: "Custom" + icon_color: self.theme_cls.onPrimaryColor orientation: "vertical" size_hint: None, None - size: self.navigation_rail.width if self.navigation_rail else 100, "56dp" + width: "80dp" + height: self.minimum_height + spacing: + ( \ + { \ + "selected": "8dp", \ + "labeled": "16dp", \ + "unselected": "16dp", \ + }[self._navigation_rail.type] \ + ) \ + if self._navigation_rail else 0 - RelativeLayout: - id: container + + + canvas.before: + Color: + rgba: + ( \ + ( \ + self.theme_cls.secondaryContainerColor \ + if not self.active_indicator_color else \ + self.active_indicator_color \ + )[:-1] + [self._alpha] \ + ) \ + if self._layer_color == self.theme_cls.transparentColor else \ + self._layer_color + RoundedRectangle: + group: "navigation-rail-rounded-rectangle" + radius: + ( \ + [ \ + ( \ + dp(16) \ + if self._navigation_rail.type != "unselected" else \ + dp(28) \ + ), \ + ] \ + ) \ + if self._navigation_rail else [0, ] + pos: + self.center_x - self._selected_region_width / 2, \ + ( \ + self.y \ + - ( \ + dp(4) \ + if self._navigation_rail.type != "unselected" else \ + dp(16) \ + ) \ + ) \ + if self._navigation_rail else 0 + size: + self._selected_region_width, \ + ( \ + self.height \ + + ( \ + dp(8) \ + if self._navigation_rail.type != "unselected" else \ + self.width + dp(8)\ + ) \ + ) \ + if self._navigation_rail else 0 + + pos_hint: {"center_x": .5} + + + + size_hint_y: None + height: 0 + halign: "center" + text_color: self.theme_cls.onSurfaceVariantColor + font_style: "Label" + role: "medium" + + + + size_hint: None, 1 + width: "80dp" + md_bg_color: self.theme_cls.surfaceColor + + BoxLayout: + id: box_items + orientation: "vertical" size_hint: None, None - size: root.size - - RippleWidget: - id: ripple_widget - size_hint: None, None - size: (container.width, container.width) - radius: container.width / 2 - scale_value_x: 0 - scale_value_y: 0 - scale_value_z: 0 - opacity: 0 - md_bg_color: - root.navigation_rail.ripple_color_item \ - if root.navigation_rail and \ - root.navigation_rail.ripple_color_item else \ - app.theme_cls.primary_color - - MDIcon: - id: icon - icon: root.icon - opposite_colors: root.opposite_colors - font_size: "24sp" - pos_hint: {"center_x": .5} - badge_icon: root.badge_icon - badge_font_size: root.badge_font_size - badge_icon_color: - root.badge_icon_color \ - if root.badge_icon_color else \ - (1, 1, 1, 1) - badge_bg_color: - root.badge_bg_color \ - if root.badge_bg_color else \ - app.theme_cls.error_color - theme_text_color: "Custom" - text_color: - ( \ - root.navigation_rail.icon_color_item_normal \ - if root.navigation_rail \ - and root.navigation_rail.icon_color_item_normal else \ - app.theme_cls.text_color \ - ) \ - if not root.active else \ - ( \ - root.navigation_rail.icon_color_item_active \ - if root.navigation_rail.icon_color_item_active else \ - app.theme_cls.text_color \ - ) - y: - container.height - \ - ( \ - (self.height + dp(4)) \ - if root.navigation_rail and \ - root.navigation_rail.type == "unselected" else \ - (self.height - dp(8)) \ - ) - - canvas.before: - Color: - rgba: - ( \ - ( \ - ( \ - app.theme_cls.primary_color \ - if not root.navigation_rail.selected_color_background else \ - root.navigation_rail.selected_color_background \ - ) \ - if root._release else \ - (0, 0, 0, 0) \ - ) \ - ) \ - if root.active else \ - (0, 0, 0, 0) - RoundedRectangle: - radius: - [root._selected_region_width / 2,] \ - if root.navigation_rail and \ - root.navigation_rail.type == "unselected" else \ - [root._selected_region_width / 4,] - size: - root._selected_region_width, \ - root._selected_region_width \ - if root.navigation_rail and \ - root.navigation_rail.type == "unselected" else \ - root._selected_region_width / 2 - pos: - self.center_x - self.width - dp(4), \ - self.center_y - root._selected_region_width / 2 \ - if root.navigation_rail and \ - root.navigation_rail.type == "unselected" else \ - self.center_y - root._selected_region_width / 4 - - MDLabel: - id: label - text: root.text - size_hint_x: None - text_size: None, root.height - adaptive_height: True - opposite_colors: root.opposite_colors - pos_hint: {"center_x": .5} - y: "16" - font_style: "Body2" - theme_text_color: "Custom" - font_name: - root.navigation_rail.font_name \ - if root.navigation_rail else \ - "Roboto" - text_color: - ( \ - root.navigation_rail.text_color_item_normal \ - if root.navigation_rail and \ - root.navigation_rail.text_color_item_normal else \ - app.theme_cls.text_color \ - ) \ - if not root.active else \ - ( \ - root.navigation_rail.text_color_item_active \ - if root.navigation_rail.text_color_item_active else \ - app.theme_cls.text_color \ - ) - opacity: - (0 if root.navigation_rail and \ - root.navigation_rail.type == "unselected" else 1) \ - if root.navigation_rail and \ - root.navigation_rail.type != "selected" else \ - (0 if not root.active else 1) + size: self.minimum_size + pos_hint: {"center_x": .5} + spacing: + { \ + "selected": "12dp", \ + "labeled": "24dp", \ + "unselected": "36dp", \ + }[root.type] diff --git a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.py b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.py index 762c74d..b4e7dad 100644 --- a/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.py +++ b/kivy_venv/lib/python3.11/site-packages/kivymd/uix/navigationrail/navigationrail.py @@ -6,16 +6,19 @@ Components/NavigationRail .. seealso:: - `Material Design spec, Navigation rail `_ - -.. rubric:: Navigation rails provide access to primary destinations in apps - when using tablet and desktop screens. + `Material Design spec, Navigation rail