details:   https://code.tryton.org/tryton/commit/23864f40889b
branch:    default
user:      Cédric Krier <[email protected]>
date:      Tue Mar 10 15:45:24 2026 +0100
description:
        Add generic management for label style in form widget
diffstat:

 sao/src/view/form.js                                          |  57 ++++------
 tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py |  23 +---
 tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py  |  28 +---
 tryton/tryton/gui/window/view_form/view/form_gtk/widget.py    |  11 +-
 4 files changed, 43 insertions(+), 76 deletions(-)

diffs (336 lines):

diff -r 42cf694cdab3 -r 23864f40889b sao/src/view/form.js
--- a/sao/src/view/form.js      Tue Mar 10 14:54:48 2026 +0100
+++ b/sao/src/view/form.js      Tue Mar 10 15:45:24 2026 +0100
@@ -1287,6 +1287,7 @@
             this.position = 0;
             this.visible = true;
             this.labelled = null;  // Element which received the labelledby
+            this.label = null;  // Optional element rendering the field label
         },
         display: function() {
             var field = this.field;
@@ -1350,6 +1351,10 @@
                 }
             }
             this.set_invisible(invisible);
+            if (this.label) {
+                Sao.common.apply_label_attributes(
+                    this.label, readonly, required);
+            }
         },
         get _styled_el() {
             return this.el;
@@ -3268,7 +3273,6 @@
             Sao.View.Form.One2Many._super.init.call(this, view, attributes);
 
             this._readonly = true;
-            this._required = false;
             this._position = undefined;
             this._length = 0;
 
@@ -3280,16 +3284,16 @@
             });
             this.el.append(this.menu);
 
