Merge branch 'master' into blender2.8
[blender-addons.git] / development_icon_get.py
blob3fc7f9b4aa9d57907bd4052c0bce6708851b7973
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # <pep8 compliant>
22 bl_info = {
23 "name": "Icon Viewer",
24 "description": "Click an icon to copy its name to the clipboard",
25 "author": "roaoao",
26 "version": (1, 3, 2),
27 "blender": (2, 80, 0),
28 "location": "Spacebar > Icon Viewer, Text Editor > Properties",
29 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6"
30 "/Py/Scripts/Development/Display_All_Icons",
31 "category": "Development"
34 import bpy
35 import math
37 DPI = 72
38 POPUP_PADDING = 10
39 PANEL_PADDING = 44
40 WIN_PADDING = 32
41 ICON_SIZE = 20
42 HISTORY_SIZE = 100
43 HISTORY = []
46 def ui_scale():
47 prefs = bpy.context.user_preferences.system
48 return prefs.dpi * prefs.pixel_size / DPI
51 def prefs():
52 return bpy.context.user_preferences.addons[__name__].preferences
55 class Icons:
56 def __init__(self, is_popup=False):
57 self._filtered_icons = None
58 self._filter = ""
59 self.filter = ""
60 self.selected_icon = ""
61 self.is_popup = is_popup
63 @property
64 def filter(self):
65 return self._filter
67 @filter.setter
68 def filter(self, value):
69 if self._filter == value:
70 return
72 self._filter = value
73 self.update()
75 @property
76 def filtered_icons(self):
77 if self._filtered_icons is None:
78 self._filtered_icons = []
79 icon_filter = self._filter.upper()
80 self.filtered_icons.clear()
81 pr = prefs()
83 icons = bpy.types.UILayout.bl_rna.functions[
84 "prop"].parameters["icon"].enum_items.keys()
85 for icon in icons:
86 if icon == 'NONE' or \
87 icon_filter and icon_filter not in icon or \
88 not pr.show_brush_icons and "BRUSH_" in icon and \
89 icon != 'BRUSH_DATA' or \
90 not pr.show_matcap_icons and "MATCAP_" in icon or \
91 not pr.show_colorset_icons and "COLORSET_" in icon:
92 continue
93 self._filtered_icons.append(icon)
95 return self._filtered_icons
97 @property
98 def num_icons(self):
99 return len(self.filtered_icons)
101 def update(self):
102 if self._filtered_icons is not None:
103 self._filtered_icons.clear()
104 self._filtered_icons = None
106 def draw(self, layout, num_cols=0, icons=None):
107 if icons:
108 filtered_icons = reversed(icons)
109 else:
110 filtered_icons = self.filtered_icons
112 column = layout.column(True)
113 row = column.row(True)
114 row.alignment = 'CENTER'
116 selected_icon = self.selected_icon if self.is_popup else \
117 bpy.context.window_manager.clipboard
118 col_idx = 0
119 for i, icon in enumerate(filtered_icons):
120 p = row.operator(
121 IV_OT_icon_select.bl_idname, "",
122 icon=icon, emboss=icon == selected_icon)
123 p.icon = icon
124 p.force_copy_on_select = not self.is_popup
126 col_idx += 1
127 if col_idx > num_cols - 1:
128 if icons:
129 break
130 col_idx = 0
131 if i < len(filtered_icons) - 1:
132 row = column.row(True)
133 row.alignment = 'CENTER'
135 if col_idx != 0 and not icons and i >= num_cols:
136 sub = row.row(True)
137 sub.scale_x = num_cols - col_idx
138 sub.label("", icon='BLANK1')
140 if not filtered_icons:
141 row.label("No icons were found")
144 class IV_Preferences(bpy.types.AddonPreferences):
145 bl_idname = __name__
147 panel_icons = Icons()
148 popup_icons = Icons(is_popup=True)
150 def update_icons(self, context):
151 self.panel_icons.update()
152 self.popup_icons.update()
154 def set_panel_filter(self, value):
155 self.panel_icons.filter = value
157 panel_filter: bpy.props.StringProperty(
158 description="Filter",
159 default="",
160 get=lambda s: s.panel_icons.filter,
161 set=set_panel_filter,
162 options={'TEXTEDIT_UPDATE'},
164 show_panel_icons: bpy.props.BoolProperty(
165 name="Show Icons",
166 description="Show icons", default=True,
168 show_history: bpy.props.BoolProperty(
169 name="Show History",
170 description="Show history", default=True,
172 show_brush_icons: bpy.props.BoolProperty(
173 name="Show Brush Icons",
174 description="Show brush icons", default=True,
175 update=update_icons,
177 show_matcap_icons: bpy.props.BoolProperty(
178 name="Show Matcap Icons",
179 description="Show matcap icons", default=True,
180 update=update_icons,
182 show_colorset_icons: bpy.props.BoolProperty(
183 name="Show Colorset Icons",
184 description="Show colorset icons", default=True,
185 update=update_icons,
187 copy_on_select: bpy.props.BoolProperty(
188 name="Copy Icon On Click",
189 description="Copy icon on click", default=True,
191 close_on_select: bpy.props.BoolProperty(
192 name="Close Popup On Click",
193 description=(
194 "Close the popup on click.\n"
195 "Not supported by some windows (User Preferences, Render)"
197 default=False,
199 auto_focus_filter: bpy.props.BoolProperty(
200 name="Auto Focus Input Field",
201 description="Auto focus input field", default=True,
203 show_panel: bpy.props.BoolProperty(
204 name="Show Panel",
205 description="Show the panel in the Text Editor", default=True,
207 show_header: bpy.props.BoolProperty(
208 name="Show Header",
209 description="Show the header in the Python Console",
210 default=True,
213 def draw(self, context):
214 layout = self.layout
215 row = layout.row()
216 row.scale_y = 1.5
217 row.operator(IV_OT_icons_show.bl_idname)
219 row = layout.row()
221 col = row.column(True)
222 col.label("Icons:")
223 col.prop(self, "show_matcap_icons")
224 col.prop(self, "show_brush_icons")
225 col.prop(self, "show_colorset_icons")
226 col.separator()
227 col.prop(self, "show_history")
229 col = row.column(True)
230 col.label("Popup:")
231 col.prop(self, "auto_focus_filter")
232 col.prop(self, "copy_on_select")
233 if self.copy_on_select:
234 col.prop(self, "close_on_select")
236 col = row.column(True)
237 col.label("Panel:")
238 col.prop(self, "show_panel")
239 if self.show_panel:
240 col.prop(self, "show_panel_icons")
242 col.separator()
243 col.label("Header:")
244 col.prop(self, "show_header")
247 class IV_PT_icons(bpy.types.Panel):
248 bl_space_type = "TEXT_EDITOR"
249 bl_region_type = "UI"
250 bl_label = "Icon Viewer"
252 @staticmethod
253 def tag_redraw():
254 wm = bpy.context.window_manager
255 if not wm:
256 return
258 for w in wm.windows:
259 for a in w.screen.areas:
260 if a.type == 'TEXT_EDITOR':
261 for r in a.regions:
262 if r.type == 'UI':
263 r.tag_redraw()
265 def draw(self, context):
266 pr = prefs()
267 row = self.layout.row(True)
268 if pr.show_panel_icons:
269 row.prop(pr, "panel_filter", "", icon='VIEWZOOM')
270 else:
271 row.operator(IV_OT_icons_show.bl_idname)
272 row.operator(IV_OT_panel_menu_call.bl_idname, "", icon='COLLAPSEMENU')
274 _, y0 = context.region.view2d.region_to_view(0, 0)
275 _, y1 = context.region.view2d.region_to_view(0, 10)
276 region_scale = 10 / abs(y0 - y1)
278 num_cols = max(
280 (context.region.width - PANEL_PADDING) //
281 math.ceil(ui_scale() * region_scale * ICON_SIZE))
283 col = None
284 if HISTORY and pr.show_history:
285 col = self.layout.column(True)
286 pr.panel_icons.draw(col.box(), num_cols, HISTORY)
288 if pr.show_panel_icons:
289 col = col or self.layout.column(True)
290 pr.panel_icons.draw(col.box(), num_cols)
292 @classmethod
293 def poll(cls, context):
294 return prefs().show_panel
297 class IV_HT_icons(bpy.types.Header):
298 bl_space_type = 'CONSOLE'
300 def draw(self, context):
301 if not prefs().show_header:
302 return
303 layout = self.layout
304 layout.separator()
305 layout.operator(IV_OT_icons_show.bl_idname)
308 class IV_OT_panel_menu_call(bpy.types.Operator):
309 bl_idname = "iv.panel_menu_call"
310 bl_label = ""
311 bl_description = "Menu"
312 bl_options = {'INTERNAL'}
314 def menu(self, menu, context):
315 pr = prefs()
316 layout = menu.layout
317 layout.prop(pr, "show_panel_icons")
318 layout.prop(pr, "show_history")
320 if not pr.show_panel_icons:
321 return
323 layout.separator()
324 layout.prop(pr, "show_matcap_icons")
325 layout.prop(pr, "show_brush_icons")
326 layout.prop(pr, "show_colorset_icons")
328 def execute(self, context):
329 context.window_manager.popup_menu(self.menu, "Icon Viewer")
330 return {'FINISHED'}
333 class IV_OT_icon_select(bpy.types.Operator):
334 bl_idname = "iv.icon_select"
335 bl_label = ""
336 bl_description = "Select the icon"
337 bl_options = {'INTERNAL'}
339 icon = bpy.props.StringProperty()
340 force_copy_on_select = bpy.props.BoolProperty()
342 def execute(self, context):
343 pr = prefs()
344 pr.popup_icons.selected_icon = self.icon
345 if pr.copy_on_select or self.force_copy_on_select:
346 context.window_manager.clipboard = self.icon
347 self.report({'INFO'}, self.icon)
349 if pr.close_on_select and IV_OT_icons_show.instance:
350 IV_OT_icons_show.instance.close()
352 if pr.show_history:
353 if self.icon in HISTORY:
354 HISTORY.remove(self.icon)
355 if len(HISTORY) >= HISTORY_SIZE:
356 HISTORY.pop(0)
357 HISTORY.append(self.icon)
358 return {'FINISHED'}
361 class IV_OT_icons_show(bpy.types.Operator):
362 bl_idname = "iv.icons_show"
363 bl_label = "Icon Viewer"
364 bl_description = "Icon viewer"
365 bl_property = "filter_auto_focus"
367 instance = None
369 def set_filter(self, value):
370 prefs().popup_icons.filter = value
372 def set_selected_icon(self, value):
373 if IV_OT_icons_show.instance:
374 IV_OT_icons_show.instance.auto_focusable = False
376 filter_auto_focus = bpy.props.StringProperty(
377 description="Filter",
378 get=lambda s: prefs().popup_icons.filter,
379 set=set_filter,
380 options={'TEXTEDIT_UPDATE', 'SKIP_SAVE'})
381 filter = bpy.props.StringProperty(
382 description="Filter",
383 get=lambda s: prefs().popup_icons.filter,
384 set=set_filter,
385 options={'TEXTEDIT_UPDATE'})
386 selected_icon = bpy.props.StringProperty(
387 description="Selected Icon",
388 get=lambda s: prefs().popup_icons.selected_icon,
389 set=set_selected_icon)
391 def get_num_cols(self, num_icons):
392 return round(1.3 * math.sqrt(num_icons))
394 def draw_header(self, layout):
395 pr = prefs()
396 header = layout.box()
397 header = header.split(0.75) if self.selected_icon else header.row()
398 row = header.row(True)
399 row.prop(pr, "show_matcap_icons", "", icon='SMOOTH')
400 row.prop(pr, "show_brush_icons", "", icon='BRUSH_DATA')
401 row.prop(pr, "show_colorset_icons", "", icon='COLOR')
402 row.separator()
404 row.prop(
405 pr, "copy_on_select", "",
406 icon='BORDER_RECT', toggle=True)
407 if pr.copy_on_select:
408 sub = row.row(True)
409 if bpy.context.window.screen.name == "temp":
410 sub.alert = True
411 sub.prop(
412 pr, "close_on_select", "",
413 icon='RESTRICT_SELECT_OFF', toggle=True)
414 row.prop(
415 pr, "auto_focus_filter", "",
416 icon='OUTLINER_DATA_FONT', toggle=True)
417 row.separator()
419 if self.auto_focusable and pr.auto_focus_filter:
420 row.prop(self, "filter_auto_focus", "", icon='VIEWZOOM')
421 else:
422 row.prop(self, "filter", "", icon='VIEWZOOM')
424 if self.selected_icon:
425 row = header.row()
426 row.prop(self, "selected_icon", "", icon=self.selected_icon)
428 def draw(self, context):
429 pr = prefs()
430 col = self.layout
431 self.draw_header(col)
433 history_num_cols = int(
434 (self.width - POPUP_PADDING) / (ui_scale() * ICON_SIZE))
435 num_cols = min(
436 self.get_num_cols(len(pr.popup_icons.filtered_icons)),
437 history_num_cols)
439 subcol = col.column(True)
441 if HISTORY and pr.show_history:
442 pr.popup_icons.draw(subcol.box(), history_num_cols, HISTORY)
444 pr.popup_icons.draw(subcol.box(), num_cols)
446 def close(self):
447 bpy.context.window.screen = bpy.context.window.screen
449 def check(self, context):
450 return True
452 def cancel(self, context):
453 IV_OT_icons_show.instance = None
454 IV_PT_icons.tag_redraw()
456 def execute(self, context):
457 if not IV_OT_icons_show.instance:
458 return {'CANCELLED'}
459 IV_OT_icons_show.instance = None
461 pr = prefs()
462 if self.selected_icon and not pr.copy_on_select:
463 context.window_manager.clipboard = self.selected_icon
464 self.report({'INFO'}, self.selected_icon)
465 pr.popup_icons.selected_icon = ""
467 IV_PT_icons.tag_redraw()
468 return {'FINISHED'}
470 def invoke(self, context, event):
471 pr = prefs()
472 pr.popup_icons.selected_icon = ""
473 pr.popup_icons.filter = ""
474 IV_OT_icons_show.instance = self
475 self.auto_focusable = True
477 num_cols = self.get_num_cols(len(pr.popup_icons.filtered_icons))
478 self.width = min(
479 ui_scale() * (num_cols * ICON_SIZE + POPUP_PADDING),
480 context.window.width - WIN_PADDING)
482 return context.window_manager.invoke_props_dialog(self, self.width)
485 def register():
486 if bpy.app.background:
487 return
489 bpy.utils.register_module(__name__)
492 def unregister():
493 if bpy.app.background:
494 return
496 bpy.utils.unregister_module(__name__)