Shannon Sterz [Wed, 23 Oct 2024 12:52:56 +0000 (14:52 +0200)]
widget: remove useless `try_from` call in theme density selector
the enum member `SetThemeDensity` already only takes values of type
`ThemeDensity`. so the `try_from` here converts from `ThemeDensity`
to `ThemeDensity` which is pointless and trivially must always
succeed. remove it so that the compiler stops complaining about
irrefutable patterns.
Shannon Sterz [Tue, 8 Oct 2024 09:02:19 +0000 (11:02 +0200)]
widget: form: make selector load only when enabled
loading when a selector is disabled doesn't serve any purpose as users
can't select the loaded entries anyway. so only load when the
selector is enabled. also makes sure that the selector loads if it
was previously disabled and is now enabled.
Dominik Csapak [Tue, 8 Oct 2024 10:31:33 +0000 (12:31 +0200)]
widget: data table: react to column changes
the headers are part of the properties, so if they change, we should
react to that. Until now, we only accepted them at the first 'create'
call, which meant that when the columns changed afterwards (e.g. when we
want to pass different data to the renderer) it did not get rerendered
with the new information.
To do this, refactor the header processing code from 'create' into it's
own function, and call it also when the headers changed in the 'changed'
method.
Dominik Csapak [Mon, 7 Oct 2024 10:25:53 +0000 (12:25 +0200)]
widget: input panel: fix key generation for labels
yews key mechanism does not work on markup level, but on component
level. So the attempt to auto-generate keys for FieldLabels in the view
method instead of the input panel was misguided, since that does not
actually give the label itself a key.
This was noticed on all input panels where we dynamically added/removed
fields, since then the whole form was reset because of the missing keys.
(E.g. the ACME DNS plugin panel)
Instead generate the label key like before in the input panel itself,
but only when the FieldLabel itself does not already have one set.
(so users can manually override that if they want)
Fixes: bd58deb (widget: input panel: use FieldLabel instead of just text) Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Dominik Csapak [Thu, 3 Oct 2024 13:24:50 +0000 (15:24 +0200)]
widget: input panel: adapt to recent grid column change
we changed the layout to a 5 column grid (one spacer in the middle),
but forgot to add the middle column when we set the label_width or
field_width manually.
and remove old `Checkbox` implementation. Since we now have a separate
RadioButton component and the Boolean one has more features that should
cover all use cases of the old Checkbox field, simply rename the Boolean
to Checkbox.
Also having only one Checkbox component instead of two separate ones is
less confusing and less error prone.
This makes it necessary to adapt all code paths using either Checkbox or
Boolean, but these changes should be rather trivial:
* either changing the submit_on/off_values where we used a checkbox
previously
* or rename Boolean to Checkbox
If we missed some use case for the Checkbox, we can either simply add it
again, or use a more generic Field with input_type 'checkbox' instead.
instead of reusing the Checkbox component for creating radio buttons,
have a separate component for that. This makes it easier to specialize
the code for that use case.
The code is mostly a mix of Checkbox and Boolean (for some of the newer
features), with the irrelevant portions stripped out.
sometimes it's useful to map the checked/unchecked state to different
submit values than true/false, e.g. for inverted checkboxes or if the
api does not accept true/false but e.g. 1/0 instead.
widget: move FieldLabel functionality into Boolean
We only ever need labels on the right side (called box label now), only
on checkboxes, so it does not really make sense to have a separate
widget for that.
For now we only accept text as the label, but we could change that
later if we need that.
This makes the 'FieldLabel' available and ready to use elsewhere, e.g.
the input panel.
For convenience, we implement some From traits for it, so one can use a
bare string to create such a field label.
widget: checkbox: make clickable area react to clicks
the outer container contains the visual cues for clicking the checkbox,
but only the inner actual checkbox reacted to clicks. Move the onclick
handler to the outer container so the click behavior matches the
visuals.
this can be useful if the theme or project defines it's own color
schemes, but still want to refer to them in the code without having to
use bare css classes
navigation_drawer: update route even if the current key is selected
this is necessary so a user can use the parent's navigation elements to
navigate back to parent of the current child too. otherwise, only other
elements on the same level as the parent are usable.
dropdown: fix picker not closing on first select after input
we don't want to close the picker when we change the value via keyboard
input, so we save that info in `change_from_input`.
Since we only handle that flag when the picker is open, we must only set
it when the picker is open too. Otherwise we possibly set it while the
picker is closed, having the wrong behavior when the picker gets opened
afterwards.
Dominik Csapak [Tue, 13 Aug 2024 11:42:11 +0000 (13:42 +0200)]
widget: data table: simplify cursor selection
we don't have to check for ctrl here, since just before we clear the
selection if we didn't have ctrl pressed, so `toggle` does the
same as `select` here in that case. Also, this makes it possible
to deselect rows with the simple selection mode.
Dominik Csapak [Tue, 13 Aug 2024 11:42:13 +0000 (13:42 +0200)]
widget: data table: improve checkbox clicking in selection column
by;
* moving the click handler on the whole cell instead of the tiny
checkbox icon
* stopping propagation, this makes it actually work, since otherwise
the row would get clicked and it resulted in the usual 'select only
this row' behavior
Dominik Csapak [Tue, 13 Aug 2024 11:42:10 +0000 (13:42 +0200)]
state: selection: handle multiselect change more gracefully
instead of keeping the respective state, try to be smart about it:
* when changing to multiselect, keep the selection
* when changing from multiselect, clear the map, but keep the selection
if there was only one
otherwise it's possible to let the spinner running by
* pressing the mouse button on the spinner
* moving the cursor outside of the spinner
* letting go
this is a helper struct to better handle focusin/out events.
We had the pattern with DelayedFocusChange in a few components, and they
were basically all doing the same.
To factor out, we have to use a bit of a different approach (see the
comment on the struct itself), since we don't want to introduce an extra
component in the component tree for this (since nothing is really
rendered for that).
It's not saving us much code for now, but with every new component
needing that, we can make sure we have the same behavior.
widget: number field: add spinner repeat behaviour
instead of reacting to each click, react to pointerdown/up
and implement a very basic repeat logic, so that the value
de/increments repeatedly when keep pressing the up/down buttons
widget: dropdown: fix non-editable cursor with renderer
when we have a 'rendered' value, the component tree is different, and
we have to put the 'non-editable' class one level higher for it to have
an effect
this is used with a ContextProvider to provide a visibility information
to children elements, without the need to 'prop drill'.
Currently only used by a selection view, but could be used by all
elements that cache child elements that only show/hide them instead
of letting the dom change.
When using in a generic widget/etc, should react to higher level
visibility contexts.
'Parse number failed' implies that we could not parse the number, but to
know it was too big, we had to parse the number correctly, so this is
confusing. Replacing with 'Input invalid' makes it clearer that what
is actually happening.
widget: number field: prevent invalid settings with scroll/keyboard
By don't in/decreasing the value if it's over the max/under the min
value. To insert a value when scrolling/keyboard even if none was set,
introducing a 'clamp_value' trait fn that simply forwards to the
underlying clamp with T::MIN and T::MAX as defaults. This is then used
to determine the initial value that is set.
until now we used a modal dialog for the picker. While had some
advantages for focus/keyboard handling, it made it impossible to have
and 'editable' field while having the dialog open.
So instead, use a non-modal dialog and rework the focus/keyboard handling
to work as expected.
The biggest change here is how keyboard uses can navigate it:
instead of being 'captured' in the picker once it's open, using
tab/shift+tab simply closes the picker should the focus go outside the
current field
With this changes, having an editable dropdown works as expected, the
field gets the focus by default, the picker remains open until it's
closed or the widget loses focus, and one can open/close the picker
manually with the keyboard or trigger.
by adding a 'show_dialog' binding. For this to work correctly in all
situations, we have to adapt the align code to distinguish between modal
and non-modal dialogs, so we set a custom attribute on the dom element
when opening.
but only when the field is
* not editable (then the user can simply delete the value)
* not disabled (no input possible)
* not empty (nothing to clear)
* not required (empty field is not allowed)