unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* vtable: Add column weights feature
@ 2022-10-08  1:51 Tad Fisher
  2022-10-08 13:06 ` Lars Ingebrigtsen
  0 siblings, 1 reply; 4+ messages in thread
From: Tad Fisher @ 2022-10-08  1:51 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 211 bytes --]

Hello,

This is a patch to allow allocating the full window width to vtable
columns, in proportion to a new `weight' slot value.

I would need to assign copyright if this patch were to be accepted.

Thanks,
Tad

[-- Attachment #2: 0001-vtable-Add-column-weights-feature.patch --]
[-- Type: text/x-patch, Size: 6155 bytes --]

From 6c03a268eaa81479799a12a747c299bf83363e8e Mon Sep 17 00:00:00 2001
From: Tad Fisher <tadfisher@gmail.com>
Date: Fri, 7 Oct 2022 17:57:25 -0700
Subject: [PATCH] vtable: Add column weights feature

Add a mechanism to expand the table to the full window width, while
distributing unallocated space to columns in proportion to their
`weight' value.
* lisp/emacs-lisp/vtable.el: Add column weights feature
* doc/misc/vtable.texi: Document column weights feature
---
 doc/misc/vtable.texi      | 12 ++++++
 lisp/emacs-lisp/vtable.el | 87 +++++++++++++++++++++++++++++----------
 2 files changed, 78 insertions(+), 21 deletions(-)

diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi
index 59cd9d0..b2eb375 100644
--- a/doc/misc/vtable.texi
+++ b/doc/misc/vtable.texi
@@ -298,6 +298,18 @@ Making A Table
 given as a percentage of the window width, and you want to ensure that
 the column doesn't grow pointlessly large or unreadably narrow.
 
+@item weight
+A number that specifies how to distribute unallocated space to this
+column. After measuring all columns without a @code{weight} value, the
+remaining window width is divided proportionally among all columns with
+a @code{weight} value. For example: given a table holding two columns,
+one with @samp{:weight 1} and another with @samp{:weight 2}, the first
+will have half the width of the second, or 33% of the window width.
+
+This value is ignored when @code{width} is specified. The
+@code{min-width} and @code{max-width} slots will still apply, which may
+cause the table width to exceed the available window width.
+
 @item primary
 Whether this is the primary column---this will be used for initial
 sorting.  This should be either @code{ascend} or @code{descend} to say
diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el
index 9bdf90b..ec1fd7f 100644
--- a/lisp/emacs-lisp/vtable.el
+++ b/lisp/emacs-lisp/vtable.el
@@ -40,6 +40,7 @@ vtable-column
   width
   min-width
   max-width
+  weight
   primary
   align
   getter
@@ -775,34 +776,78 @@ vtable--compute-width
    (t
     (error "Invalid spec: %s" spec))))
 
-(defun vtable--compute-widths (table cache)
-  "Compute the display widths for TABLE."
+(defun vtable--apply-column-constraints (table column width)
+  "Constrain WIDTH according to constraints in COLUMN for TABLE."
+  (when-let ((min-width (and (vtable-column-min-width column)
+                             (vtable--compute-width
+                              table (vtable-column-min-width column)))))
+    (setq width (max width min-width)))
+  (when-let ((max-width (and (vtable-column-max-width column)
+                             (vtable--compute-width
+                              table (vtable-column-max-width column)))))
+    (setq width (min width max-width)))
+  width)
+
+(defun vtable--compute-fixed-widths (table cache)
+  "Compute fixed display widths for TABLE."
   (seq-into
    (seq-map-indexed
     (lambda (column index)
-      (let ((width
-             (or
-              ;; Explicit widths.
-              (and (vtable-column-width column)
-                   (vtable--compute-width table (vtable-column-width column)))
-              ;; Compute based on the displayed widths of
-              ;; the data.
-              (seq-max (seq-map (lambda (elem)
+      (or
+       ;; Explicit width.
+       (when-let ((spec (vtable-column-width column)))
+         (let ((width (vtable--compute-width table spec)))
+           (vtable--apply-column-constraints table column width)))
+
+       ;; Non-weighted width.
+       (unless (vtable-column-weight column)
+         (let ((width (seq-max
+                       (seq-map (lambda (elem)
                                   (nth 1 (elt (cdr elem) index)))
-                                cache)))))
-        ;; Let min-width/max-width specs have their say.
-        (when-let ((min-width (and (vtable-column-min-width column)
-                                   (vtable--compute-width
-                                    table (vtable-column-min-width column)))))
-          (setq width (max width min-width)))
-        (when-let ((max-width (and (vtable-column-max-width column)
-                                   (vtable--compute-width
-                                    table (vtable-column-max-width column)))))
-          (setq width (min width max-width)))
-        width))
+                                cache))))
+           (vtable--apply-column-constraints table column width)))
+
+       0))
     (vtable-columns table))
    'vector))
 
+(defun vtable--compute-weighted-widths (table space)
+  "Compute weighted column widths for TABLE given SPACE."
+  (let* ((columns (vtable-columns table))
+         (weights (seq-into
+                   (seq-map
+                    (lambda (column)
+                       (if (vtable-column-width column) 0
+                         (or (vtable-column-weight column) 0)))
+                    columns)
+                   'vector))
+         (total-weight (seq-reduce #'+ weights 0)))
+    (if (= total-weight 0)
+        (make-vector (length columns) 0)
+      (seq-into
+       (seq-map-indexed
+        (lambda (column index)
+          (let ((weight (seq-elt weights index)))
+            (if (= 0 weight) 0
+              (let* ((rel-weight (/ weight total-weight))
+                     (width (* rel-weight space)))
+                (vtable--apply-column-constraints table column width)))))
+          columns)
+       'vector))))
+
+(defun vtable--compute-widths (table cache)
+  "Compute the display widths for TABLE."
+  (let* ((fixed-widths (vtable--compute-fixed-widths table cache))
+         (fixed-space (seq-reduce #'+ fixed-widths 0))
+         (weighted-space (- (window-width nil t)
+                            fixed-space
+                            (* (vtable--spacer table)
+                               (1- (length (vtable-columns table))))))
+         (weighted-widths (vtable--compute-weighted-widths table weighted-space)))
+    (seq-into
+     (seq-mapn #'+ fixed-widths weighted-widths)
+   'vector)))
+
 (defun vtable--compute-cache (table)
   (seq-map
    (lambda (object)
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: vtable: Add column weights feature
  2022-10-08  1:51 vtable: Add column weights feature Tad Fisher
@ 2022-10-08 13:06 ` Lars Ingebrigtsen
  2022-10-08 21:11   ` Tad Fisher
  0 siblings, 1 reply; 4+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-08 13:06 UTC (permalink / raw)
  To: Tad Fisher; +Cc: emacs-devel

Tad Fisher <tadfisher@gmail.com> writes:

> This is a patch to allow allocating the full window width to vtable
> columns, in proportion to a new `weight' slot value.

Thanks, the code looks good.

But I'm not quite sure how the "weight" concept interacts with
percentage widths?  That is, when would it be preferable to add width
specs to columns instead of just using percentages?  (And an explanation
for this should be added to the manual.)

> I would need to assign copyright if this patch were to be accepted.

Here's the form to get started:

---


Please email the following information to assign@gnu.org, and we
will send you the assignment form for your past and future changes.

Please use your full legal name (in ASCII characters) as the subject
line of the message.
----------------------------------------------------------------------
REQUEST: SEND FORM FOR PAST AND FUTURE CHANGES

[What is the name of the program or package you're contributing to?]
Emacs

[Did you copy any files or text written by someone else in these changes?
Even if that material is free software, we need to know about it.]

[Do you have an employer who might have a basis to claim to own
your changes?  Do you attend a school which might make such a claim?]

[For the copyright registration, what country are you a citizen of?]

[What year were you born?]

[Please write your email address here.]

[Please write your postal address here.]

[Which files have you changed so far, and which new files have you written
so far?]



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: vtable: Add column weights feature
  2022-10-08 13:06 ` Lars Ingebrigtsen
@ 2022-10-08 21:11   ` Tad Fisher
  2022-10-09 14:26     ` Lars Ingebrigtsen
  0 siblings, 1 reply; 4+ messages in thread
From: Tad Fisher @ 2022-10-08 21:11 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: emacs-devel

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Tad Fisher <tadfisher@gmail.com> writes:
>
>> This is a patch to allow allocating the full window width to vtable
>> columns, in proportion to a new `weight' slot value.
>
> Thanks, the code looks good.
>
> But I'm not quite sure how the "weight" concept interacts with
> percentage widths?  That is, when would it be preferable to add width
> specs to columns instead of just using percentages?  (And an explanation
> for this should be added to the manual.)

In my mind, "percentage of window width" specs aren't useful to begin
with, because they interact poorly with fixed-width columns. If your
goal is to have the vtable occupy a particular width of the window (e.g.
100%), this goal becomes difficult/impossible as soon as a fixed-width
column is added.

So in the case you want the vtable to occupy 100% of the window width,
weights are the strictly superior option. In case you want the vtable to
occupy, say, 80% of the window width, then the only option is to assign
percentages to all columns and strictly avoid fixed-width specs.

Ideally, you'd have a constraint on the vtable itself---as in, "I want
the vtable to occupy 80% of the window width", and that value is used
instead of (window-width nil t) when calculating column widths.

And I do think that defining these concepts as "constraints" is the
better approach in the long run; as in, the "width", "min-width", and
"max-width" slots become part of an enumerated "constraint" type,
so the API limits the possible values to those that make sense. Then
the vtable--column-widths function solves those constraints to obtain
the final width values. Does this make sense? My experience is mostly
from Android UIs where this is a common way to define layouts, and my
understanding is that the CSS "flexbox" model is similar.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: vtable: Add column weights feature
  2022-10-08 21:11   ` Tad Fisher
@ 2022-10-09 14:26     ` Lars Ingebrigtsen
  0 siblings, 0 replies; 4+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-09 14:26 UTC (permalink / raw)
  To: Tad Fisher; +Cc: emacs-devel

Tad Fisher <tadfisher@gmail.com> writes:

> In my mind, "percentage of window width" specs aren't useful to begin
> with, because they interact poorly with fixed-width columns. If your
> goal is to have the vtable occupy a particular width of the window (e.g.
> 100%), this goal becomes difficult/impossible as soon as a fixed-width
> column is added.

That shouldn't be impossible -- the normal way to do this is to let the
percentage columns soak up the available space (but you need a way to
specify the total width of the table, which should be easy enough to
add).

> Ideally, you'd have a constraint on the vtable itself---as in, "I want
> the vtable to occupy 80% of the window width", and that value is used
> instead of (window-width nil t) when calculating column widths.

Yes, we could add that.

> And I do think that defining these concepts as "constraints" is the
> better approach in the long run; as in, the "width", "min-width", and
> "max-width" slots become part of an enumerated "constraint" type,
> so the API limits the possible values to those that make sense. Then
> the vtable--column-widths function solves those constraints to obtain
> the final width values. Does this make sense? My experience is mostly
> from Android UIs where this is a common way to define layouts, and my
> understanding is that the CSS "flexbox" model is similar.

I think percentages are easier to deal with if you don't consider them
to be strict.  That is, if you've specified the width of the entire
table, then having one table saying "10%" and another "20%" means that
any extra space would be distributed 1:2 between those two columns.




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-10-09 14:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-08  1:51 vtable: Add column weights feature Tad Fisher
2022-10-08 13:06 ` Lars Ingebrigtsen
2022-10-08 21:11   ` Tad Fisher
2022-10-09 14:26     ` Lars Ingebrigtsen

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).