-            this.title = jQuery('<label/>', {
+            this.label = jQuery('<label/>', {
                 'class': this.class_ + '-string',
                 text: attributes.string
             });
-            this.menu.append(this.title);
-
-            this.title.uniqueId();
+            this.menu.append(this.label);
+
+            this.label.uniqueId();
             this.el.uniqueId();
-            this.el.attr('aria-labelledby', this.title.attr('id'));
-            this.title.attr('for', this.el.attr('id'));
+            this.el.attr('aria-labelledby', this.label.attr('id'));
+            this.label.attr('for', this.el.attr('id'));
 
             var toolbar = jQuery('<div/>', {
                 'class': this.class_ + '-toolbar'
@@ -3335,7 +3339,7 @@
             ).appendTo(buttons);
             this.but_previous.click(disable_during(this.previous.bind(this)));
 
-            this.label = jQuery('<span/>', {
+            this.badge = jQuery('<span/>', {
                 'class': 'badge',
             }).text('_ / 0'
             ).appendTo(jQuery('<span/>', {
@@ -3511,15 +3515,6 @@
         set_readonly: function(readonly) {
             Sao.View.Form.One2Many._super.set_readonly.call(this, readonly);
             this.prm.done(() => this._set_button_sensitive());
-            this._set_label_state();
-        },
-        set_required: function(required) {
-            this._required = required;
-            this._set_label_state();
-        },
-        _set_label_state: function() {
-            Sao.common.apply_label_attributes(this.title, this._readonly,
-                    this._required);
         },
         _set_button_sensitive: function() {
             var size_limit, o2m_size;
@@ -3947,7 +3942,7 @@
                 }
             }
             var message = name + ' / ' + Sao.common.humanize(size);
-            this.label.text(message).attr('title', message);
+            this.badge.text(message).attr('title', message);
             this.prm.done(() => this._set_button_sensitive());
         },
         validate: function() {
@@ -4013,7 +4008,6 @@
             Sao.View.Form.Many2Many._super.init.call(this, view, attributes);
 
             this._readonly = true;
-            this._required = false;
             this._position = 0;
 
             this.el = jQuery('<div/>', {
@@ -4024,16 +4018,16 @@
             });
             this.el.append(this.menu);
 
-            this.title = jQuery('<label/>', {
+            this.label = jQuery('<label/>', {
                 'class': this.class_ + '-string',
                 text: attributes.string
             });
-            this.menu.append(this.title);
-
-            this.title.uniqueId();
+            this.menu.append(this.label);
+
+            this.label.uniqueId();
             this.el.uniqueId();
-            this.el.attr('aria-labelledby', this.title.attr('id'));
-            this.title.attr('for', this.el.attr('id'));
+            this.el.attr('aria-labelledby', this.label.attr('id'));
+            this.label.attr('for', this.el.attr('id'));
 
             var toolbar = jQuery('<div/>', {
                 'class': this.class_ + '-toolbar'
@@ -4074,7 +4068,7 @@
             ).appendTo(buttons);
             this.but_add.click(this.add.bind(this));
 
-            this.label = jQuery('<span/>', {
+            this.badge = jQuery('<span/>', {
                 'class': 'badge',
             }).text('_ / 0'
             ).appendTo(jQuery('<span/>', {
@@ -4150,15 +4144,6 @@
         set_readonly: function(readonly) {
             Sao.View.Form.Many2Many._super.set_readonly.call(this, readonly);
             this._set_button_sensitive();
-            this._set_label_state();
-        },
-        set_required: function(required) {
-            this._required = required;
-            this._set_label_state();
-        },
-        _set_label_state: function() {
-            Sao.common.apply_label_attributes(this.title, this._readonly,
-                    this._required);
         },
         _set_button_sensitive: function() {
             var size_limit = false,
@@ -4203,7 +4188,7 @@
                 }
             }
             var message = name + ' / ' + Sao.common.humanize(size);
-            this.label.text(message).attr('title', message);
+            this.badge.text(message).attr('title', message);
             this._set_button_sensitive();
         },
         display: function() {
diff -r 42cf694cdab3 -r 23864f40889b 
tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py
--- a/tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py     Tue Mar 
10 14:54:48 2026 +0100
+++ b/tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py     Tue Mar 
10 15:45:24 2026 +0100
@@ -35,10 +35,10 @@
         hbox = Gtk.HBox(homogeneous=False, spacing=0)
         hbox.set_border_width(2)
 
-        self.title = Gtk.Label(
+        self.label = Gtk.Label(
             label=set_underline(attrs.get('string', '')),
             use_underline=True, halign=Gtk.Align.START)
-        hbox.pack_start(self.title, expand=True, fill=True, padding=0)
+        hbox.pack_start(self.label, expand=True, fill=True, padding=0)
 
         hbox.pack_start(Gtk.VSeparator(), expand=False, fill=True, padding=0)
 
@@ -71,8 +71,8 @@
         self.but_add.set_relief(Gtk.ReliefStyle.NONE)
         hbox.pack_start(self.but_add, expand=False, fill=False, padding=0)
 
-        self.label = Gtk.Label(label='(_/0)')
-        hbox.pack_start(self.label, expand=False, fill=False, padding=0)
+        self.badge = Gtk.Label(label='(_/0)')
+        hbox.pack_start(self.badge, expand=False, fill=False, padding=0)
 
         self.but_remove = Gtk.Button(can_focus=False)
         tooltips.set_tip(self.but_remove, _('Remove selected record'))
@@ -114,7 +114,7 @@
 
         vbox.pack_start(self.screen.widget, expand=True, fill=True, padding=0)
 
-        self.title.set_mnemonic_widget(
+        self.label.set_mnemonic_widget(
             self.screen.current_view.mnemonic_widget)
 
         self.screen.widget.connect('key_press_event', self.on_keypress)
@@ -281,19 +281,10 @@
             screen, callback, new=True, save_current=True, defaults=defaults)
 
     def _readonly_set(self, value):
-        self._readonly = value
+        super()._readonly_set(value)
         self._set_button_sensitive()
         self.wid_text.set_sensitive(not value)
         self.wid_text.set_editable(not value)
-        self._set_label_state()
-
-    def _required_set(self, value):
-        self._required = value
-        self._set_label_state()
-
-    def _set_label_state(self):
-        common.apply_label_attributes(
-            self.title, self._readonly, self._required)
 
     def _set_button_sensitive(self):
         if self.record and self.field:
@@ -330,7 +321,7 @@
         if selected > 1:
             name += '#%i' % selected
         name = '(%s/%s)' % (name, common.humanize(size))
-        self.label.set_text(name)
+        self.badge.set_text(name)
         self._set_button_sensitive()
 
     def display(self):
diff -r 42cf694cdab3 -r 23864f40889b 
tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py
--- a/tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py      Tue Mar 
10 14:54:48 2026 +0100
+++ b/tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py      Tue Mar 
10 15:45:24 2026 +0100
@@ -30,17 +30,16 @@
         vbox = Gtk.VBox(homogeneous=False, spacing=2)
         self.widget.add(vbox)
         self._readonly = True
-        self._required = False
         self._position = None
         self._length = 0
 
         self.title_box = hbox = Gtk.HBox(homogeneous=False, spacing=0)
         hbox.set_border_width(2)
 
-        self.title = Gtk.Label(
+        self.label = Gtk.Label(
             label=set_underline(attrs.get('string', '')),
             use_underline=True, halign=Gtk.Align.START)
-        hbox.pack_start(self.title, expand=True, fill=True, padding=0)
+        hbox.pack_start(self.label, expand=True, fill=True, padding=0)
 
         hbox.pack_start(Gtk.VSeparator(), expand=False, fill=True, padding=0)
 
@@ -62,8 +61,8 @@
         self.but_pre.set_relief(Gtk.ReliefStyle.NONE)
         hbox.pack_start(self.but_pre, expand=False, fill=False, padding=0)
 
-        self.label = Gtk.Label(label='(_/0)')
-        hbox.pack_start(self.label, expand=False, fill=False, padding=0)
+        self.badge = Gtk.Label(label='(_/0)')
+        hbox.pack_start(self.badge, expand=False, fill=False, padding=0)
 
         self.but_next = Gtk.Button(can_focus=False)
         tooltips.set_tip(self.but_next, _('Next'))
@@ -175,7 +174,7 @@
 
         vbox.pack_start(self.screen.widget, expand=True, fill=True, padding=0)
 
-        self.title.set_mnemonic_widget(
+        self.label.set_mnemonic_widget(
             self.screen.current_view.mnemonic_widget)
 
         self.screen.widget.connect('key_press_event', self.on_keypress)
@@ -266,25 +265,16 @@
         string = self.attrs.get('string', '')
         if mnemonic_widget:
             string = set_underline(string)
-        self.title.set_mnemonic_widget(mnemonic_widget)
-        self.title.set_label(string)
+        self.label.set_mnemonic_widget(mnemonic_widget)
+        self.label.set_label(string)
 
     @property
     def modified(self):
         return self.screen.current_view.modified
 
     def _readonly_set(self, value):
-        self._readonly = value
+        super()._readonly_set(value)
         self._set_button_sensitive()
-        self._set_label_state()
-
-    def _required_set(self, value):
-        self._required = value
-        self._set_label_state()
-
-    def _set_label_state(self):
-        common.apply_label_attributes(
-            self.title, self._readonly, self._required)
 
     def _set_button_sensitive(self):
         if self.record and self.field:
@@ -555,7 +545,7 @@
         if selected > 1:
             name += '#%i' % selected
         name = '(%s/%s)' % (name, common.humanize(size))
-        self.label.set_text(name)
+        self.badge.set_text(name)
         self._set_button_sensitive()
 
     def display(self):
diff -r 42cf694cdab3 -r 23864f40889b 
tryton/tryton/gui/window/view_form/view/form_gtk/widget.py
--- a/tryton/tryton/gui/window/view_form/view/form_gtk/widget.py        Tue Mar 
10 14:54:48 2026 +0100
+++ b/tryton/tryton/gui/window/view_form/view/form_gtk/widget.py        Tue Mar 
10 15:45:24 2026 +0100
@@ -26,6 +26,7 @@
         self.mnemonic_widget = None
         self.visible = True
         self._readonly = False
+        self.label = None  # optional label
 
     @property
     def field_name(self):
@@ -110,13 +111,11 @@
         if self.view.screen.readonly:
             readonly = True
         self._readonly_set(readonly)
-        self._required_set(not readonly and states.get('required', False))
+        required = not readonly and states.get('required', False)
+        self._required_set(required)
         if self._styled_widget:
             widget_class(self._styled_widget, 'readonly', readonly)
-            widget_class(
-                self._styled_widget,
-                'required',
-                not readonly and states.get('required', False))
+            widget_class(self._styled_widget, 'required', required)
             widget_class(
                 self._styled_widget,
                 'invalid',
@@ -128,6 +127,8 @@
                 and self.field_name in self.record.modified_fields)
         self.invisible_set(self.attrs.get(
                 'invisible', states.get('invisible', False)))
+        if self.label:
+            common.apply_label_attributes(self.label, readonly, required)
 
     def get_value(self):
         pass

Reply via email to