From: Stephen Berman via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Mauro Aranda <maurooaranda@gmail.com>
Cc: 69942@debbugs.gnu.org, Eli Zaretskii <eliz@gnu.org>
Subject: bug#69942: 30.0.50; Fontification of radio-button widget labels
Date: Mon, 25 Mar 2024 01:40:36 +0100 [thread overview]
Message-ID: <87msqnqh2z.fsf@gmx.net> (raw)
In-Reply-To: <87v85bqxfv.fsf@gmx.net> (Stephen Berman's message of "Sun, 24 Mar 2024 19:47:16 +0100")
[-- Attachment #1: Type: text/plain, Size: 4425 bytes --]
On Sun, 24 Mar 2024 19:47:16 +0100 Stephen Berman <stephen.berman@gmx.net> wrote:
> On Sat, 23 Mar 2024 18:05:30 -0300 Mauro Aranda <maurooaranda@gmail.com> wrote:
>
>> Stephen Berman <stephen.berman@gmx.net> writes:
>>
>>> In bug#69941 I reported a faulty fontification of radio-button widgets
>>> and noted in passing that the labels associated with the radio buttons
>>> also have unexpected faces, namely, the widget-inactive face regardless
>>> of whether the associated radio buttons are inactive or active (except
>>> for the label of a radio button that has been pressed, which has the
>>> default face). While the faulty fontification discussed in bug#69941
>>> appears to be a real bug, the widget-inactive face assigned to
>>> radio-button labels is apparently by design -- it was present in the
>>> initial commit of the widget library. But this seems to me to have been
>>> a UX mistake, since it effectively ignores the semantics implied by the
>>> name widget-inactive. I think a less surprising UI would be for the
>>> labels to be fontified according to the widget's activation state:
>>> default face when the widget is active and widget-inactive face when
>>> it's inactive. The attached patches provide two possible
>>> implementations of this UI.
>>>
>>> The first patch makes the change unconditionally, treating the current
>>> fontification as a UI/UX bug. But it may be argued that this aspect of
>>> the widget UI should not be unconditionally changed, since it was
>>> apparently a deliberate design choice and there have been (AFAIK) no
>>> complaints about the semantic discrepancy till now. The lack of
>>> complaint could be because the widget-inactive face inherits the shadow
>>> face, so it is not sharply different from the default face. But if one
>>> uses a very different face (as I did for illustrative purposes in
>>> bug#69941), the inconsistency is very obvious and (IMO) jarring.
>>> Nevertheless, to allow keeping the current fontification, the second
>>> patch conditionalizes the change from the current fontification by means
>>> of a user option (with the default being the current fontification).
>>>
>>> Is either of these changes acceptable?
>>
>> Thanks for working on this. What about adding a widget-unselected face?
>> I think that might be the intention with using the widget-inactive face
>> for unselected radio items.
>
> Yes, I agree that was likely the intention. But I think it's
> superfluous: after all, the distinction between selected (or chosen) and
> unselected items is already clear from the appearance of the radio
> buttons or, with checklist widgets, the check boxes (my patch neglected
> checklists, but it's straightforward to account for them: in
> widget-checklist-add-item the (widget-apply child :deactivate) sexp
> should be wrapped in an (unless widget-radio-face-from-state ...)).
>
> On the other hand, with an unselected face for the labels of the radio
> button or check boxes, if it defaults to inheriting the shadow face for
> unselected items, that corresponds to the current appearance with the
> widget-inactive face, and by setting the widget-unselected face to the
> default face, all labels would appear the same, which is what I want.
> So for me that's an acceptable alternative to my proposed defcustom. I
> tried to implement it, but I'm not very conversant with the workings of
> widget properties and how to apply faces depending on the widget's
> state, and I haven't managed to come up with a working implementation
> yet. I'll keep trying, but you or someone else might be able to do it
> sooner.
>
> (There is another argument, besides superfluousness, against using a
> separate face for unselected items: using multiple check boxes instead
> of a checklist, as e.g. recentf-edit-list does. With these the label of
> each check box is supplied by the :tag property, so it is not touched by
> the current handling in terms of the child widget's activation state.
> I'm not sure if using an unselected face here would be unproblematic or
> not.)
Ok, I've gotten further with implementing disinguishing by faces
selected (chosen) and unselected radio buttons in radio-button-choice
widgets and check boxes in checklist widgets, see the attached patch.
Initial tests seem ok, but it definitely needs more testing.
Steve Berman
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: selected and unselected widgets --]
[-- Type: text/x-patch, Size: 5205 bytes --]
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 172da3db1e0..005aa918087 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -555,6 +555,27 @@ widget-specify-active
(delete-overlay inactive)
(widget-put widget :inactive nil))))
+(defface widget-unselected
+ '((t :inherit shadow))
+ "Face used for unselected widgets."
+ :group 'widget-faces
+ :version "30.1")
+
+(defun widget-specify-unselected (widget from to)
+ "Fontify WIDGET as unselected (not chosen)."
+ (let ((overlay (make-overlay from to nil t nil)))
+ (overlay-put overlay 'face 'widget-unselected)
+ (overlay-put overlay 'evaporate t)
+ (overlay-put overlay 'priority 100)
+ (widget-put widget :unselected overlay)))
+
+(defun widget-specify-selected (widget)
+ "Remove fontification of WIDGET as unselected (not chosen)."
+ (let ((unselected (widget-get widget :unselected)))
+ (when unselected
+ (delete-overlay unselected)
+ (widget-put widget :unselected nil))))
+
;;; Widget Properties.
(defsubst widget-type (widget)
@@ -2415,10 +2436,16 @@ 'checkbox
(defun widget-checkbox-action (widget &optional event)
"Toggle checkbox, notify parent, and set active state of sibling."
(widget-toggle-action widget event)
- (let ((sibling (widget-get-sibling widget)))
+ (let* ((sibling (widget-get-sibling widget))
+ (from (widget-get sibling :from))
+ (to (widget-get sibling :to)))
(when sibling
- (widget-apply sibling
- (if (widget-value widget) :activate :deactivate))
+ (if (widget-value widget)
+ (progn
+ (widget-apply sibling :activate)
+ (widget-specify-selected sibling))
+ :deactivate
+ (widget-specify-unselected sibling from to))
(widget-clear-undo))))
;;; The `checklist' Widget.
@@ -2474,15 +2501,19 @@ widget-checklist-add-item
((eq escape ?v)
(setq child
(cond ((not chosen)
- (let ((child (widget-create-child widget type)))
- (widget-apply child :deactivate)
+ (let* ((child (widget-create-child widget type))
+ (from (widget-get child :from))
+ (to (widget-get child :to)))
+ (widget-specify-unselected child from to)
child))
((widget-inline-p type t)
(widget-create-child-value
- widget type (cdr chosen)))
+ widget type (cdr chosen))
+ (widget-specify-selected child))
(t
(widget-create-child-value
- widget type (car (cdr chosen)))))))
+ widget type (car (cdr chosen)))
+ (widget-specify-selected child)))))
(t
(error "Unknown escape `%c'" escape)))))
;; Update properties.
@@ -2653,8 +2684,11 @@ widget-radio-add-item
(widget-create-child-value
widget type value)
(widget-create-child widget type)))
- (unless chosen
- (widget-apply child :deactivate)))
+ (if chosen
+ (widget-specify-selected child)
+ (let ((from (widget-get child :from))
+ (to (widget-get child :to)))
+ (widget-specify-unselected child from to))))
(t
(error "Unknown escape `%c'" escape)))))
;; Update properties.
@@ -2704,14 +2738,17 @@ widget-radio-value-set
(dolist (current (widget-get widget :children))
(let* ((button (widget-get current :button))
(match (and (not found)
- (widget-apply current :match value))))
+ (widget-apply current :match value)))
+ (from (widget-get current :from))
+ (to (widget-get current :to)))
(widget-value-set button match)
(if match
- (progn
- (widget-value-set current value)
- (widget-apply current :activate))
- (widget-apply current :deactivate))
- (setq found (or found match))))))
+ (progn
+ (widget-value-set current value)
+ (widget-apply current :activate)
+ (widget-specify-selected current))
+ (widget-specify-unselected current from to))
+ (setq found (or found match))))))
(defun widget-radio-validate (widget)
;; Valid if we have made a valid choice.
@@ -2731,13 +2768,16 @@ widget-radio-action
(let ((buttons (widget-get widget :buttons)))
(when (memq child buttons)
(dolist (current (widget-get widget :children))
- (let* ((button (widget-get current :button)))
+ (let* ((button (widget-get current :button))
+ (from (widget-get current :from))
+ (to (widget-get current :to)))
(cond ((eq child button)
(widget-value-set button t)
- (widget-apply current :activate))
+ (widget-apply current :activate)
+ (widget-specify-selected current))
((widget-value button)
(widget-value-set button nil)
- (widget-apply current :deactivate)))))))
+ (widget-specify-unselected current from to)))))))
;; Pass notification to parent.
(widget-apply widget :notify child event))
next prev parent reply other threads:[~2024-03-25 0:40 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-22 15:04 bug#69942: 30.0.50; Fontification of radio-button widget labels Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-22 15:33 ` Eli Zaretskii
2024-03-23 21:05 ` Mauro Aranda
2024-03-24 18:47 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-25 0:40 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2024-04-01 15:21 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-06 9:02 ` Eli Zaretskii
2024-04-08 10:58 ` Mauro Aranda
2024-04-08 11:15 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-08 12:03 ` Eli Zaretskii
2024-04-18 9:23 ` Eli Zaretskii
2024-04-18 10:07 ` Mauro Aranda
2024-04-18 13:37 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-21 19:45 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-26 12:47 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-09 7:22 ` Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87msqnqh2z.fsf@gmx.net \
--to=bug-gnu-emacs@gnu.org \
--cc=69942@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=maurooaranda@gmail.com \
--cc=stephen.berman@gmx.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).