1
$\begingroup$

I have an UIList in which I display a PropertyGroup defined like this:

class CUSTOM_PG_library_list(bpy.types.PropertyGroup): lib_name: bpy.props.StringProperty(name ="lib_name") lib_last_mod: bpy.props.IntProperty(name ="lib_last_mod") lib_active: bpy.props.BoolProperty(name="lib_active", default=False) class CUSTOM_UL_items(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): checkbox = "CHECKBOX_HLT" if item.lib_active else "CHECKBOX_DEHLT" split = layout.split(factor=0.1) split.prop(item, "lib_active", text="", emboss=False, icon=checkbox) split.label(text=item.lib_name) 

I never worked with UILists so I have a bit of a hard time to understand how they work.

In the UiList, I would like to be able to only set one checkmark at any time. (Switching the others off). Unfortunately, toggling the checkmark on or off is a different action as selecting one line in the UIList.

Is it possible to bind the click on an UIList line (name or checkmark doesn't matter) together? So if I click on a line it toggles the checkmark belonging to that line to on but also turns all other off. (One needs to be selected, so there can not be a state where all are off.)

How can I achieve this? Do I need an update function to lib_active or some sort of an update function to the UIList itself?

EDIT: Here is the call from the UI:

layout.template_list("CUSTOM_UL_items", "", self, "lib_list", self, "lib_list_index", rows=2) 

The look should be like this:

enter image description here

What I would like to avoid is this:

enter image description here

(UIList selection and Set Checkmark are mismatched.)

I don't know how to "synchronize" the click on a list with the state of a checkmark. For example, I can toggle the checkmark without selecting the list, which is also not what I want. Checkmark and active line in UIList should be always the same.

$\endgroup$
4
  • $\begingroup$ if i understood you right, you don't want a checkmark, but more an enum value, is that right? $\endgroup$ Commented Apr 22, 2024 at 12:54
  • $\begingroup$ Note the data.active_propname value is changed when you click on a UI list element. Where do you store it ? How do you call the ui list template in your layout code ? $\endgroup$ Commented Apr 22, 2024 at 13:25
  • $\begingroup$ I updated the question with the UI call and with some clarification on what I want. @Chris : No, I want the checkmark but always in sync with the selected UIList line. I have some more data in the PropertyGroup which will be displayed, so it is not just the name and the checkmark. $\endgroup$ Commented Apr 22, 2024 at 14:33
  • $\begingroup$ @Gorgious This UIList is shown in my Add-On's preferences. The question is a follow up to my other question: blender.stackexchange.com/questions/316781/… Dealing with Preferences in combination with UIList is very hard for a beginner as there is very little documentation especially on UILists. Outside of the preferences where the SCENE is used for data it is much easier. $\endgroup$ Commented Apr 23, 2024 at 7:38

1 Answer 1

0
$\begingroup$

preferences.lib_list_index is the index of the selected item in your UI list.

You can directly use that to display a checkbox when drawing your item.

class CUSTOM_UL_items(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): # The for loop is used to retrieve the current item index in the list for i, list_item in enumerate(data.lib_list): if list_item == item: break split = layout.split(factor=0.1) checkbox = "CHECKBOX_HLT" if i == getattr(active_data, active_propname) else "CHECKBOX_DEHLT" split.label(text="", icon=checkbox) split.label(text=item.lib_name) 
$\endgroup$
10
  • $\begingroup$ Thank you! When I test it, I get the index number of the selected item instead of a checkbox. What do I do wrong? Also, could you explain what the for loop does? Do active_data and active_propname contain the selected line in the UIList? $\endgroup$ Commented Apr 23, 2024 at 12:54
  • $\begingroup$ So, the for is to loop trough the amount of entries in lib_list and it breaks when it is the same position as the index from the UIList active item. This I think I understand, but i is an integer. Does getattr gives back a "positional" integer where it finds the active_propname in the active_data? $\endgroup$ Commented Apr 23, 2024 at 13:26
  • $\begingroup$ @Steve you understood well. I made a mistake, layout.prop can't show an icon IIRC for an integer field. You can simply set a label with the icon. See my modified answer $\endgroup$ Commented Apr 24, 2024 at 5:57
  • $\begingroup$ Fantastic, thanks! I put a "print(active_data, active_propname)" statement inbetween and it showed lib_list_index as active_propname. I just didn't know how to handle it and change it to lib_active or any other way to display the checkmark. Your modified solution is very simple and elegant! I keep forgetting that the draw_item function is a constant loop. $\endgroup$ Commented Apr 24, 2024 at 12:28
  • $\begingroup$ I'm still confused by the UIList... :-( Where can I put additional code that should be executed when the user clicks on one of the rows? I need to set lib_active in my Property_Group to True on the one item the user clicked but to false on all other items. The code in the UIList is a constant loop, so there is no point constantly setting some variables there. Is there a function that is called when a user clicked on a list item? $\endgroup$ Commented Apr 24, 2024 at 12:59

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.