Welcome to mirror list, hosted at ThFree Co, Russian Federation.

wm_uilist_type.c « intern « windowmanager « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 82ba4aa6e6f74320cdd3f71eecd497a1a6bcc30d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/** \file
 * \ingroup wm
 *
 * UI List Registry.
 */

#include <stdio.h>
#include <string.h>

#include "BLI_listbase.h"
#include "BLI_sys_types.h"

#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"

#include "MEM_guardedalloc.h"

#include "UI_interface.h"

#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"

#include "BKE_main.h"
#include "BKE_screen.h"

#include "WM_api.h"
#include "WM_types.h"

static GHash *uilisttypes_hash = NULL;

uiListType *WM_uilisttype_find(const char *idname, bool quiet)
{
  if (idname[0]) {
    uiListType *ult = BLI_ghash_lookup(uilisttypes_hash, idname);
    if (ult) {
      return ult;
    }
  }

  if (!quiet) {
    printf("search for unknown uilisttype %s\n", idname);
  }

  return NULL;
}

bool WM_uilisttype_add(uiListType *ult)
{
  BLI_ghash_insert(uilisttypes_hash, ult->idname, ult);
  return 1;
}

static void wm_uilisttype_unlink_from_region(const uiListType *ult, ARegion *region)
{
  LISTBASE_FOREACH (uiList *, list, &region->ui_lists) {
    if (list->type == ult) {
      /* Don't delete the list, it's not just runtime data but stored in files. Freeing would make
       * that data get lost. */
      list->type = NULL;
    }
  }
}

static void wm_uilisttype_unlink_from_area(const uiListType *ult, ScrArea *area)
{
  LISTBASE_FOREACH (SpaceLink *, space_link, &area->spacedata) {
    ListBase *regionbase = (space_link == area->spacedata.first) ? &area->regionbase :
                                                                   &space_link->regionbase;
    LISTBASE_FOREACH (ARegion *, region, regionbase) {
      wm_uilisttype_unlink_from_region(ult, region);
    }
  }
}

/**
 * For all lists representing \a ult, clear their `uiListType` pointer. Use when a list-type is
 * deleted, so that the UI doesn't keep references to it.
 *
 * This is a common pattern for unregistering (usually .py defined) types at runtime, e.g. see
 * #WM_gizmomaptype_group_unlink().
 * Note that unlike in some other cases using this pattern, we don't actually free the lists with
 * type \a ult, we just clear the reference to the type. That's because UI-Lists are written to
 * files and we don't want them to get lost together with their (user visible) settings.
 */
static void wm_uilisttype_unlink(Main *bmain, const uiListType *ult)
{
  for (wmWindowManager *wm = bmain->wm.first; wm != NULL; wm = wm->id.next) {
    LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
      LISTBASE_FOREACH (ScrArea *, global_area, &win->global_areas.areabase) {
        wm_uilisttype_unlink_from_area(ult, global_area);
      }
    }
  }

  for (bScreen *screen = bmain->screens.first; screen != NULL; screen = screen->id.next) {
    LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
      wm_uilisttype_unlink_from_area(ult, area);
    }

    LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
      wm_uilisttype_unlink_from_region(ult, region);
    }
  }
}

void WM_uilisttype_remove_ptr(Main *bmain, uiListType *ult)
{
  wm_uilisttype_unlink(bmain, ult);

  bool ok = BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, MEM_freeN);

  BLI_assert(ok);
  UNUSED_VARS_NDEBUG(ok);
}

/* called on initialize WM_init() */
void WM_uilisttype_init(void)
{
  uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16);
}

void WM_uilisttype_free(void)
{
  GHashIterator gh_iter;
  GHASH_ITER (gh_iter, uilisttypes_hash) {
    uiListType *ult = BLI_ghashIterator_getValue(&gh_iter);
    if (ult->rna_ext.free) {
      ult->rna_ext.free(ult->rna_ext.data);
    }
  }

  BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN);
  uilisttypes_hash = NULL;
}

/**
 * The "full" list-ID is an internal name used for storing and identifying a list. It is built like
 * this:
 * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to
 * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_".
 *
 * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it
 * passed to `UILayout.template_list()`. C code can query that through
 * #WM_uilisttype_list_id_get().
 */
void WM_uilisttype_to_full_list_id(const uiListType *ult,
                                   const char *list_id,
                                   char r_full_list_id[/*UI_MAX_NAME_STR*/])
{
  /* We tag the list id with the list type... */
  BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : "");
}

/**
 * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details.
 *
 * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()!
 */
const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list)
{
  /* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */
  BLI_assert((list->list_id + strlen(ult->idname))[0] == '_');
  /* +1 to skip the '_' */
  return list->list_id + strlen(ult->idname) + 1;
}