# -*- coding: utf-8 -*-
from setuptools import setup

package_dir = \
{'': 'src'}

packages = \
['textual',
 'textual.drivers',
 'textual.layouts',
 'textual.views',
 'textual.widgets']

package_data = \
{'': ['*']}

install_requires = \
['rich>=12.0.0,<13.0.0']

extras_require = \
{':python_version < "3.8"': ['typing-extensions>=3.10.0,<4.0.0']}

setup_kwargs = {
    'name': 'textual',
    'version': '0.1.17',
    'description': 'Text User Interface using Rich',
    'long_description': '# Textual\n\n![screenshot](./imgs/textual.png)\n\nTextual is a TUI (Text User Interface) framework for Python inspired by modern web development. Currently a **Work in Progress**.\n\n\n> ⚠ **NOTE:** We ([Textualize.io](https://www.textualize.io)) are hard at work on the **css** branch. We will maintain the 0.1.0 branch for the near future but may not be able to accept API changes. If you would like to contribute code via a PR, please raise a discussion first, to avoid disapointment.\n\n\nFollow [@willmcgugan](https://twitter.com/willmcgugan) for progress updates, or post in Discussions if you have any requests / suggestions.\n\n[![Join the chat at https://gitter.im/textual-ui/community](https://badges.gitter.im/textual-ui/community.svg)](https://gitter.im/textual-ui/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\n## Compatibility\n\nTextual currently runs on **MacOS / Linux / Window**.\n\n## How it works\n\nTextual uses [Rich](https://github.com/willmcgugan/rich) to render rich text, so anything that Rich can render may be used in Textual.\n\nEvent handling in Textual is asynchronous (using `async` and `await` keywords). Widgets (UI components) can independently update and communicate with each other via message passing.\n\nTextual has more in common with modern web development than it does with [curses](<https://en.wikipedia.org/wiki/Curses_(programming_library)>); layout is done with CSS grid and (soon) the theme may be customized with CSS. Other techniques are borrowed from JS frameworks such as Vue and React.\n\n## Installation\n\nYou can install Textual via pip (`pip install textual`), or by checking out the repo and installing with [poetry](https://python-poetry.org/docs/).\n\n```\npoetry install\n```\n\nOnce installed you can run the following command for a quick test, or see examples (below):\n\n```\npython -m textual.app\n```\n\nTextual requires Python 3.7 or above.\n\n## Examples\n\nUntil I\'ve written the documentation, the [examples](https://github.com/willmcgugan/textual/tree/main/examples/) may be the best way to learn Textual.\n\nYou can see some of these examples in action in the [Developer Video Log](#developer-video-log).\n\n- [animation.py](https://github.com/willmcgugan/textual/tree/main/examples/animation.py) Demonstration of 60fps animation easing function\n- [calculator.py](https://github.com/willmcgugan/textual/tree/main/examples/calculator.py) A "clone" of the MacOS calculator using Grid layout\n- [code_viewer.py](https://github.com/willmcgugan/textual/tree/main/examples/code_viewer.py) A demonstration of a tree view which loads syntax highlighted code\n- [grid.py](https://github.com/willmcgugan/textual/tree/main/examples/grid.py) A simple demonstration of adding widgets in a Grid layout\n- [grid_auto.py](https://github.com/willmcgugan/textual/tree/main/examples/grid_auto.py) A demonstration of automatic Grid layout\n- [simple.py](https://github.com/willmcgugan/textual/tree/main/examples/simple.py) A very simple Textual app with scrolling Markdown view\n\n## Building Textual applications\n\n_This guide is a work in progress_\n\nLet\'s look at the simplest Textual app which does _something_:\n\n```python\nfrom textual.app import App\n\n\nclass Beeper(App):\n    def on_key(self):\n        self.console.bell()\n\n\nBeeper.run()\n```\n\nHere we can see a textual app with a single `on_key` method which will handle key events. Pressing any key will result in playing the terminal bell (generally an irritating beep). Hit Ctrl+C to exit.\n\nEvent handlers in Textual are defined by convention, not by inheritance (there\'s no base class with all the handlers defined). Each event has a `name` attribute which for the key event is simply `"key"`. Textual will call the method named `on_<event.name>` if it exists.\n\nLet\'s look at a _slightly_ more interesting example:\n\n```python\nfrom textual.app import App\n\n\nclass ColorChanger(App):\n    def on_key(self, event):\n        if event.key.isdigit():\n            self.background = f"on color({event.key})"\n\n\nColorChanger.run(log="textual.log")\n```\n\nYou\'ll notice that the `on_key` method above contains an additional `event` parameter which wasn\'t present on the beeper example. If the `event` argument is present, Textual will call the handler with an event object. Every event has an associated handler object, in this case it is a KeyEvent which contains additional information regarding which key was pressed.\n\nThe key event handler above will set the background attribute if you press the keys 0-9, which turns the terminal to the corresponding [ansi color](https://rich.readthedocs.io/en/latest/appendix/colors.html).\n\nNote that we didn\'t need to explicitly refresh the screen or draw anything. Setting the `background` attribute to a [Rich style](https://rich.readthedocs.io/en/latest/style.html) is enough for Textual to update the visuals. This is an example of _reactivity_ in Textual. To make changes to the terminal interface you modify the _state_ and let Textual update the UI.\n\n## Widgets\n\nTo make more interesting apps you will need to make use of _widgets_, which are independent user interface elements. Textual comes with a (growing) library of widgets, but you can develop your own.\n\nLet\'s look at an app which contains widgets. We will be using the built-in `Placeholder` widget which you can use to design application layouts before you implement the real content.\n\n```python\nfrom textual.app import App\nfrom textual.widgets import Placeholder\n\n\nclass SimpleApp(App):\n\n    async def on_mount(self) -> None:\n        await self.view.dock(Placeholder(), edge="left", size=40)\n        await self.view.dock(Placeholder(), Placeholder(), edge="top")\n\n\nSimpleApp.run(log="textual.log")\n```\n\nThis app contains a single event handler `on_mount`. The mount event is sent when the app or widget is ready to start processing events, and is typically used for initialization. You may have noticed that `on_mount` is an `async` function. Since Textual is an asynchronous framework we will need this if we need to call most other methods.\n\nThe `on_mount` method makes two calls to `self.view.dock` which adds widgets to the terminal.\n\nHere\'s the first line in the mount handler:\n\n```python\nawait self.view.dock(Placeholder(), edge="left", size=40)\n```\n\nNote this method is asynchronous like almost all API methods in Textual. We are awaiting `self.view.dock` which takes a newly constructed Placeholder widget, and docks it on to the `"left"` edge of the terminal with a size of 40 characters. In a real app you might use this to display a side-bar.\n\nThe following line is similar:\n\n```python\nawait self.view.dock(Placeholder(), Placeholder(), edge="top")\n```\n\nYou will notice that this time we are docking _two_ Placeholder objects onto the `"top"` edge. We haven\'t set an explicit size this time so Textual will divide the remaining size amongst the two new widgets.\n\nThe last line calls the `run` class method in the usual way, but with an argument we haven\'t seen before: `log="textual.log"` tells Textual to write log information to the given file. You can tail textual.log to see events being processed and other debug information.\n\nIf you run the above example, you will see something like the following:\n\n![widgets](./imgs/widgets.png)\n\nIf you move the mouse over the terminal you will notice that widgets receive mouse events. You can click any of the placeholders to give it input focus.\n\nThe dock layout feature is very flexible, but for more sophisticated layouts we can use the grid API. See the [calculator.py](https://github.com/willmcgugan/textual/blob/main/examples/calculator.py) example which makes use of Grid.\n\n### Creating Widgets\n\nYou can create your own widgets by subclassing the `textual.widget.Widget` class and implementing a `render()` method which should return anything that can be rendered with [Rich](https://rich.readthedocs.io/en/latest/introduction.html), including a plain string which will be interpreted as [console markup](https://rich.readthedocs.io/en/latest/markup.html).\n\nLet\'s look at an example with a custom widget:\n\n```python\nfrom rich.panel import Panel\n\nfrom textual.app import App\nfrom textual.reactive import Reactive\nfrom textual.widget import Widget\n\n\nclass Hover(Widget):\n\n    mouse_over = Reactive(False)\n\n    def render(self) -> Panel:\n        return Panel("Hello [b]World[/b]", style=("on red" if self.mouse_over else ""))\n\n    def on_enter(self) -> None:\n        self.mouse_over = True\n\n    def on_leave(self) -> None:\n        self.mouse_over = False\n\n\nclass HoverApp(App):\n    """Demonstrates custom widgets"""\n\n    async def on_mount(self) -> None:\n        hovers = (Hover() for _ in range(10))\n        await self.view.dock(*hovers, edge="top")\n\n\nHoverApp.run(log="textual.log")\n```\n\nThe `Hover` class is a custom widget which displays a panel containing the classic text "Hello World". The first line in the Hover class may seem a little mysterious at this point:\n\n```python\nmouse_over = Reactive(False)\n```\n\nThis adds a `mouse_over` attribute to your class which is a bool with a default of `False`. Adding attributes like this makes them _reactive_: any changes will result in the widget updating.\n\nThe following `render()` method is where you define how the widget should be displayed. In the Hover widget we return a [Panel](https://rich.readthedocs.io/en/latest/panel.html) containing rich text with a background that changes depending on the value of `mouse_over`. The goal here is to add a mouse hover effect to the widget, which we can achieve by handling two events: `Enter` and `Leave`. These events are sent when the mouse enters or leaves the widget.\n\nHere are the two event handlers again:\n\n```python\n    def on_enter(self) -> None:\n        self.mouse_over = True\n\n    def on_leave(self) -> None:\n        self.mouse_over = False\n```\n\nBoth event handlers set the `mouse_over` attribute which will result in the widget\'s `render()` method being called.\n\nThe `HoverApp` has a `on_mount` handler which creates 10 Hover widgets and docks them on the top edge to create a vertical stack:\n\n```python\n    async def on_mount(self) -> None:\n        hovers = (Hover() for _ in range(10))\n        await self.view.dock(*hovers, edge="top")\n```\n\nIf you run this script you will see something like the following:\n\n![widgets](./imgs/custom.gif)\n\nIf you move your mouse over the terminal you should see that the widget under the mouse cursor changes to a red background.\n\n### Actions and key bindings\n\nActions in Textual are white-listed functions that may be bound to keys. Let\'s look at a trivial example of binding a key to an action. Here is an app which exits when we hit the Q key:\n\n```python\nfrom textual.app import App\n\n\nclass Quitter(App):\n    async def on_load(self, event):\n        await self.bind("q", "quit")\n\n\nQuitter.run()\n```\n\nIf you run this you will get a blank terminal which will return to the prompt when you press Q.\n\nBinding is done in the Load event handler. The `bind` method takes the key (in this case "q") and binds it to an action ("quit"). The quit action is built in to Textual and simply exits the app.\n\nTo define your own actions, add a method that begins with `action_`, which may take parameters. Let\'s create a simple action that changes the color of the terminal and binds keys to it:\n\n```python\nfrom textual.app import App\n\n\nclass Colorizer(App):\n\n    async def on_load(self, event):\n        await self.bind("r", "color(\'red\')")\n        await self.bind("g", "color(\'green\')")\n        await self.bind("b", "color(\'blue\')")\n\n    async def action_color(self, color:str) -> None:\n        self.background = f"on {color}"\n\n\nColorizer.run()\n```\n\nIf you run this app you can hit the keys R, G, or B to change the color of the background.\n\nIn the `on_load` method we have bound the keys R, G, and B to the `color` action with a single parameter. When you press any of these three keys Textual will call the method `action_color` with the appropriate parameter.\n\nYou could be forgiven for thinking that `"color(\'red\')"` is Python code which Textual evaluates. This is not the case. The action strings are parsed and may not include expressions or arbitrary code. The reason that strings are used over a callable is that (in a future update) key bindings may be loaded from a configuration file.\n\n### More on Events\n\n_TODO_\n\n### Watchers\n\n_TODO_\n\n### Animation\n\n_TODO_\n\n### Timers and Intervals\n\nTextual has a `set_timer` and a `set_interval` method which work much like their Javascript counterparts. The `set_timer` method will invoke a callable after a given period of time, and `set_interval` will invoke a callable repeatedly. Unlike Javascript these methods expect the time to be in seconds (_not_ milliseconds).\n\nLet\'s create a simple terminal based clock with the `set_interval` method:\n\n```python\nfrom datetime import datetime\n\nfrom rich.align import Align\n\nfrom textual.app import App\nfrom textual.widget import Widget\n\n\nclass Clock(Widget):\n    def on_mount(self):\n        self.set_interval(1, self.refresh)\n\n    def render(self):\n        time = datetime.now().strftime("%c")\n        return Align.center(time, vertical="middle")\n\n\nclass ClockApp(App):\n    async def on_mount(self):\n        await self.view.dock(Clock())\n\n\nClockApp.run()\n\n```\n\nIf you run this app you will see the current time in the center of the terminal until you hit Ctrl+C.\n\nThe Clock widget displays the time using [rich.align.Align](https://rich.readthedocs.io/en/latest/reference/align.html) to position it in the center. In the clock\'s Mount handler there is the following call to `set_interval`:\n\n```python\nself.set_interval(1, self.refresh)\n```\n\nThis tells Textual to call a function (in this case `self.refresh` which updates the widget) once a second. When a widget is refreshed it calls `Clock.render` again to display the latest time.\n\n## Developer Video Log\n\nSince Textual is a visual medium, I\'ll be documenting new features and milestones here.\n\n### Update 1 - Basic scrolling\n\n[![Textual update 1](https://yt-embed.herokuapp.com/embed?v=zNW7U36GHlU&img=0)](http://www.youtube.com/watch?v=zNW7U36GHlU)\n\n### Update 2 - Keyboard toggle\n\n[![Textual update 2](https://yt-embed.herokuapp.com/embed?v=bTYeFOVNXDI&img=0)](http://www.youtube.com/watch?v=bTYeFOVNXDI)\n\n### Update 3 - New scrollbars and smooth scrolling\n\n[![Textual update 3](https://yt-embed.herokuapp.com/embed?v=4LVl3ClrXIs&img=0)](http://www.youtube.com/watch?v=4LVl3ClrXIs)\n\n### Update 4 - Animation system with easing function\n\nNow with a system to animate changes to values, going from the initial to the final value in small increments over time . Here applied to the scroll position. The animation system supports CSS like _easing functions_. You may be able to tell from the video that the page up / down keys cause the window to first speed up and then slow down.\n\n[![Textual update 4](https://yt-embed.herokuapp.com/embed?v=k2VwOp1YbSk&img=0)](http://www.youtube.com/watch?v=k2VwOp1YbSk)\n\n### Update 5 - New Layout system\n\nA new update system allows for overlapping layers. Animation is now synchronized with the display which makes it very smooth!\n\n[![Textual update 5](https://yt-embed.herokuapp.com/embed?v=XxRnfx2WYRw&img=0)](http://www.youtube.com/watch?v=XxRnfx2WYRw)\n\n### Update 6 - New Layout API\n\nNew version (0.1.4) with API updates and the new layout system.\n\n[![Textual update 6](https://yt-embed.herokuapp.com/embed?v=jddccDuVd3E&img=0)](http://www.youtube.com/watch?v=jddccDuVd3E)\n\n### Update 7 - New Grid Layout\n\n**11 July 2021**\n\nAdded a new layout system modelled on CSS grid. The example demonstrates how once created a grid will adapt to the available space.\n\n[![Textual update 7](https://yt-embed.herokuapp.com/embed?v=Zh9CEvu73jc&img=0)](http://www.youtube.com/watch?v=Zh9CEvu73jc)\n\n## Update 8 - Tree control and scroll views\n\n**6 Aug 2021**\n\nAdded a tree control and refactored the renderer to allow for widgets within a scrollable view\n\n[![Textual update 8](https://yt-embed.herokuapp.com/embed?v=J-dzzD6NQJ4&img=0)](http://www.youtube.com/watch?v=J-dzzD6NQJ4)\n',
    'author': 'Will McGugan',
    'author_email': 'willmcgugan@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/willmcgugan/textual',
    'package_dir': package_dir,
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
