forked from jayanam/bl_ui_widgets
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathdemo_panel_op.py
628 lines (546 loc) · 28.8 KB
/
demo_panel_op.py
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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.
#
# ##### END GPL LICENSE BLOCK #####
# --- ### Header
bl_info = {"name": "BL UI Widgets",
"description": "UI Widgets to draw in the 3D view",
"author": "Marcelo M. Marques (fork of Jayanam's original project)",
"version": (1, 0, 6),
"blender": (3, 0, 0),
"location": "View3D > viewport area",
"support": "COMMUNITY",
"category": "3D View",
"warning": "Version numbering diverges from Jayanam's original project",
"doc_url": "https://github.com/mmmrqs/bl_ui_widgets",
"tracker_url": "https://github.com/mmmrqs/bl_ui_widgets/issues"
}
# --- ### Change log
# v1.0.6 (05.27.2023) - by atticus-lv
# Chang: Added example on how to use the new bind_operator function -- see code for the 'self.button3' below
# v1.0.5 (03.06.2023) - by Marcelo M. Marques
# Added: 'time_step' property to allow customization of the interval in seconds between timer events
# v1.0.4 (09.28.2022) - by Marcelo M. Marques
# Added: Logic to 'poll' classmethod that prevents the panel to be opened in multiple simultaneous instances.
# v1.0.3 (09.25.2022) - by Marcelo M. Marques
# Added: Logic to 'on_invoke' function to identify when in QuadView mode and to position the remote panel appropriately so it
# does not get stuck lost out of visible region.
# Added: New statement necessary for the remote panel to stay open when called by Blender's <F3> menu.
# Added: Logic to 'terminate_execution' function to automatically close the panel if user switches between regular and QuadView display modes.
# Added: Logic to 'terminate_execution' function to keep a session variable updated with the clock time that will allow the modal operator
# to identify any odd situation in which the panel is no more active and must be automatically closed.
# Chang: Some notes and comments for better documentation
# v1.0.2 (10.31.2021) - by Marcelo M. Marques
# Added: 'valid_modes' property to indicate the 'bpy.context.mode' valid values for displaying the panel.
# Added: 'suppress_rendering' function that can be optionally used to control render bypass of the panel widget.
# Added: 'area' and 'region' input parameters to the overridable 'terminate_execution()' function.
# v1.0.1 (09.20.2021) - by Marcelo M. Marques
# Chang: just some pep8 code formatting
# v1.0.0 (09.01.2021) - by Marcelo M. Marques
# Added: 'terminate_execution' function that can be overriden by programmer to command termination of the 'Floating Panel'.
# Added: New properties and functions to all widgets (check their corresponding modules for more information).
# --- ### Imports
import bpy
import time
import os
from bpy.types import Operator
from .bl_ui_label import BL_UI_Label
from .bl_ui_patch import BL_UI_Patch
from .bl_ui_checkbox import BL_UI_Checkbox
from .bl_ui_slider import BL_UI_Slider
from .bl_ui_textbox import BL_UI_Textbox
from .bl_ui_button import BL_UI_Button
from .bl_ui_tooltip import BL_UI_Tooltip
from .bl_ui_draw_op import BL_UI_OT_draw_operator
from .bl_ui_drag_panel import BL_UI_Drag_Panel
from .bl_ui_widget_demo import is_quadview_region
class DP_OT_draw_operator(BL_UI_OT_draw_operator): # in: bl_ui_draw_op.py ##
bl_idname = "object.dp_ot_draw_operator"
bl_label = "bl ui widgets custom operator"
bl_description = "Operator for bl ui widgets"
bl_options = {'REGISTER'}
# --- Blender interface methods quick documentation
# def poll: checked before running the operator, which will never run when poll fails.
# used to check if an operator can run, menu items will be greyed out and if key bindings should be ignored.
#
# def invoke: called by default when accessed from a key binding and menu, this takes the current context - mouse location.
# used for interactive operations such as dragging & drawing. (hint: think of this as "run by a person")
#
# def description: allows a dynamic tooltip that changes based on the context and operator parameters.
#
# def draw: called to draw options, giving control over the layout. Without this, options will draw in the order they are defined.
#
# def modal: handles events which would normally access other operators, they keep running until they return FINISHED.
# used for operators which continuously run, eg: fly mode, knife tool, circle select are all examples of modal operators.
#
# def execute: runs the operator, assuming values are set by the caller (else use defaults).
# used for undo/redo, and executing operators from Python.
#
# def cancel: called when Blender cancels a modal operator, not used often. Internal cleanup can be done here if needed.
# --- methods
@classmethod
def poll(cls, context):
# Show this panel in View_3D only
if context.space_data.type != 'VIEW_3D':
return False
# Prevents multiple instances of panel
try:
if context.scene.var.RemoVisible and int(time.time()) - context.scene.var.btnRemoTime <= 1:
return False
except:
return False
return True
def __init__(self):
super().__init__()
if __package__.find(".") != -1:
package = __package__[0:__package__.find(".")]
else:
package = __package__
# The values assigned to the self.valid_modes variable below will be used to restrict panel display
# to those options only. Set it accordingly to the desired functionality of your particular addon.
#
# Possible valid mode options (as of Blender 2.8):
# 'EDIT_MESH', 'EDIT_CURVE', 'EDIT_SURFACE', 'EDIT_TEXT', 'EDIT_ARMATURE', 'EDIT_METABALL',
# 'EDIT_LATTICE', 'POSE', 'SCULPT', 'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE', 'PARTICLE',
# 'OBJECT', 'PAINT_GPENCIL', 'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'
# Additional valid mode option (as of Blender 2.9):
# 'VERTEX_GPENCIL'
# Additional valid mode options (as of Blender 3.2):
# 'EDIT_CURVES', 'SCULPT_CURVES'
# Note: Leave it empty, e.g. self.valid_modes = {}, for no restrictions to be applied.
self.valid_modes = {'OBJECT', 'EDIT_MESH'}
# (float in [0, inf]) – Custom Interval in seconds between timer events (default = 0.1)
self.time_step = 0.5
# From Preferences/Themes/User Interface/"State"
theme = bpy.context.preferences.themes[0]
ui = theme.user_interface
widget_style = getattr(ui, "wcol_state")
status_color = tuple(widget_style.inner_changed) + (0.3,)
btnC = 0 # Element counter
btnS = 4 # Button separation (for the smallest ones)
btnG = 0 # Button gap (for the biggest ones)
btnW = 56 # Button width
btnH = 40 + btnS # Button height (takes 2 small buttons plus their separation)
marginX = 16 # Margin from left border
marginY = 27 # Margin from top border
btnX = marginX + 1 # Button position X (for the very first button)
btnY = marginY + 1 # Button position Y (for the very first button)
self.button1 = BL_UI_Button(btnX, btnY, btnW, btnH)
self.button1.style = 'RADIO'
self.button1.text = "PUSH"
self.button1.textwo = "-ME-"
self.button1.text_size = 13
self.button1.textwo_size = 10
self.button1.rounded_corners = (1, 1, 0, 0)
self.button1.set_mouse_up(self.button1_click)
self.button1.set_button_pressed(self.button1_pressed)
self.button1.description = "Press this button to unlock its brothers (after the button " + \
"with a 'LOCK' caption has been pressed). {Let me " + \
"type a very large description here to showcase a " + \
"tooltip text automatically being wrapped around " + \
"multiple lines inside its containing box}. Whatever " + \
"comes beyond the defined limit of maximum lines " + \
"will be left out! You'll see this text will be truncated..."
self.button1.shortcut = "Shortcut: None"
self.button1.python_cmd = "bpy.ops.object.dp_ot_draw_operator.button1_click()"
if self.button1_pressed(self.button1):
self.button1.state = 3
btnC += 1
#
self.button2 = BL_UI_Button((btnX + ((btnW - 1 + btnG) * btnC)), btnY, btnW, btnH)
self.button2.style = 'RADIO'
self.button2.text = "HELP"
self.button2.textwo = "(Go)"
self.button2.text_size = 13
self.button2.textwo_size = 10
self.button2.rounded_corners = (0, 0, 0, 0)
self.button2.set_mouse_up(self.button2_click)
self.button2.set_button_pressed(self.button2_pressed)
self.button2.description = "You can help me by doing as follows:\n" + \
" -Press button 4 to Disable Me\n" + \
" -Press button 1 to Enable Me"
self.button2.python_cmd = "bpy.ops.object.dp_ot_draw_operator.button2_click()"
if self.button2_pressed(self.button2):
self.button2.state = 3
btnC += 1
#
# For this next example it is shown the old/standard style for defining a button (see the "if True" section) and the alternative
# style (as of v1.0.6, see the 'else' section) that is to use the newly added bind_operator method (which is more compact).
# Notice that by using the new method there is not a way to call custom functions though. This may get enhanced in the future.
self.button3 = BL_UI_Button((btnX + ((btnW - 1 + btnG) * btnC)), btnY, btnW, btnH)
self.button3.text_size = 13
self.button3.rounded_corners = (0, 0, 0, 0)
if True:
self.button3.style = 'RADIO'
self.button3.text = "ADD"
self.button3.set_mouse_up(self.button3_click)
self.button3.set_button_pressed(self.button3_pressed)
self.button3.description = "Adds one little 'MONKEY' object to 3D View area"
self.button3.python_cmd = "bpy.ops.object.dp_ot_draw_operator.button3_click()"
self.button3.rounded_corners = (0, 0, 0, 0)
else:
self.button3.bind_operator('mesh.primitive_monkey_add', text ='ADD')
# self.button3.bind_operator('mesh.primitive_monkey_add', text ='ADD', icon_path=r'ERROR PATH TEST')
if self.button3_pressed(self.button3):
self.button3.state = 3
btnC += 1
#
self.button4 = BL_UI_Button((btnX + ((btnW - 1 + btnG) * btnC)), btnY, btnW, btnH)
self.button4.style = 'RADIO'
self.button4.text = "LOCK"
self.button4.textwo = "(CTRL-L)"
self.button4.text_size = 13
self.button4.textwo_size = 10
self.button4.rounded_corners = (0, 0, 1, 1)
self.button4.set_mouse_up(self.button4_click)
self.button4.set_button_pressed(self.button4_pressed)
self.button4.enabled = (not bpy.context.scene.var.OpState6)
self.button4.description = "This button does nothing more than to disable 2 and 3.\n" +\
"Note: CTRL-L does not actually work as a short-cut, but " +\
"you could have programmed it to do so"
# In this example there is no .python_cmd populated, thus only the main description appears in the tooltip
if self.button4_pressed(self.button4):
self.button4.state = 3
btnC += 1
oldX = (btnX + ((btnW - 1 + btnG) * btnC))
oldH = btnH
oldW = btnW
newX = oldX + marginX + btnW - 1 + btnS
btnW = 96
btnH = 20
#
self.button5 = BL_UI_Button(newX, btnY, btnW, btnH)
self.button5.text = "Do Nothing"
newY = btnY + btnH + btnS
#
self.button6 = BL_UI_Button(newX, newY, btnW, btnH)
self.button6.selected_color = status_color
self.button6.text = "Switch Btn 4"
self.button6.set_mouse_up(self.button6_click)
self.button6.set_button_pressed(self.button6_pressed)
self.button6.description = "Switches button 4's state"
if self.button6_pressed(self.button6):
self.button6.state = 3
#
newX = newX + btnW - 1 + btnS
btnW = 120
#
self.number1 = BL_UI_Slider(newX, btnY, btnW, btnH)
self.number1.style = 'NUMBER_CLICK'
self.number1.value = 500
self.number1.step = 100
self.number1.unit = "m"
self.number1.precision = 0
self.number1.description = "This is a click slider component and it can work with a full range of values"
self.number1.set_value_updated(self.number1_update)
#
self.slider1 = BL_UI_Slider(newX, newY, btnW, btnH)
self.slider1.style = 'NUMBER_SLIDE'
self.slider1.text = "Z Rot"
self.slider1.value = 180
self.slider1.min = 0
self.slider1.max = 360
self.slider1.description = "This is a standard slider component with a 0 to 100 sliding percent bar.\nYou can use it to rotate the selected object(s) in the scene"
self.slider1.set_value_updated(self.slider1_update)
#
self.objname = "<Press the ADD button so you can edit here>"
self.textbox1 = BL_UI_Textbox(btnX, newY + 35, 350, btnH)
self.textbox1.text = self.objname
self.textbox1.max_input_chars = 50
self.textbox1.description = "Textbox editing entry field"
self.textbox1.set_value_changed(self.textbox1_changed)
self.textbox1.enabled = False
#
self.check1 = BL_UI_Checkbox(newX, newY + 37, btnW, btnH)
self.check1.text = "Unregit"
self.check1.set_value_changed(self.check1_changed)
self.check1.description = "This checkbox accesses an 'UNREGISTER' fully circular button"
self.check1.python_cmd = "bpy.ops.object.dp_ot_draw_operator.check1_changed()"
self.check1.is_checked = False
# -----------
panW = newX + btnW + 2 + marginX # Panel desired width (beware: this math is good for my setup only)
panH = newY + btnH + 0 + 10 + 35 # Panel desired height (ditto)
# Save the panel's size to preferences properties to be used in there
bpy.context.preferences.addons[package].preferences.RC_PAN_W = panW
bpy.context.preferences.addons[package].preferences.RC_PAN_H = panH
# Need this just because I want the panel to be centered
if bpy.context.preferences.addons[package].preferences.RC_UI_BIND:
# From Preferences/Interface/"Display"
ui_scale = bpy.context.preferences.view.ui_scale
else:
ui_scale = 1
over_scale = bpy.context.preferences.addons[package].preferences.RC_SCALE
# The panel X and Y coords are in relation to the bottom-left corner of the 3D viewport area
panX = int((bpy.context.area.width - panW * ui_scale * over_scale) / 2.0) + 1 # Panel X coordinate, for panel's top-left corner
panY = panH + 100 - 1 # The '100' is just a spacing # Panel Y coordinate, for panel's top-left corner
self.panel = BL_UI_Drag_Panel(panX, panY, panW, panH)
self.panel.style = 'PANEL' # Options are: {HEADER,PANEL,SUBPANEL,TOOLTIP,NONE}
self.tooltip = BL_UI_Tooltip() # This is for displaying the widgets tooltips. Only need one instance!
self.patch1 = BL_UI_Patch(0, 0, panW, 17)
self.patch1.style = 'HEADER'
self.patch1.set_mouse_move(self.patch1_mouse_move)
self.label1 = BL_UI_Label(5, 12, panW, 17)
self.label1.style = 'TITLE'
self.label1.text = "Panel Title For Example"
self.label1.size = 12
self.label2 = BL_UI_Label(panW - 100, 12, 100, 17)
self.label2.text = "" # This empty text label will be used later on to display some dynamic values on the panel
self.patch2 = BL_UI_Patch(oldX + 10, btnY, oldW, oldH)
self.patch2.bg_color = (0, 0, 0, 0)
self.patch2.outline_color = (1, 1, 1, 0.4)
self.patch2.roundness = 0.4
self.patch2.corner_radius = 10
self.patch2.shadow = True
self.patch2.rounded_corners = (1, 1, 1, 1)
self.patch2.description = "This could be any image (size, color, transparent etc)\n" + \
"and the cool part is that it scales together with the panel"
script_file = os.path.realpath(__file__)
directory = os.path.dirname(script_file)
imagePath = directory + "\\img\\rotate.png"
self.patch2.set_image(imagePath)
self.patch2.set_image_size((32, 32))
self.patch2.set_image_position((11, 5))
# -----------
# Display an 'UNRegister' button on screen
# ==================================================================
# -- This is just for demonstration, not to be used in production
# ==================================================================
btnH = 32
newX = panW - marginX - btnH - 2
newY = panH - btnH - 6
self.buttonU = BL_UI_Button(newX, newY, btnH, btnH)
self.buttonU.text = "UNR"
self.buttonU.text_size = 12
self.buttonU.text_color = (1, 1, 1, 1)
self.buttonU.bg_color = (0.5, 0, 0, 1)
self.buttonU.outline_color = (0.6, 0.6, 0.6, 0.8)
self.buttonU.corner_radius = btnH / 2 - 1
self.buttonU.roundness = 1.0
self.buttonU.set_mouse_up(self.buttonU_click)
self.buttonU.description = "Unregisters the Remote Control panel object and closes it"
self.buttonU.python_cmd = "bpy.ops.object.dp_ot_draw_operator.buttonU_click()"
self.buttonU.visible = False
def on_invoke(self, context, event):
# Add your widgets here (TODO: perhaps a better, more automated solution?)
# --------------------------------------------------------------------------------------------------
widgets_panel = [self.panel
]
widgets_items = [self.patch1, self.patch2, self.label1, self.label2,
self.button1, self.button2, self.button3, self.button4, self.button5, self.button6,
self.buttonU, self.slider1, self.number1, self.check1, self.textbox1,
self.tooltip, # <-- If there is a tooltip object, it must be the last in this list
]
# --------------------------------------------------------------------------------------------------
widgets = widgets_panel + widgets_items
self.init_widgets(context, widgets, self.valid_modes)
self.panel.add_widgets(widgets_items)
self.panel.quadview, _, region = is_quadview_region(context)
if self.panel.quadview and region:
# When in QuadView mode it has to be manually repositioned otherwise may get stuck out of region space
if __package__.find(".") != -1:
package = __package__[0:__package__.find(".")]
else:
package = __package__
if bpy.context.preferences.addons[package].preferences.RC_UI_BIND:
# From Preferences/Interface/"Display"
ui_scale = bpy.context.preferences.view.ui_scale
else:
ui_scale = 1
over_scale = bpy.context.preferences.addons[package].preferences.RC_SCALE
panX = int((region.width - (self.panel.width * ui_scale * over_scale)) / 2.0) + 1
panY = self.panel.height + 10 - 1 # The '10' is just a spacing from region border
self.panel.set_location(panX, panY)
else:
self.panel.set_location(self.panel.x, self.panel.y)
# This statement is necessary so that the remote panel stays open when called by Blender's <F3> menu
bpy.context.scene.var.RemoVisible = True
# -- Helper function
def suppress_rendering(self, area, region):
'''
This is a special case 'overriding function' to allow subclass control for displaying (rendering) the panel.
Function is defined in class BL_UI_OT_draw_operator (bl_ui_draw_op.py) and available to be inherited here.
If not included here the function in the superclass just returns 'False' and rendering is always executed.
When 'True" is returned below, the rendering of the entire panel is bypassed and it is not drawn on screen.
'''
return False
def terminate_execution(self, area, region, event):
'''
This is a special case 'overriding function' to allow subclass control for terminating/closing the panel.
Function is defined in class BL_UI_OT_draw_operator (bl_ui_draw_op.py) and available to be inherited here.
If not included here the function in the superclass just returns 'False' and no termination is executed.
When 'True" is returned below, the execution is auto terminated and the 'Remote Control' panel closes itself.
'''
'''
BEWARE THAT ARGUMENTS 'AREA' AND/OR 'REGION' CAN BE EQUAL TO "NONE"
'''
if self.panel.quadview and area is None:
bpy.context.scene.var.RemoVisible = False
else:
if not area is None:
if area.type == 'VIEW_3D':
# If user switches between regular and QuadView display modes, the panel is automatically closed
is_quadview = (len(area.spaces.active.region_quadviews) > 0)
if self.panel.quadview != is_quadview:
bpy.context.scene.var.RemoVisible = False
if event.type == 'TIMER' and bpy.context.scene.var.RemoVisible:
# Update the remote panel "clock marker". This marker is used to keep track if the remote panel is
# actually opened and active. In the case that bpy.context.scene.var.RemoVisible state gets misleading
# the panel will be automatically closed when this clock marker has not been updated for more than 1 sec
bpy.context.scene.var.btnRemoTime = int(time.time())
return (not bpy.context.scene.var.RemoVisible)
# -- Button press handlers
# This is a sample when a context override is needed to work around the 'context is incorrect' error condition when calling bps operators
# def btn_click(self, widget, event, x, y):
# for window in bpy.context.window_manager.windows:
# for area in window.screen.areas:
# if area.type == 'VIEW_3D':
# with bpy.context.temp_override(window=window, area=area, region=area.regions[-1]):
# bpy.ops.view3d.view_axis(type = 'TOP')
# return True
def button1_click(self, widget, event, x, y):
self.button2.enabled = True
self.button3.enabled = True
self.press_only(1)
def button2_click(self, widget, event, x, y):
self.press_only(2)
def button3_click(self, widget, event, x, y):
bpy.ops.mesh.primitive_monkey_add()
self.objname = bpy.context.object.name
self.textbox1.text = "'" + self.objname + "' is her name, but you can edit it here!"
self.textbox1.enabled = True
self.press_only(3)
def button4_click(self, widget, event, x, y):
self.button2.enabled = False
self.button3.enabled = False
self.press_only(4)
# I am not even obligated to create any of these functions, see?
# button5 does not have an active function bound to it at all.
#
# def button5_click(self, widget, event, x, y):
# do_something()
def button6_click(self, widget, event, x, y):
var = bpy.context.scene.var
var.OpState6 = (not var.OpState6)
self.button4.enabled = (not self.button4.enabled)
def buttonU_click(self, widget, event, x, y):
self.finish()
def button1_pressed(self, widget):
return (bpy.context.scene.var.OpState1)
def button2_pressed(self, widget):
return (bpy.context.scene.var.OpState2)
def button3_pressed(self, widget):
return (bpy.context.scene.var.OpState3)
def button4_pressed(self, widget):
return (bpy.context.scene.var.OpState4)
# I am not even obligated to create any of these functions, see?
# button5 does not have an active function tied to it at all.
#
# def button5_pressed(self, widget):
# return (bpy.context.scene.var.OpState5)
def button6_pressed(self, widget):
return (bpy.context.scene.var.OpState6)
def patch1_mouse_move(self, widget, event, x, y):
self.label2.text = "x: " + str(x) + " y: " + str(y)
return False
def number1_update(self, widget, value):
# Example of a dynamic unit conversion with dynamic min/max limits
converted = False
if widget.unit == "mm" and value >= 1000:
# Upscale to meters
value = value / 1000
widget.unit = "m"
widget.step = 10
widget.precision = 0
converted = True
if widget.unit == "m" and value >= 1000:
# Upscale to kilometers
value = value / 1000
widget.unit = "km"
widget.step = 0.1
widget.precision = 1
converted = True
if widget.unit == "km" and value >= 10:
# I want my hardcoded max limit to be 10 km
value = 10
converted = True
if widget.unit == "km" and value < 1:
# Downscale to meters
value = value * 1000
widget.unit = "m"
widget.step = 10
widget.precision = 0
converted = True
if widget.unit == "m" and value < 1:
# Downscale to millimeters
value = value * 1000
widget.unit = "mm"
widget.step = 10
widget.precision = 0
converted = True
if widget.unit == "mm" and value < 1:
# I want my hardcoded min limit to be 1 mm
value = 1
converted = True
if converted:
widget.value = round(value, widget.precision)
return False
else:
# By returning True the 'value' argument will be committed to the widget.value property
return True
def slider1_update(self, widget, value):
import math
try:
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
obj.rotation_euler[2] = math.radians(value)
except Exception as e:
pass
return True
def textbox1_changed(self, widget, context, former_text, updated_text):
# This is just an example done in a rush, so not much thinking and probably with bugs ;-)
# self.objname is a variable declared in this module (around the place where self.textbox1 is declared)
if updated_text != self.objname:
if updated_text.strip() == "":
self.objname = "<Why have you tried to blank her name?>"
widget.text = self.objname
return True
try:
for obj in bpy.data.objects:
if obj.type == 'MESH' and obj.name == self.objname:
obj.name = updated_text
self.objname = obj.name
break
except Exception as e:
self.objname = "<Error trying to assign this name to object>"
widget.text = self.objname
return True
def check1_changed(self, widget, event, x, y):
self.buttonU.visible = not self.check1.is_checked
return True
# -- Helper functions
def press_only(self, button):
var = bpy.context.scene.var
var.OpState1 = (button == 1)
var.OpState2 = (button == 2)
var.OpState3 = (button == 3)
var.OpState4 = (button == 4)
# -Register/unregister processes
def register():
bpy.utils.register_class(DP_OT_draw_operator)
def unregister():
bpy.utils.unregister_class(DP_OT_draw_operator)
if __name__ == '__main__':
register()