Commit Graph

476 Commits

Author SHA1 Message Date
Rodrigo Girão Serrão
639d8f0250 Change default 'overflow' style for 'Horizontal'.
Related issues: #1957.
2023-03-09 15:30:44 +00:00
Rodrigo Girão Serrão
e111449856 Add container 'Middle'.
Related issues: #1957.
2023-03-09 15:24:13 +00:00
Rodrigo Girão Serrão
f91750ed3d Add container 'Center'.
This container will centre children horizontally.

Related issues: #1957.
2023-03-09 15:21:20 +00:00
Rodrigo Girão Serrão
be41797a8d Merge branch 'main' into add-containers 2023-03-09 15:19:43 +00:00
Will McGugan
e2d88572c2 changelog 2023-03-09 14:53:39 +00:00
Will McGugan
1f1222b1ce Version 0.14.0 release and blog (#2004)
* new release, and blog

* Edit copy
2023-03-09 14:53:10 +00:00
Rodrigo Girão Serrão
90dce06eae Add 'HorizontalScroll'.
Related issues: #1957.
2023-03-09 14:35:49 +00:00
Will McGugan
f61a50b790 prevent stuck scrollbar (#2003)
* prevent stuck scrollbar

* update changelog

* remove debug

* remove debug
2023-03-09 14:13:12 +00:00
darrenburns
f929e133b2 Generate MouseUp events (#1968)
* Remove redundant import

* Generate a MouseUp event when dragging stops

* Update CHANGELOG.md

* Ensure button is propagated through to artificial MouseUp event
2023-03-09 11:56:38 +00:00
Dave Pearson
97a5478bd0 Add ContentSwitcher (#1983)
* Add the basic ContentSwitcher widget

* Docstring tidy

* Add a visible_content property to the ContentSwitcher

* Clarify that children of ContentSwitcher with no IDs get ignored

* Simplify setting the display value

* Add the start of an example ContentSwitcher for the docs

* Tweak the example layout to better fit in small spaces

* Add the content switcher to the API docs

* Add a guide entry for the ContentSwitcher

This one is a wee bit more involved than most other widget entries in the
guide in that it doesn't obviously do anything itself, but needs
developer-input to make it do something useful. As such the outline here
isn't as clean as it could be, but I think it conveys everything necessary
without getting too complicated.

* Add the reactive attribute table to the ContentSwitcher guide

* Update the README

* Add a refresh after everything has been flipped in the switcher

As noted in the code, this should not be necessary and I don't believe it
has anything to do with this code. I would suspect some lower-level issue
with flipping between different widgets within a container. I need to find a
way to make an isolated reproduction that isn't about this particular
widget. Meanwhile though this works with the refresh().

* Swap current from var to reactive

This solves the explicit refresh issue, but only because the refresh is
implied due to the use of a reactive over a var. As such this sort of
addresses #1979 by ignoring the issue rather than diving into it.

I still suspect that I shouldn't need to do this, and that perhaps there's a
refresh issue when you flip display. So I'll keep #1979 kicking around and
at some point see if I can recreate in isolation.

* Add unit tests for the content switcher

* Add snapshot tests for the ContentSwitcher

* Clarify that an exception can be thrown on a bad ID

* Try and help other Pythons

* Add a pause at the end of the second switcher snapshot test

I'm getting a lot of fails in CI; none of them are actual problems.
Hopefully this will cure it.

* Paaaaaaaaause

More of a test than anything else really. My particular snapshot test is
failing but kinda randomly in each environment each time -- sometimes
Windows, sometimes GNU/Linux, different Python versions.

So... yeah, let's try this and see if it makes it through; otherwise I may
need to rethink this.

* New pause

So it turns out that _ doesn't do anything any more; and instead there's a
"wait:<n>" syntax! So let's give that a try.

* Learning my alphabet...

* Fix a typo in the docs.

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* Add missing full stop.

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* Add a missing word

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* Try a longer wait on the switcher

I'm starting to suspect that this doesn't come down to a timing issue;
especially given that the snapshot report seems to be showing some oddity in
the length of the vertical scrollbar. But... I want to be as sure as
possible so let's double the length of the wait.

Bit a bit of me is starting to wonder if I've somehow managed to create the
perfect storm for scrollbars and you don't always get the same result every
time.

Seems unlikely, but if it's not timing it's that or lots of cosmic rays.

* Test a longer pause on the content switcher test

The idea here being that it takes 200ms for the button to pop again.

* Refresh the snapshots

This time. THIS TIME!

* Experiment: is the issue the same name for two tests?

* Experiment: drop the different source files, try terminal size

Having got over the issue of the button not ending up in the same state,
we're stuck with the scrollbar having different sizes. Having tried other
options let's go with tweaking the terminal size.

* Do a little less work when changing current

Rather than set everything invisible then the new one visible, every time
current is changed, instead just make sure everything is invisible up front
and then just swap the affected children each time.

This does mean that if someone messes with the children under the hood they
may see oddness happening, but less work while being less defensive seems
fair here.

---------

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
2023-03-09 11:39:30 +00:00
Dave Pearson
a5695edcb5 Swap out the primary Markdown bullet for one that works everywhere (#1997)
* Swap out the primary Markdown bullet for one that works everywhere

The primary bullet wasn't displaying well on Windows in the Windows
terminal.

* Refresh the snapshot tests

Imagine that, changing how something looks needs that the snapshot tests get
updated. *facepalm*
2023-03-09 11:38:58 +00:00
Rodrigo Girão Serrão
8565d3cef6 Renamed 'Vertical' to 'VerticalScroll'.
Related issues: #1957.
2023-03-08 18:31:24 +00:00
darrenburns
2ed72e1710 DataTable - fix crash when selection made in empty table (#1973) 2023-03-07 20:58:28 +00:00
darrenburns
b366d1d49c Pilot - add hover and click methods (#1966)
* Delete redundant test file

* Sketch out pilot API improvements - signatures/docstrings

* Pilot click and hover

* Updating test to use new pilot hover method for DataTable

* hover and click methods for Pilot

* Update changelog

* Add docstring
2023-03-07 15:19:23 +00:00
Dave Pearson
b7de48cca3 Border colour percentage (#1954)
* Allow setting an additional alpha on a border

See #1863.

* Update the ChangeLog

* Add snapshot tests for the border alpha value

* Extend the border snapshot tests

While this doesn't test *every* permutation, it covers enough bases that if
something were to change it should catch it.

* Tweak a typo in the border style examples

* Add border transparency percentage to the border docs

* Add a CSS example for using border transparency

* Add Color.multiply_alpha

* Update the CHANGELOG

* Multiply the alpha on a colour rather than replace it

As requested in
https://github.com/Textualize/textual/pull/1954#pullrequestreview-1328170386

(actually required while talking in person with Will, but noted in the
above)

* Multiply the alpha on a border colour rather than replace it

As requested in
https://github.com/Textualize/textual/pull/1954#pullrequestreview-1328170386

(actually requested while talking in person with Will, but noted in the
above)
2023-03-07 14:14:17 +00:00
darrenburns
1b06e50f10 Fix for DataTable race-condition crash (#1962)
* Fix for DataTable race-condition crash

* Update CHANGELOG.md
2023-03-07 13:01:06 +00:00
Will McGugan
864931e94b Compound docs (#1952)
* compound example

* update bit switch

* prevent

* no css

* compound widget example

* more diagrams

* more diagrams

* diagrams

* words

* words

* remove sender

* removed priority post

* timer fix

* test fixes

* drop async version of post_message

* extended docs

* fix no app

* Added control properties

* changelog

* changelog

* changelog

* fix for stopping timers

* changelog

* docs update

* last byte example

* new section

* update of byte03

* updae to docs

* Added compound examples

* Rewording

* Use set sender

* don't need this

* hyphens

* Update docs/guide/widgets.md

Co-authored-by: Dave Pearson <davep@davep.org>

* Update docs/guide/widgets.md

Co-authored-by: Dave Pearson <davep@davep.org>

* Update docs/guide/widgets.md

Co-authored-by: Dave Pearson <davep@davep.org>

* Update docs/guide/widgets.md

Co-authored-by: Dave Pearson <davep@davep.org>

* Update docs/guide/widgets.md

Co-authored-by: Dave Pearson <davep@davep.org>

* Update docs/guide/widgets.md

Co-authored-by: Dave Pearson <davep@davep.org>

* Update docs/guide/widgets.md

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* Update docs/guide/widgets.md

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* Update docs/guide/widgets.md

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* Update docs/guide/widgets.md

Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>

* parenthesis

* stack diagram

---------

Co-authored-by: Dave Pearson <davep@davep.org>
Co-authored-by: Rodrigo Girão Serrão <5621605+rodrigogiraoserrao@users.noreply.github.com>
2023-03-06 16:56:24 +00:00
darrenburns
fd0e0d9983 Datatable extend background (#1946)
* Extending DataTable widget horizontally

* Fading background of extended DataTable rows

* Updating DataTable snapshots

* Update CHANGELOG.md

---------

Co-authored-by: Will McGugan <willmcgugan@gmail.com>
2023-03-06 16:27:29 +00:00
Dave Pearson
286293b810 Update the ChangeLog 2023-03-06 13:54:58 +00:00
Rodrigo Girão Serrão
6c27bcfc33 Update changelog. 2023-03-06 11:07:10 +00:00
Will McGugan
373fc95fc1 Drop explicit sender attribute from messages (#1940)
* remove sender

* removed priority post

* timer fix

* test fixes

* drop async version of post_message

* extended docs

* fix no app

* Added control properties

* changelog

* changelog

* changelog

* fix for stopping timers

* changelog

* added aliases to radio and checkbox

* Drop sender from Message init

* drop time

* drop cast

* Added aliases
2023-03-06 10:52:34 +00:00
Will McGugan
203b31d30d fix date 2023-03-02 15:27:23 +00:00
Will McGugan
55fc89cf14 changelog 2023-03-02 14:51:59 +00:00
Will McGugan
2bf3ed1fea version bump (#1923) 2023-03-02 14:50:21 +00:00
Will McGugan
41003e356c Fix content width (#1910)
* fix calculation for scrollbars

* added snapshot

* fix for name change

* snapshot

* fix for textual colors

* remove logs

* scrollbar logic

* scroll logic

* remove dead code

* snapshot tests

* scrollbar mechanism

* tidy

* demo tweak

* preset window size

* no need for repaint

* Restore repaint

* wait for idle on pause

* colors tweak

* remove wait for idle

* snapshot

* small sleep

* change stabilizer

* debug tweaks

* remove debug

* remove debug

* snapshot test

* docstring

* changelog

* add pause
2023-03-02 14:39:31 +00:00
Rodrigo Girão Serrão
ed28a7019c Make mypy happy (#1831)
* Helper file for error progress tracking.

* Fix typing of Keys.???.value.

* Assert that we have frame information.

@willmcgugan I went with the asserts because the tone of the code tells me that we are kind of certain that the current and previous frames always exist. Should the function be refactored to handle None for the previous frame (or the current & previous frames) by writing to the buffer without caller information, for example?

* Use inspect.Traceback instead of inspect.FrameInfo.

Looks like the two shared a lot of attributes, so we were trying to use FrameInfo but inspect.getframeinfo returns a Traceback, so that felt like the correct type to use.

* Update after installing msgpack-types.

* Assert we have frame info.

Same fix as in b709219.

* Fix MapGeometry order information typing.

There was another alternative solution, which was to just flatten everything entirely, so that the code actually obeyed the comments.
After all, the comments for the attribute `order` in the definition of `MapGeometry` said that `order` was a tuple of integers defining the painting order, which was not true because the very first widget was having its order defined as `order = ((0,),)` instead of `order = (0,)`.
Thus, another possible solution would be to retype `order` as `tuple[int, ...]` and make everything flat, but I opted for the “tuple of tuples” approach because the sub-tuples will highlight the nested structure of the DOM hierarchy.

* Fix import and typing for fromkeys.

* Assert app is not None.

[skip cli]

* Import missing type.

* Use CallbackType for event Callback.

* Remove variable name clash.

* Ensure ScalarAnimation only receives widgets.

Two other alternatives would be:
 - leave typing of 'widget: DOMNode' and then assert 'widget' is actually of type 'Widget', which works just fine but looks weird in the sense that we type a parameter in one way but then only manage to do any work if it is of another type;
 - type it as 'widget: DOMNode | Widget' and set 'size' to something other than 'widget.outer_size' if 'widget' is a 'DOMNode'.

* Count spacing values as 1 for int instance.

Adding an 'assert not isinstance(spacing, int)' before raising the error sounds reasonable, because 'Spacing.unpack' seems to be able to handle a lone integer just fine, but I decided against it because I would not like to raise an assertion error from within an exception handling inside Textual.
So, to keep it on the safer side, I went with the conditional expression that checks if we have an integer or a tuple.

* Use correct default.

The obvious fix would be to do 'default_factory=RulesMap' but mypy will infer that the type of 'RulesMap' is 'type[RulesMap]' and will not see it as a 'Callable[[], RulesMap]'. That could be fixed by using 'cast'. I decided to use 'RulesMap.__call__'.

[skip ci]

* Use correct abstract methods.

We fix the LSP violation by using the abstract methods that the ABC already provides... Which is a shame, because I thought I was about to write my first Protocol.

* Add missing annotation.

* Fix type inference.

* Check token is not None.

* Revert "Check token is not None."

This reverts commit 0ae463366e.
Upon closer look, this is not the correct fix.

* Check that token is not None.

Checking if the token is not 'None' brings us a tiny step closer to fixing #1849, which still needs to ensure the variable definition is complete and valid, even if empty.

* Type DOMQuery instantiation correctly.

After some fiddling, some crying, and talking to Dave and Will, we got to a partial solution.
I cried a bit more and came up with the fix that entailed lifting 'ExpectType' to outside of 'DOMNode'.
Then, I realised 'ExpectType' and 'QueryType' from 'query.py' were essentially the same thing so I decided to only make use of 'QueryType'.

* Infer correct type while walking.

* Cast to remove doubt about None.

mypy can't infer that if after is None, then before won't.

* Explicitly type variable.

* Cast to console renderable.

@willmcgugan did I understand correctly that this 'cast' is exactly what renderable being possibly a 'RichCast' asks me to do..? To be honest, I was not 100% sure after reading rich's documentation for 'RichCast' and after reading the source of 'rich_cast'.

* Type variable to remove literal ambiguity.

mypy was inferring the type of the empty string as a literal and thus was not type checking the fact that 'render' would either be a string or Text.

* Assert scrollbars always have parents.

* Make scrollbar scroll actions synchronous.

The scrollbars were posting the messages and awaiting for them but that's not what Widget does, which handles scrolling synchronously. Thus, I made them synchronous methods by using 'post_message_no_wait'.

* Use link only when available.

* Update errors.

* Relax type inference.

* Ignore missing imports for uvloop.

'uvloop' is completely optional and this code only exists to cater for the case where the user _already_ has uvloop installed.
With that in mind, it makes sense to silence errors about uvloop not being available because we don't need to know about that.
We only care if uvloop happens to be installed.

* Enable variable reuse.

* Fix type issues in easing.py.

* Fix typing issues in demo.

Fixing the typing issues here involved making use of the messaging features to replace a method (wasn't exactly wrong, but this is more in line with the Textual way of doing things, which should be prevalent in the demo of the framework).
We also dealt with a typing issue in DarkSwitch.on_dark_change by deleting an unnecessary parameter, but the underlying problem is unsolved and was logged as issue #1865.

Related issues: #1865.

* Fix typing issues in _doc.py.

* Type actions with a type alias.

* Make return values optional.

As per discussion with @darrenburns.

* Make StringKey idempotent.

This set up is so that we can easily make sure that a variable of the type str | SK (where SK is a subclass of StringKey) becomes of the type SK.
Instead of having to write a conditional expression to only convert in case of a string, we make SK idempotent so that we can just call it on the value that may still be a string.

* Make sorting type safe.

* Fix typing of StringKey.__new__.

This is needed to ensure the type checkers know the exact type of the instances returned when instantiating subclasses of StringKey.

* Add explicit type variables.

* Type-safe line rendering.

* Type safe _render_line_in_row.

* Type safe _render_cell.

* Type safe ordered_rows property.

* Type safe ordered_columns property.

* Simplify handling of Nones in TwoWayDict.

In the beginning of the work on this PR, mypy flagged two issues in the implementation of TwoWayDict, which would return None when the keys/values were not available but the signatures of get/get_key did not have the missing '| None'.
When I added the '| None' to the return values of TwoWayDict.get and TwoWayDict.get_key, many new errors popped up because the implementation of DataTable assumes, in many different places, that those methods return the exact thing that we asked for, and not None.

To fix this, I started going over the call sites for get/get_key and started adding checks for 'None' and raising the appropriate RowDoesNotExist/ColumnDoesNotExist error.

At some point, I realised that went a little bit against the semantics of the code, which pretty much assumes those accesses WILL work.

So, I subclassed TwoWayDict to specialise it even further to this use case.
The subclass is meant to work with RowKey/ColumnKey as the underlying keys and it will automatically raise an error if the access fails.

CC: @darrenburns.

* Make use of idempotency of StringKey subclasses.

* Make message aware of type of sender.

* Only select when possible.

* Fix typing of reactive attribute.

* Reset cursor upon moving action if needed.

* Assure mypy we have ListItems.

This could be improved (as in, cast wouldn't be needed) if #1871 is resolved favourably.

* Add explicit return.

* Ignore argument types to watch.

Related issues: #1865.

* Type safe App._register.

* Redirect output to void.

* Remove helper file.

* Fix Python compat. issues.

* Button can only accept str/Text as label.

Fixes: #1870.

* Add runtime type check for list items.

This change follows from a discussion in issue #1871.

* Address review comments.

* Revert "Fix typing issues in demo."

This reverts commit f366783920.

* Address review comments.

Related comments: https://github.com/Textualize/textual/pull/1831\#discussion_r1118155296

* Add clarifying comment.

See: https://github.com/Textualize/textual/pull/1831\#discussion_r1118154777

* Revert changes to data table.
2023-03-01 15:50:15 +00:00
Dave Pearson
37208b199c Fixes and improvements relating to scrolling
The changes here roll two issues into one change. With this commit:

- Scrolling up/down/etc using the keyboard now moves just one cell, rather
  than moving the number of cells specified by the scroll sensitivity that's
  intended for pointing devices. #1897
- Where appropriate the scrolling is done lazily; that is it is done after
  the next refresh, helping to ensure that the scroll will take into account
  any updates in the same parent call. #1774
2023-02-28 14:59:46 +00:00
Dave Pearson
8c5fb38851 Merge branch 'main' into toggle-boxen 2023-02-27 10:31:06 +00:00
darrenburns
cbe2ab87c6 Datatable labelling rows (#1868)
* Renaming some component classes in DataTable

* Some more renaming of DataTable component classes

* Separate styling for fixed rows/columns from labels

* Highlight fixed rows/cols affected by colour differently

* Tweaking styles for fixed data in DataTable

* Update DataTable snapshots

* Add row label to Row metadata

* Wiring up some labelled row logic behind flags

* Renaming variable in DataTable

* Variable renaming in DataTable

* [no ci] Labelling rows progress

* Add RenderedRow abstraction to DataTable

* Computing label widths

* Use the Column object to represent row label column

* Ability to toggle row labels reactively

* Adjust width calculation for label widths

* Add DataTable.RowLabelSelected

* Posting the RowLabelClick message

* Hovering of row labels applies new style

* Remove a print

* Ensure horizontal scrolling with column cursor accounts for row label column

* Account for possible row labels in cell cursor horizontal scrolling

* Ensure cursor highlighting is correct on row label cells

* Document component class for DataTable label hover

* Test to ensure clicking row label emits correct event

* Add snapshot test for DataTable with fixed rows/cols and row labels

* Using pilot pause instead of wait_for_idle directly

* Update CHANGELOG

* Add a docstring

* Add a note to CHANGELOG.md about RowLabelSelected
2023-02-27 10:29:17 +00:00
Dave Pearson
e6e46d0825 Merge branch 'main' into toggle-boxen 2023-02-27 08:53:30 +00:00
Will McGugan
8ba789367b catch exceptions from post mount 2023-02-26 16:54:29 +00:00
Will McGugan
4e766887bc version bump 2023-02-25 08:19:08 +00:00
Will McGugan
8b17579ff4 changelog 2023-02-25 08:18:37 +00:00
Will McGugan
05bb10aed0 batch update fix, and optimization 2023-02-25 08:15:00 +00:00
Will McGugan
99a9b6aa91 changelog 2023-02-24 12:46:21 +00:00
Will McGugan
0924bb2ba4 Version bump 2023-02-24 12:45:49 +00:00
Will McGugan
96370b1fd8 Merge pull request #1873 from Textualize/screen-children-fix
fix walk children
2023-02-24 12:36:58 +00:00
Will McGugan
5a77e3493d add test 2023-02-24 10:13:58 +00:00
Dave Pearson
f0a6771533 Update the ChangeLog and the roadmap 2023-02-23 22:14:41 +00:00
Will McGugan
f723f3771f changelog 2023-02-23 13:51:34 +00:00
Will McGugan
7d99d168ff prevent implementation 2023-02-23 13:49:07 +00:00
Will McGugan
bf50e6a424 changelog 2023-02-22 16:29:15 +00:00
Will McGugan
019a0dde5b Fix text log refreshing 2023-02-22 16:27:05 +00:00
Will McGugan
2e2473552a changelog 2023-02-21 15:37:30 +00:00
Will McGugan
a714ffe388 Merge branch 'main' into alt-compose 2023-02-21 10:46:45 +00:00
Will McGugan
4c9326f66f Merge pull request #1832 from Textualize/batch-update
Batch update
2023-02-21 10:42:31 +00:00
Will McGugan
068d7513b8 Merge pull request #1823 from Textualize/optimize-scroll
Optimize scroll with a Spatial Map
2023-02-21 10:41:04 +00:00
Will McGugan
453070032e Merge pull request #1785 from davep/promote-disabled
Promote disabled to `Widget` level
2023-02-21 09:56:01 +00:00
Will McGugan
ae498d49c8 Merge branch 'main' into optimize-scroll 2023-02-21 09:40:42 +00:00
Will McGugan
7d9ef17b10 changelog 2023-02-20 20:51:15 +00:00