Removed bundled brush pack
[blender-addons.git] / paint_palette.py
blob10b8fe31ad3b25a18378f74443cfc3776d3f9761
1 # paint_palette.py (c) 2011 Dany Lebel (Axon_D)
3 # ##### BEGIN GPL LICENSE BLOCK #####
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # ##### END GPL LICENSE BLOCK #####
22 bl_info = {
23 "name": "Paint Palettes",
24 "author": "Dany Lebel (Axon D)",
25 "version": (0, 9, 4),
26 "blender": (2, 80, 0),
27 "location": "Image Editor and 3D View > Any Paint mode > Color Palette or Weight Palette panel",
28 "description": "Palettes for color and weight paint modes",
29 "warning": "",
30 "doc_url": "{BLENDER_MANUAL_URL}/addons/paint/paint_palettes.html",
31 "category": "Paint",
34 """
35 This add-on brings palettes to the paint modes.
37 * Color Palette for Image Painting, Texture Paint and Vertex Paint modes.
38 * Weight Palette for the Weight Paint mode.
40 Set a number of colors (or weights according to the mode) and then associate it
41 with the brush by using the button under the color.
42 """
44 import bpy
45 from bpy.types import (
46 Operator,
47 Menu,
48 Panel,
49 PropertyGroup,
51 from bpy.props import (
52 BoolProperty,
53 FloatProperty,
54 FloatVectorProperty,
55 IntProperty,
56 StringProperty,
57 PointerProperty,
58 CollectionProperty,
62 def update_panels():
63 pp = bpy.context.scene.palette_props
64 current_color = pp.colors[pp.current_color_index].color
65 pp.color_name = pp.colors[pp.current_color_index].name
66 brush = current_brush()
67 brush.color = current_color
68 pp.index = pp.current_color_index
71 def sample():
72 pp = bpy.context.scene.palette_props
73 current_color = pp.colors[pp.current_color_index]
74 brush = current_brush()
75 current_color.color = brush.color
76 return None
79 def current_brush():
80 context = bpy.context
81 if context.area.type == 'VIEW_3D' and context.vertex_paint_object:
82 brush = context.tool_settings.vertex_paint.brush
83 elif context.area.type == 'VIEW_3D' and context.image_paint_object:
84 brush = context.tool_settings.image_paint.brush
85 elif context.area.type == 'IMAGE_EDITOR' and context.space_data.mode == 'PAINT':
86 brush = context.tool_settings.image_paint.brush
87 else:
88 brush = None
89 return brush
92 def update_weight_value():
93 pp = bpy.context.scene.palette_props
94 tt = bpy.context.tool_settings
95 tt.unified_paint_settings.weight = pp.weight_value
96 return None
99 def check_path_return():
100 from os.path import normpath
101 preset_path = bpy.path.abspath(bpy.context.scene.palette_props.presets_folder)
102 paths = normpath(preset_path)
104 return paths if paths else ""
107 class PALETTE_MT_menu(Menu):
108 bl_label = "Presets"
109 preset_subdir = ""
110 preset_operator = "palette.load_gimp_palette"
112 def path_menu(self, searchpaths, operator, props_default={}):
113 layout = self.layout
114 # hard coded to set the operators 'filepath' to the filename.
115 import os
116 import bpy.utils
118 layout = self.layout
120 if bpy.data.filepath == "":
121 layout.label(text="*Please save the .blend file first*")
122 return
124 if not searchpaths[0]:
125 layout.label(text="* Missing Paths *")
126 return
128 # collect paths
129 files = []
130 for directory in searchpaths:
131 files.extend([(f, os.path.join(directory, f)) for f in os.listdir(directory)])
133 files.sort()
135 for f, filepath in files:
137 if f.startswith("."):
138 continue
139 # do not load everything from the given folder, only .gpl files
140 if f[-4:] != ".gpl":
141 continue
143 preset_name = bpy.path.display_name(f)
144 props = layout.operator(operator, text=preset_name)
146 for attr, value in props_default.items():
147 setattr(props, attr, value)
149 props.filepath = filepath
150 if operator == "palette.load_gimp_palette":
151 props.menu_idname = self.bl_idname
153 def draw_preset(self, context):
154 paths = check_path_return()
155 self.path_menu([paths], self.preset_operator)
157 draw = draw_preset
160 class PALETTE_OT_load_gimp_palette(Operator):
161 """Execute a preset"""
162 bl_idname = "palette.load_gimp_palette"
163 bl_label = "Load a Gimp palette"
165 filepath: StringProperty(
166 name="Path",
167 description="Path of the .gpl file to load",
168 default=""
170 menu_idname: StringProperty(
171 name="Menu ID Name",
172 description="ID name of the menu this was called from",
173 default=""
176 def execute(self, context):
177 from os.path import basename
178 import re
179 filepath = self.filepath
181 palette_props = bpy.context.scene.palette_props
182 palette_props.current_color_index = 0
184 # change the menu title to the most recently chosen option
185 preset_class = getattr(bpy.types, self.menu_idname)
186 preset_class.bl_label = bpy.path.display_name(basename(filepath))
188 palette_props.columns = 0
189 error_palette = False # errors found
190 error_import = [] # collect exception messages
191 start_color_index = 0 # store the starting line for color definitions
193 if filepath[-4:] != ".gpl":
194 error_palette = True
195 else:
196 gpl = open(filepath, "r")
197 lines = gpl.readlines()
198 palette_props.notes = ''
199 has_color = False
200 for index_0, line in enumerate(lines):
201 if not line or (line[:12] == "GIMP Palette"):
202 pass
203 elif line[:5] == "Name:":
204 palette_props.palette_name = line[5:]
205 elif line[:8] == "Columns:":
206 palette_props.columns = int(line[8:])
207 elif line[0] == "#":
208 palette_props.notes += line
209 elif line[0] == "\n":
210 pass
211 else:
212 has_color = True
213 start_color_index = index_0
214 break
215 i = -1
216 if has_color:
217 for i, ln in enumerate(lines[start_color_index:]):
218 try:
219 palette_props.colors[i]
220 except IndexError:
221 palette_props.colors.add()
222 try:
223 # get line - find keywords with re.split, remove the empty ones with filter
224 get_line = list(filter(None, re.split(r'\t+|\s+', ln.rstrip('\n'))))
225 extract_colors = get_line[:3]
226 get_color_name = [str(name) for name in get_line[3:]]
227 color = [float(rgb) / 255 for rgb in extract_colors]
228 palette_props.colors[i].color = color
229 palette_props.colors[i].name = " ".join(get_color_name) or "Color " + str(i)
230 except Exception as e:
231 error_palette = True
232 error_import.append(".gpl file line: {}, error: {}".format(i + 1 + start_color_index, e))
233 pass
235 exceeding = i + 1
236 while palette_props.colors.__len__() > exceeding:
237 palette_props.colors.remove(exceeding)
239 if has_color:
240 update_panels()
241 gpl.close()
242 pass
244 message = "Loaded palette from file: {}".format(filepath)
246 if error_palette:
247 message = "Not supported palette format for file: {}".format(filepath)
248 if error_import:
249 message = "Some of the .gpl palette data can not be parsed. See Console for more info"
250 print("\n[Paint Palette]\nOperator: palette.load_gimp_palette\nErrors: %s\n" %
251 ('\n'.join(error_import)))
253 self.report({'INFO'}, message)
255 return {'FINISHED'}
258 class WriteGimpPalette():
259 """Base preset class, only for subclassing
260 subclasses must define
261 - preset_values
262 - preset_subdir """
263 bl_options = {'REGISTER'} # only because invoke_props_popup requires
265 name: StringProperty(
266 name="Name",
267 description="Name of the preset, used to make the path name",
268 maxlen=64,
269 options={'SKIP_SAVE'},
270 default=""
272 remove_active: BoolProperty(
273 default=False,
274 options={'HIDDEN'}
277 @staticmethod
278 def as_filename(name): # could reuse for other presets
279 for char in " !@#$%^&*(){}:\";'[]<>,.\\/?":
280 name = name.replace(char, '_')
281 return name.lower().strip()
283 def execute(self, context):
284 import os
285 pp = bpy.context.scene.palette_props
287 if hasattr(self, "pre_cb"):
288 self.pre_cb(context)
290 preset_menu_class = getattr(bpy.types, self.preset_menu)
291 target_path = check_path_return()
293 if not target_path:
294 self.report({'WARNING'}, "Failed to create presets path")
295 return {'CANCELLED'}
297 if not os.path.exists(target_path):
298 self.report({'WARNING'},
299 "Failure to open the saved Palettes Folder. Check if the path exists")
300 return {'CANCELLED'}
302 if not self.remove_active:
303 if not self.name:
304 self.report({'INFO'},
305 "No name is given for the preset entry. Operation Cancelled")
306 return {'FINISHED'}
308 filename = self.as_filename(self.name)
309 filepath = os.path.join(target_path, filename) + ".gpl"
310 file_preset = open(filepath, 'wb')
311 gpl = "GIMP Palette\n"
312 gpl += "Name: %s\n" % filename
313 gpl += "Columns: %d\n" % pp.columns
314 gpl += pp.notes
315 if pp.colors.items():
316 for i, color in enumerate(pp.colors):
317 gpl += "%3d%4d%4d %s" % (color.color.r * 255, color.color.g * 255,
318 color.color.b * 255, color.name + '\n')
319 file_preset.write(bytes(gpl, 'UTF-8'))
321 file_preset.close()
323 pp.palette_name = filename
324 preset_menu_class.bl_label = bpy.path.display_name(filename)
326 self.report({'INFO'}, "Created Palette: {}".format(filepath))
328 else:
329 preset_active = preset_menu_class.bl_label
330 filename = self.as_filename(preset_active)
332 filepath = os.path.join(target_path, filename) + ".gpl"
334 if not filepath or not os.path.exists(filepath):
335 self.report({'WARNING'}, "Preset could not be found. Operation Cancelled")
336 self.reset_preset_name(preset_menu_class, pp)
337 return {'CANCELLED'}
339 if hasattr(self, "remove"):
340 self.remove(context, filepath)
341 else:
342 try:
343 os.remove(filepath)
344 self.report({'INFO'}, "Deleted palette: {}".format(filepath))
345 except:
346 import traceback
347 traceback.print_exc()
349 self.reset_preset_name(preset_menu_class, pp)
351 if hasattr(self, "post_cb"):
352 self.post_cb(context)
354 return {'FINISHED'}
356 @staticmethod
357 def reset_preset_name(presets, props):
358 # XXX, still stupid!
359 presets.bl_label = "Presets"
360 props.palette_name = ""
362 def check(self, context):
363 self.name = self.as_filename(self.name)
365 def invoke(self, context, event):
366 if not self.remove_active:
367 wm = context.window_manager
368 return wm.invoke_props_dialog(self)
370 return self.execute(context)
373 class PALETTE_OT_preset_add(WriteGimpPalette, Operator):
374 bl_idname = "palette.preset_add"
375 bl_label = "Add Palette Preset"
376 preset_menu = "PALETTE_MT_menu"
377 bl_description = "Add a Palette Preset"
379 preset_defines = []
380 preset_values = []
381 preset_subdir = "palette"
384 class PALETTE_OT_add_color(Operator):
385 bl_idname = "palette_props.add_color"
386 bl_label = ""
387 bl_description = "Add a Color to the Palette"
389 def execute(self, context):
390 pp = bpy.context.scene.palette_props
391 new_index = 0
392 if pp.colors.items():
393 new_index = pp.current_color_index + 1
394 pp.colors.add()
396 last = pp.colors.__len__() - 1
398 pp.colors.move(last, new_index)
399 pp.current_color_index = new_index
400 sample()
401 update_panels()
403 return {'FINISHED'}
406 class PALETTE_OT_remove_color(Operator):
407 bl_idname = "palette_props.remove_color"
408 bl_label = ""
409 bl_description = "Remove Selected Color"
411 @classmethod
412 def poll(cls, context):
413 pp = bpy.context.scene.palette_props
414 return bool(pp.colors.items())
416 def execute(self, context):
417 pp = context.scene.palette_props
418 i = pp.current_color_index
419 pp.colors.remove(i)
421 if pp.current_color_index >= pp.colors.__len__():
422 pp.index = pp.current_color_index = pp.colors.__len__() - 1
424 return {'FINISHED'}
427 class PALETTE_OT_sample_tool_color(Operator):
428 bl_idname = "palette_props.sample_tool_color"
429 bl_label = ""
430 bl_description = "Sample Tool Color"
432 def execute(self, context):
433 pp = context.scene.palette_props
434 brush = current_brush()
435 pp.colors[pp.current_color_index].color = brush.color
437 return {'FINISHED'}
440 class IMAGE_OT_select_color(Operator):
441 bl_idname = "paint.select_color"
442 bl_label = ""
443 bl_description = "Select this color"
444 bl_options = {'UNDO'}
446 color_index: IntProperty()
448 def invoke(self, context, event):
449 palette_props = context.scene.palette_props
450 palette_props.current_color_index = self.color_index
452 update_panels()
454 return {'FINISHED'}
457 def color_palette_draw(self, context):
458 palette_props = context.scene.palette_props
460 layout = self.layout
462 row = layout.row(align=True)
463 row.menu("PALETTE_MT_menu", text=PALETTE_MT_menu.bl_label)
464 row.operator("palette.preset_add", text="", icon='ADD').remove_active = False
465 row.operator("palette.preset_add", text="", icon='REMOVE').remove_active = True
467 col = layout.column(align=True)
468 row = col.row(align=True)
469 row.operator("palette_props.add_color", icon='ADD')
470 row.prop(palette_props, "index")
471 row.operator("palette_props.remove_color", icon="PANEL_CLOSE")
473 row = col.row(align=True)
474 row.prop(palette_props, "columns")
475 if palette_props.colors.items():
476 layout = col.box()
477 row = layout.row(align=True)
478 row.prop(palette_props, "color_name")
479 row.operator("palette_props.sample_tool_color", icon="COLOR")
481 laycol = layout.column(align=False)
483 if palette_props.columns:
484 columns = palette_props.columns
485 else:
486 columns = 16
488 for i, color in enumerate(palette_props.colors):
489 if not i % columns:
490 row1 = laycol.row(align=True)
491 row1.scale_y = 0.8
492 row2 = laycol.row(align=True)
493 row2.scale_y = 0.8
495 active = True if i == palette_props.current_color_index else False
496 icons = "LAYER_ACTIVE" if active else "LAYER_USED"
497 row1.prop(palette_props.colors[i], "color", event=True, toggle=True)
498 row2.operator("paint.select_color", text=" ",
499 emboss=active, icon=icons).color_index = i
501 layout = self.layout
502 row = layout.row()
503 row.prop(palette_props, "presets_folder", text="")
506 class BrushButtonsPanel():
507 bl_space_type = 'IMAGE_EDITOR'
508 bl_region_type = 'UI'
510 @classmethod
511 def poll(cls, context):
512 sima = context.space_data
513 toolsettings = context.tool_settings.image_paint
514 return sima.show_paint and toolsettings.brush
517 class PaintPanel():
518 bl_space_type = 'VIEW_3D'
519 bl_region_type = 'UI'
520 bl_category = 'Paint'
522 @staticmethod
523 def paint_settings(context):
524 ts = context.tool_settings
526 if context.vertex_paint_object:
527 return ts.vertex_paint
528 elif context.weight_paint_object:
529 return ts.weight_paint
530 elif context.texture_paint_object:
531 return ts.image_paint
532 return None
535 class IMAGE_PT_color_palette(BrushButtonsPanel, Panel):
536 bl_label = "Color Palette"
537 bl_options = {'DEFAULT_CLOSED'}
539 def draw(self, context):
540 color_palette_draw(self, context)
543 class VIEW3D_PT_color_palette(PaintPanel, Panel):
544 bl_label = "Color Palette"
545 bl_options = {'DEFAULT_CLOSED'}
547 @classmethod
548 def poll(cls, context):
549 return (context.image_paint_object or context.vertex_paint_object)
551 def draw(self, context):
552 color_palette_draw(self, context)
555 class VIEW3D_OT_select_weight(Operator):
556 bl_idname = "paint.select_weight"
557 bl_label = ""
558 bl_description = "Select this weight value slot"
559 bl_options = {'UNDO'}
561 weight_index: IntProperty()
563 def current_weight(self):
564 pp = bpy.context.scene.palette_props
565 if self.weight_index == 0:
566 weight = pp.weight_0
567 elif self.weight_index == 1:
568 weight = pp.weight_1
569 elif self.weight_index == 2:
570 weight = pp.weight_2
571 elif self.weight_index == 3:
572 weight = pp.weight_3
573 elif self.weight_index == 4:
574 weight = pp.weight_4
575 elif self.weight_index == 5:
576 weight = pp.weight_5
577 elif self.weight_index == 6:
578 weight = pp.weight_6
579 elif self.weight_index == 7:
580 weight = pp.weight_7
581 elif self.weight_index == 8:
582 weight = pp.weight_8
583 elif self.weight_index == 9:
584 weight = pp.weight_9
585 elif self.weight_index == 10:
586 weight = pp.weight_10
587 return weight
589 def invoke(self, context, event):
590 palette_props = context.scene.palette_props
591 palette_props.current_weight_index = self.weight_index
593 if self.weight_index == 0:
594 weight = palette_props.weight_0
595 elif self.weight_index == 1:
596 weight = palette_props.weight_1
597 elif self.weight_index == 2:
598 weight = palette_props.weight_2
599 elif self.weight_index == 3:
600 weight = palette_props.weight_3
601 elif self.weight_index == 4:
602 weight = palette_props.weight_4
603 elif self.weight_index == 5:
604 weight = palette_props.weight_5
605 elif self.weight_index == 6:
606 weight = palette_props.weight_6
607 elif self.weight_index == 7:
608 weight = palette_props.weight_7
609 elif self.weight_index == 8:
610 weight = palette_props.weight_8
611 elif self.weight_index == 9:
612 weight = palette_props.weight_9
613 elif self.weight_index == 10:
614 weight = palette_props.weight_10
615 palette_props.weight = weight
617 return {'FINISHED'}
620 class VIEW3D_OT_reset_weight_palette(Operator):
621 bl_idname = "paint.reset_weight_palette"
622 bl_label = ""
623 bl_description = "Reset the active Weight slot to it's default value"
625 def execute(self, context):
626 try:
627 palette_props = context.scene.palette_props
628 dict_defs = {
629 0: 0.0, 1: 0.1, 2: 0.25,
630 3: 0.333, 4: 0.4, 5: 0.5,
631 6: 0.6, 7: 0.6666, 8: 0.75,
632 9: 0.9, 10: 1.0
634 current_idx = palette_props.current_weight_index
635 palette_props.weight = dict_defs[current_idx]
637 var_name = "weight_" + str(current_idx)
638 var_to_change = getattr(palette_props, var_name, None)
639 if var_to_change:
640 var_to_change = dict_defs[current_idx]
642 return {'FINISHED'}
644 except Exception as e:
645 self.report({'WARNING'},
646 "Reset Weight palette could not be completed (See Console for more info)")
647 print("\n[Paint Palette]\nOperator: paint.reset_weight_palette\nError: %s\n" % e)
649 return {'CANCELLED'}
652 class VIEW3D_PT_weight_palette(PaintPanel, Panel):
653 bl_label = "Weight Palette"
654 bl_options = {'DEFAULT_CLOSED'}
656 @classmethod
657 def poll(cls, context):
658 return context.weight_paint_object
660 def draw(self, context):
661 palette_props = context.scene.palette_props
663 layout = self.layout
664 row = layout.row()
665 row.prop(palette_props, "weight", slider=True)
666 box = layout.box()
668 selected_weight = palette_props.current_weight_index
669 for props in range(0, 11):
670 embossed = False if props == selected_weight else True
671 prop_name = "weight_" + str(props)
672 prop_value = getattr(palette_props, prop_name, "")
673 if props in (0, 10):
674 row = box.row(align=True)
675 elif (props + 2) % 3 == 0:
676 col = box.column(align=True)
677 row = col.row(align=True)
678 else:
679 if props == 1:
680 row = box.row(align=True)
681 row = row.row(align=True)
683 row.operator("paint.select_weight", text="%.2f" % prop_value,
684 emboss=embossed).weight_index = props
686 row = layout.row()
687 row.operator("paint.reset_weight_palette", text="Reset")
690 class PALETTE_Colors(PropertyGroup):
691 """Class for colors CollectionProperty"""
692 color: FloatVectorProperty(
693 name="",
694 description="",
695 default=(0.8, 0.8, 0.8),
696 min=0, max=1,
697 step=1, precision=3,
698 subtype='COLOR_GAMMA',
699 size=3
703 class PALETTE_Props(PropertyGroup):
705 def update_color_name(self, context):
706 pp = bpy.context.scene.palette_props
707 pp.colors[pp.current_color_index].name = pp.color_name
708 return None
710 def move_color(self, context):
711 pp = bpy.context.scene.palette_props
712 if pp.colors.items() and pp.current_color_index != pp.index:
713 if pp.index >= pp.colors.__len__():
714 pp.index = pp.colors.__len__() - 1
716 pp.colors.move(pp.current_color_index, pp.index)
717 pp.current_color_index = pp.index
718 return None
720 def update_weight(self, context):
721 pp = context.scene.palette_props
722 weight = pp.weight
723 if pp.current_weight_index == 0:
724 pp.weight_0 = weight
725 elif pp.current_weight_index == 1:
726 pp.weight_1 = weight
727 elif pp.current_weight_index == 2:
728 pp.weight_2 = weight
729 elif pp.current_weight_index == 3:
730 pp.weight_3 = weight
731 elif pp.current_weight_index == 4:
732 pp.weight_4 = weight
733 elif pp.current_weight_index == 5:
734 pp.weight_5 = weight
735 elif pp.current_weight_index == 6:
736 pp.weight_6 = weight
737 elif pp.current_weight_index == 7:
738 pp.weight_7 = weight
739 elif pp.current_weight_index == 8:
740 pp.weight_8 = weight
741 elif pp.current_weight_index == 9:
742 pp.weight_9 = weight
743 elif pp.current_weight_index == 10:
744 pp.weight_10 = weight
745 bpy.context.tool_settings.unified_paint_settings.weight = weight
746 return None
748 palette_name: StringProperty(
749 name="Palette Name",
750 default="Preset",
751 subtype='FILE_NAME'
753 color_name: StringProperty(
754 name="",
755 description="Color Name",
756 default="Untitled",
757 update=update_color_name
759 columns: IntProperty(
760 name="Columns",
761 description="Number of Columns",
762 min=0, max=16,
763 default=0
765 index: IntProperty(
766 name="Index",
767 description="Move Selected Color",
768 min=0,
769 update=move_color
771 notes: StringProperty(
772 name="Palette Notes",
773 default="#\n"
775 current_color_index: IntProperty(
776 name="Current Color Index",
777 description="",
778 default=0,
779 min=0
781 current_weight_index: IntProperty(
782 name="Current Color Index",
783 description="",
784 default=10,
785 min=-1
787 presets_folder: StringProperty(name="",
788 description="Palettes Folder",
789 subtype="DIR_PATH",
790 default="//"
792 colors: CollectionProperty(
793 type=PALETTE_Colors
795 weight: FloatProperty(
796 name="Weight",
797 description="Modify the active Weight preset slot value",
798 default=0.0,
799 min=0.0, max=1.0,
800 precision=3,
801 update=update_weight
803 weight_0: FloatProperty(
804 default=0.0,
805 min=0.0, max=1.0,
806 precision=3
808 weight_1: FloatProperty(
809 default=0.1,
810 min=0.0, max=1.0,
811 precision=3
813 weight_2: FloatProperty(
814 default=0.25,
815 min=0.0, max=1.0,
816 precision=3
818 weight_3: FloatProperty(
819 default=0.333,
820 min=0.0, max=1.0,
821 precision=3
823 weight_4: FloatProperty(
824 default=0.4,
825 min=0.0, max=1.0,
826 precision=3
828 weight_5: FloatProperty(
829 default=0.5,
830 min=0.0, max=1.0,
831 precision=3
833 weight_6: FloatProperty(
834 default=0.6,
835 min=0.0, max=1.0,
836 precision=3
838 weight_7: FloatProperty(
839 default=0.6666,
840 min=0.0, max=1.0,
841 precision=3
843 weight_8: FloatProperty(
844 default=0.75,
845 min=0.0, max=1.0,
846 precision=3
848 weight_9: FloatProperty(
849 default=0.9,
850 min=0.0, max=1.0,
851 precision=3
853 weight_10: FloatProperty(
854 default=1.0,
855 min=0.0, max=1.0,
856 precision=3
860 classes = (
861 PALETTE_MT_menu,
862 PALETTE_OT_load_gimp_palette,
863 PALETTE_OT_preset_add,
864 PALETTE_OT_add_color,
865 PALETTE_OT_remove_color,
866 PALETTE_OT_sample_tool_color,
867 IMAGE_OT_select_color,
868 IMAGE_PT_color_palette,
869 VIEW3D_PT_color_palette,
870 VIEW3D_OT_select_weight,
871 VIEW3D_OT_reset_weight_palette,
872 VIEW3D_PT_weight_palette,
873 PALETTE_Colors,
874 PALETTE_Props,
878 def register():
879 for cls in classes:
880 bpy.utils.register_class(cls)
882 bpy.types.Scene.palette_props = PointerProperty(
883 type=PALETTE_Props,
884 name="Palette Props",
885 description=""
889 def unregister():
890 for cls in reversed(classes):
891 bpy.utils.unregister_class(cls)
893 del bpy.types.Scene.palette_props
896 if __name__ == "__main__":
897 register()