@@ -2742,6 +2742,9 @@ def reset_state(self):
27422742 def toggle_select_all (self ):
27432743 if self .select_toggle_action is None :
27442744 return
2745+ if self ._has_active_shape_filter ():
2746+ self ._update_select_toggle_button_tooltip ()
2747+ return
27452748 if not self .canvas .shapes :
27462749 self ._update_select_toggle_button_tooltip ()
27472750 return
@@ -2750,9 +2753,23 @@ def toggle_select_all(self):
27502753 self ._set_all_objects_visibility (not all_visible )
27512754 self ._update_select_toggle_button_tooltip ()
27522755
2756+ def _has_active_shape_filter (self ):
2757+ current_label = self .label_filter_combobox .text_box .currentText ()
2758+ current_gid = self .gid_filter_combobox .gid_box .currentText ()
2759+ return bool (current_label ) or current_gid not in ["" , "-1" ]
2760+
27532761 def _update_select_toggle_button_tooltip (self ):
27542762 if self .select_toggle_action is None :
27552763 return
2764+ if self ._has_active_shape_filter ():
2765+ tooltip = self .tr (
2766+ "Toggle shapes visibility is unavailable while a label or group filter is active"
2767+ )
2768+ self .select_toggle_action .setEnabled (False )
2769+ self .select_toggle_action .setToolTip (tooltip )
2770+ self .select_toggle_action .setStatusTip (tooltip )
2771+ return
2772+ self .select_toggle_action .setEnabled (bool (self .canvas .shapes ))
27562773 if self ._are_all_shapes_visible ():
27572774 tooltip = self .tr ("Hide all shapes" )
27582775 icon = utils .new_icon ("eye" )
@@ -2776,27 +2793,11 @@ def _are_all_shapes_visible(self):
27762793
27772794 def _set_all_objects_visibility (self , visible ):
27782795 """Set all Objects panel checkboxes and shape visibility to visible (True/False)."""
2779- model = self .label_list .model ()
2780- model .blockSignals (True )
2781- try :
2782- check_state = (
2783- Qt .CheckState .Checked if visible else Qt .CheckState .Unchecked
2784- )
2785- for item in self .label_list :
2786- item .setCheckState (check_state )
2787- shape = item .shape ()
2788- shape .visible = visible
2789- self .canvas .set_shape_visible (shape , visible )
2790- label = shape .label
2791- if label in self .label_info :
2792- self .label_info [label ]["visible" ] = visible
2793- finally :
2794- model .blockSignals (False )
2795- if (
2796- hasattr (self , "navigator_dialog" )
2797- and self .navigator_dialog .isVisible ()
2798- ):
2799- self .update_navigator_shapes ()
2796+ for item in self .label_list :
2797+ label = item .shape ().label
2798+ if label in self .label_info :
2799+ self .label_info [label ]["visible" ] = visible
2800+ self ._sync_label_list_visibility (lambda _item : visible )
28002801
28012802 def reset_attribute (self , text , shape ):
28022803 # Skip validation for auto-labeling special constants
@@ -3492,8 +3493,7 @@ def batch_edit_labels(self, shapes):
34923493 )
34933494
34943495 self .set_dirty ()
3495- self .update_combo_box ()
3496- self .update_gid_box ()
3496+ self ._refresh_shape_filters ()
34973497
34983498 def edit_label (self , item = None ):
34993499 if item and not isinstance (item , LabelListWidgetItem ):
@@ -3577,8 +3577,7 @@ def edit_label(self, item=None):
35773577 else :
35783578 item .setText (f"{ shape .label } ({ shape .group_id } )" )
35793579 self .set_dirty ()
3580- self .update_combo_box ()
3581- self .update_gid_box ()
3580+ self ._refresh_shape_filters ()
35823581
35833582 # update top-right attributes panel
35843583 selected_idx = self .canvas .shapes .index (selected_shapes [0 ])
@@ -4113,7 +4112,7 @@ def shape_selection_changed(self, selected_shapes):
41134112 else :
41144113 self .hide_attributes_panel ()
41154114
4116- def add_label (self , shape , update_last_label = True ):
4115+ def add_label (self , shape , update_last_label = True , refresh_filters = True ):
41174116 if shape .group_id is None :
41184117 text = shape .label
41194118 else :
@@ -4157,8 +4156,8 @@ def add_label(self, shape, update_last_label=True):
41574156 color = shape .fill_color .getRgb ()[:3 ]
41584157 label_list_item .setText ("{}" .format (html .escape (text )))
41594158 label_list_item .setBackground (QtGui .QColor (* color , LABEL_OPACITY ))
4160- self . update_combo_box ()
4161- self .update_gid_box ()
4159+ if refresh_filters :
4160+ self ._refresh_shape_filters ()
41624161
41634162 def load_labels (self , labels , clear_existing = True ):
41644163 """
@@ -4222,17 +4221,24 @@ def remove_labels(self, shapes):
42224221 for shape in shapes :
42234222 item = self .label_list .find_item_by_shape (shape )
42244223 self .label_list .remove_item (item )
4225- self .update_combo_box ()
4226- self .update_gid_box ()
4224+ self ._refresh_shape_filters ()
42274225
42284226 def load_shapes (self , shapes , replace = True , update_last_label = True ):
42294227 self ._no_selection_slot = True
4230- for shape in shapes :
4231- self .add_label (shape , update_last_label = update_last_label )
4232- self .label_list .clearSelection ()
4233- self ._no_selection_slot = False
4228+ self .label_list .setUpdatesEnabled (False )
4229+ try :
4230+ for shape in shapes :
4231+ self .add_label (
4232+ shape ,
4233+ update_last_label = update_last_label ,
4234+ refresh_filters = False ,
4235+ )
4236+ self .label_list .clearSelection ()
4237+ finally :
4238+ self .label_list .setUpdatesEnabled (True )
4239+ self ._no_selection_slot = False
42344240 self .canvas .load_shapes (shapes , replace = replace )
4235- self .apply_label_visibility ()
4241+ self ._refresh_shape_filters ()
42364242
42374243 def load_flags (self , flags ):
42384244 self .flag_widget .clear ()
@@ -4244,18 +4250,57 @@ def load_flags(self, flags):
42444250 )
42454251 self .flag_widget .addItem (item )
42464252
4247- def apply_label_visibility (self ):
4248- for item in self .label_list :
4249- label = item .shape ().label
4250- if label in self .label_info :
4251- is_visible = self .label_info [label ].get ("visible" , True )
4252- else :
4253- is_visible = True
4254- if is_visible :
4255- item .setCheckState (Qt .CheckState .Checked )
4256- else :
4257- item .setCheckState (Qt .CheckState .Unchecked )
4253+ def _sync_label_list_visibility (self , get_visible ):
4254+ model = self .label_list .model ()
4255+ blocker = QtCore .QSignalBlocker (model )
4256+ self .label_list .setUpdatesEnabled (False )
4257+ try :
4258+ for item in self .label_list :
4259+ is_visible = bool (get_visible (item ))
4260+ check_state = (
4261+ Qt .CheckState .Checked
4262+ if is_visible
4263+ else Qt .CheckState .Unchecked
4264+ )
4265+ if item .checkState () != check_state :
4266+ item .setCheckState (check_state )
4267+ shape = item .shape ()
4268+ shape .visible = is_visible
4269+ self .canvas .visible [shape ] = is_visible
4270+ finally :
4271+ self .label_list .setUpdatesEnabled (True )
4272+ del blocker
4273+ self .canvas .update ()
42584274 self ._update_select_toggle_button_tooltip ()
4275+ if (
4276+ hasattr (self , "navigator_dialog" )
4277+ and self .navigator_dialog .isVisible ()
4278+ ):
4279+ self .update_navigator_shapes ()
4280+
4281+ def _refresh_shape_filters (self ):
4282+ self .update_combo_box (block_signal = True )
4283+ self .update_gid_box (block_signal = True )
4284+ current_gid = self .gid_filter_combobox .gid_box .currentText ()
4285+ if current_gid and current_gid != "-1" :
4286+ self .gid_selection_changed (
4287+ self .gid_filter_combobox .gid_box .currentIndex ()
4288+ )
4289+ return
4290+ current_label = self .label_filter_combobox .text_box .currentText ()
4291+ if current_label :
4292+ self .text_selection_changed (
4293+ self .label_filter_combobox .text_box .currentIndex ()
4294+ )
4295+ return
4296+ self .apply_label_visibility ()
4297+
4298+ def apply_label_visibility (self ):
4299+ self ._sync_label_list_visibility (
4300+ lambda item : self .label_info .get (item .shape ().label , {}).get (
4301+ "visible" , True
4302+ )
4303+ )
42594304
42604305 def update_combo_box (self , block_signal = False ):
42614306 current_label = self .label_filter_combobox .text_box .currentText ()
@@ -4366,8 +4411,14 @@ def save_labels(self, filename):
43664411 def duplicate_selected_shape (self ):
43674412 added_shapes = self .canvas .duplicate_selected_shapes ()
43684413 self .label_list .clearSelection ()
4369- for shape in added_shapes :
4370- self .add_label (shape )
4414+ self .label_list .setUpdatesEnabled (False )
4415+ try :
4416+ for shape in added_shapes :
4417+ self .add_label (shape , refresh_filters = False )
4418+ finally :
4419+ self .label_list .setUpdatesEnabled (True )
4420+ if added_shapes :
4421+ self ._refresh_shape_filters ()
43714422 self .set_dirty ()
43724423
43734424 def paste_selected_shape (self ):
@@ -4410,34 +4461,23 @@ def copy_selected_shape(self):
44104461
44114462 def text_selection_changed (self , index ):
44124463 label = self .label_filter_combobox .text_box .itemText (index )
4413- for item in self .label_list :
4414- item_label = item .shape ().label
4415- if label in ["" , item_label ]:
4416- if item_label in self .label_info :
4417- is_visible = self .label_info [item_label ].get (
4418- "visible" , True
4419- )
4420- item .setCheckState (
4421- Qt .CheckState .Checked
4422- if is_visible
4423- else Qt .CheckState .Unchecked
4424- )
4425- else :
4426- item .setCheckState (Qt .CheckState .Checked )
4427- else :
4428- item .setCheckState (Qt .CheckState .Unchecked )
4464+ self ._sync_label_list_visibility (
4465+ lambda item : label in ["" , item .shape ().label ]
4466+ and self .label_info .get (item .shape ().label , {}).get (
4467+ "visible" , True
4468+ )
4469+ )
44294470
44304471 def gid_selection_changed (self , index ):
44314472 gid = self .gid_filter_combobox .gid_box .itemText (index )
4432- for item in self .label_list :
4433- if item .shape ().group_id is not None :
4434- checked_gid = ["-1" , str (item .shape ().group_id )]
4435- else :
4436- checked_gid = ["-1" ]
4437- if str (gid ) in checked_gid :
4438- item .setCheckState (Qt .CheckState .Checked )
4439- else :
4440- item .setCheckState (Qt .CheckState .Unchecked )
4473+ self ._sync_label_list_visibility (
4474+ lambda item : str (gid )
4475+ in (
4476+ ["-1" , str (item .shape ().group_id )]
4477+ if item .shape ().group_id is not None
4478+ else ["-1" ]
4479+ )
4480+ )
44414481
44424482 def label_selection_changed (self ):
44434483 if self ._no_selection_slot :
@@ -5183,8 +5223,6 @@ def load_file(self, filename=None): # noqa: C901
51835223 ** default_flags ,
51845224 ** shape .flags ,
51855225 }
5186- self .update_combo_box ()
5187- self .update_gid_box ()
51885226 self .load_shapes (self .label_file .shapes , update_last_label = False )
51895227 if self .label_file .flags is not None :
51905228 flags .update (self .label_file .flags )
@@ -5842,8 +5880,14 @@ def delete_selected_shape(self):
58425880
58435881 def copy_shape (self ):
58445882 self .canvas .end_move (copy = True )
5845- for shape in self .canvas .selected_shapes :
5846- self .add_label (shape )
5883+ self .label_list .setUpdatesEnabled (False )
5884+ try :
5885+ for shape in self .canvas .selected_shapes :
5886+ self .add_label (shape , refresh_filters = False )
5887+ finally :
5888+ self .label_list .setUpdatesEnabled (True )
5889+ if self .canvas .selected_shapes :
5890+ self ._refresh_shape_filters ()
58475891 self .label_list .clearSelection ()
58485892 self .set_dirty ()
58495893
0 commit comments