1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Copyright 2011, Ryan Inch
6 from math
import cos
, sin
, pi
, floor
11 from gpu_extras
.batch
import batch_for_shader
13 from bpy
.types
import Operator
15 from . import internals
17 from .qcd_operators
import (
24 return round(spacer
* scale_factor())
27 return bpy
.context
.preferences
.system
.ui_scale
36 (x
, y
-h
), # bottom left
37 (x
+w
, y
-h
), # bottom right
44 return vertices
, indices
46 def get_x_coords(area
):
54 (x
+(w
*0.1), y
), # top left B
55 (x
+w
, y
), # top right A
56 (x
+w
-(w
*0.1), y
), # top right B
57 (x
, y
-h
), # bottom left A
58 (x
+(w
*0.1), y
-h
), # bottom left B
59 (x
+w
, y
-h
), # bottom right A
60 (x
+w
-(w
*0.1), y
-h
), # bottom right B
61 (x
+(w
/2)-(w
*0.05), y
-(h
/2)), # center left
62 (x
+(w
/2)+(w
*0.05), y
-(h
/2)) # center right
66 (0,1,8), (1,8,9), # top left bar
67 (2,3,9), (3,9,8), # top right bar
68 (4,5,8), (5,8,9), # bottom left bar
69 (6,7,8), (6,9,8) # bottom right bar
72 return vertices
, indices
74 def get_circle_coords(area
):
76 x
= area
["vert"][0] + area
["width"] / 2
77 y
= area
["vert"][1] - area
["width"] / 2
78 radius
= area
["width"] / 2
80 vertices
= [(radius
* cos(side
* 2 * pi
/ sides
) + x
,
81 radius
* sin(side
* 2 * pi
/ sides
) + y
)
82 for side
in range(sides
+ 1)]
86 def draw_rounded_rect(area
, shader
, color
, tl
=5, tr
=5, bl
=5, br
=5, outline
=False):
89 tl
= round(tl
* scale_factor())
90 tr
= round(tr
* scale_factor())
91 bl
= round(bl
* scale_factor())
92 br
= round(br
* scale_factor())
94 bgl
.glEnable(bgl
.GL_BLEND
)
97 thickness
= round(2 * scale_factor())
98 thickness
= max(thickness
, 2)
100 bgl
.glLineWidth(thickness
)
101 bgl
.glEnable(bgl
.GL_LINE_SMOOTH
)
102 bgl
.glHint(bgl
.GL_LINE_SMOOTH_HINT
, bgl
.GL_NICEST
)
104 draw_type
= 'TRI_FAN' if not outline
else 'LINE_STRIP'
107 vert_x
= area
["vert"][0] + tl
108 vert_y
= area
["vert"][1] - tl
109 tl_vert
= (vert_x
, vert_y
)
110 vertices
= [(vert_x
, vert_y
)] if not outline
else []
112 for side
in range(sides
+1):
114 cosine
= tl
* cos(side
* 2 * pi
/ sides
) + vert_x
115 sine
= tl
* sin(side
* 2 * pi
/ sides
) + vert_y
116 vertices
.append((cosine
,sine
))
118 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
120 shader
.uniform_float("color", color
)
124 vert_x
= area
["vert"][0] + area
["width"] - tr
125 vert_y
= area
["vert"][1] - tr
126 tr_vert
= (vert_x
, vert_y
)
127 vertices
= [(vert_x
, vert_y
)] if not outline
else []
129 for side
in range(sides
+1):
131 cosine
= tr
* cos(side
* 2 * pi
/ sides
) + vert_x
132 sine
= tr
* sin(side
* 2 * pi
/ sides
) + vert_y
133 vertices
.append((cosine
,sine
))
135 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
137 shader
.uniform_float("color", color
)
141 vert_x
= area
["vert"][0] + bl
142 vert_y
= area
["vert"][1] - area
["height"] + bl
143 bl_vert
= (vert_x
, vert_y
)
144 vertices
= [(vert_x
, vert_y
)] if not outline
else []
146 for side
in range(sides
+1):
148 cosine
= bl
* cos(side
* 2 * pi
/ sides
) + vert_x
149 sine
= bl
* sin(side
* 2 * pi
/ sides
) + vert_y
150 vertices
.append((cosine
,sine
))
152 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
154 shader
.uniform_float("color", color
)
157 # bottom right corner
158 vert_x
= area
["vert"][0] + area
["width"] - br
159 vert_y
= area
["vert"][1] - area
["height"] + br
160 br_vert
= (vert_x
, vert_y
)
161 vertices
= [(vert_x
, vert_y
)] if not outline
else []
163 for side
in range(sides
+1):
165 cosine
= br
* cos(side
* 2 * pi
/ sides
) + vert_x
166 sine
= br
* sin(side
* 2 * pi
/ sides
) + vert_y
167 vertices
.append((cosine
,sine
))
169 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
171 shader
.uniform_float("color", color
)
184 (le_x
+width
, tl_vert
[1]),
186 (le_x
+width
, bl_vert
[1])
189 (base_ind
,base_ind
+1,base_ind
+2),
190 (base_ind
+2,base_ind
+3,base_ind
+1)
199 (re_x
-width
, tr_vert
[1]),
201 (re_x
-width
, br_vert
[1])
204 (base_ind
,base_ind
+1,base_ind
+2),
205 (base_ind
+2,base_ind
+3,base_ind
+1)
214 (tl_vert
[0], te_y
-width
),
216 (tr_vert
[0], te_y
-width
)
219 (base_ind
,base_ind
+1,base_ind
+2),
220 (base_ind
+2,base_ind
+3,base_ind
+1)
229 (bl_vert
[0], be_y
+width
),
231 (br_vert
[0], be_y
+width
)
234 (base_ind
,base_ind
+1,base_ind
+2),
235 (base_ind
+2,base_ind
+3,base_ind
+1)
247 (base_ind
,base_ind
+1,base_ind
+2),
248 (base_ind
+2,base_ind
+3,base_ind
+1)
251 batch
= batch_for_shader(shader
, 'TRIS', {"pos": vertices
}, indices
=indices
)
253 shader
.uniform_float("color", color
)
257 overlap
= round(thickness
/ 2 - scale_factor() / 2)
262 (le_x
, tl_vert
[1] + (overlap
if tl
== 0 else 0)),
263 (le_x
, bl_vert
[1] - (overlap
if bl
== 0 else 0))
266 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
272 (re_x
, tr_vert
[1] + (overlap
if tr
== 0 else 0)),
273 (re_x
, br_vert
[1] - (overlap
if br
== 0 else 0))
276 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
282 (tl_vert
[0] - (overlap
if tl
== 0 else 0), te_y
),
283 (tr_vert
[0] + (overlap
if tr
== 0 else 0), te_y
)
286 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
292 (bl_vert
[0] - (overlap
if bl
== 0 else 0), be_y
),
293 (br_vert
[0] + (overlap
if br
== 0 else 0), be_y
)
296 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
299 bgl
.glDisable(bgl
.GL_LINE_SMOOTH
)
301 bgl
.glDisable(bgl
.GL_BLEND
)
303 def mouse_in_area(mouse_pos
, area
, buf
= 0):
308 if x
+buf
< area
["vert"][0]:
312 if x
-buf
> area
["vert"][0] + area
["width"]:
316 if y
-buf
> area
["vert"][1]:
320 if y
+buf
< area
["vert"][1] - area
["height"]:
323 # if we reach here we're in the area
326 def account_for_view_bounds(area
):
327 # make sure it renders in the 3d view - prioritize top left
330 if area
["vert"][0] + area
["width"] > bpy
.context
.region
.width
:
331 x
= bpy
.context
.region
.width
- area
["width"]
334 area
["vert"] = (x
, y
)
337 if area
["vert"][0] < 0:
341 area
["vert"] = (x
, y
)
344 if area
["vert"][1] - area
["height"] < 0:
348 area
["vert"] = (x
, y
)
351 if area
["vert"][1] > bpy
.context
.region
.height
:
353 y
= bpy
.context
.region
.height
355 area
["vert"] = (x
, y
)
357 def update_area_dimensions(area
, w
=0, h
=0):
361 class QCDMoveWidget(Operator
):
362 """Move objects to QCD Slots"""
363 bl_idname
= "view3d.qcd_move_widget"
364 bl_label
= "QCD Move Widget"
383 def modal(self
, context
, event
):
384 if event
.type == 'TIMER':
385 if self
.hover_time
and self
.hover_time
+ 0.5 < time
.time():
386 self
.draw_tooltip
= True
388 context
.area
.tag_redraw()
389 return {'RUNNING_MODAL'}
392 context
.area
.tag_redraw()
394 if len(self
.areas
) == 1:
395 return {'RUNNING_MODAL'}
397 if self
.last_type
== 'LEFTMOUSE' and event
.value
== 'PRESS' and event
.type == 'MOUSEMOVE':
398 if mouse_in_area(self
.mouse_pos
, self
.areas
["Grab Bar"]):
399 x_offset
= self
.areas
["Main Window"]["vert"][0] - self
.mouse_pos
[0]
400 x
= event
.mouse_region_x
+ x_offset
402 y_offset
= self
.areas
["Main Window"]["vert"][1] - self
.mouse_pos
[1]
403 y
= event
.mouse_region_y
+ y_offset
405 self
.areas
["Main Window"]["vert"] = (x
, y
)
407 self
.mouse_pos
= (event
.mouse_region_x
, event
.mouse_region_y
)
409 elif event
.type == 'MOUSEMOVE':
410 self
.draw_tooltip
= False
411 self
.hover_time
= None
412 self
.mouse_pos
= (event
.mouse_region_x
, event
.mouse_region_y
)
414 if not mouse_in_area(self
.mouse_pos
, self
.areas
["Main Window"], 50 * scale_factor()):
416 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
419 bpy
.ops
.ed
.undo_push()
424 self
.initialized
= True
426 elif event
.value
== 'PRESS' and event
.type == 'LEFTMOUSE':
427 if not mouse_in_area(self
.mouse_pos
, self
.areas
["Main Window"], 10 * scale_factor()):
428 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
431 bpy
.ops
.ed
.undo_push()
435 for num
in range(20):
436 if not self
.areas
.get(f
"Button {num + 1}", None):
439 if mouse_in_area(self
.mouse_pos
, self
.areas
[f
"Button {num + 1}"]):
440 bpy
.ops
.view3d
.move_to_qcd_slot(slot
=str(num
+ 1), toggle
=event
.shift
)
443 elif event
.type in {'RIGHTMOUSE', 'ESC'}:
444 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
448 if event
.value
== 'PRESS' and event
.type in self
.slots
:
449 move_to
= self
.slots
[event
.type]
455 bpy
.ops
.view3d
.move_to_qcd_slot(slot
=str(move_to
), toggle
=True)
457 bpy
.ops
.view3d
.move_to_qcd_slot(slot
=str(move_to
), toggle
=False)
461 if event
.type != 'MOUSEMOVE' and event
.type != 'INBETWEEN_MOUSEMOVE':
462 self
.last_type
= event
.type
464 return {'RUNNING_MODAL'}
466 def invoke(self
, context
, event
):
467 if context
.area
.type == 'VIEW_3D':
468 # the arguments we pass the the callback
469 args
= (self
, context
)
470 # Add the region OpenGL drawing callback
471 # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
472 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(draw_callback_px
, args
, 'WINDOW', 'POST_PIXEL')
473 self
._timer
= context
.window_manager
.event_timer_add(0.1, window
=context
.window
)
475 self
.mouse_pos
= (event
.mouse_region_x
, event
.mouse_region_y
)
477 self
.draw_tooltip
= False
479 self
.hover_time
= None
483 # MAIN WINDOW BACKGROUND
484 x
= self
.mouse_pos
[0] - spacer()*2
485 y
= self
.mouse_pos
[1] + spacer()*2
494 self
.areas
["Main Window"] = main_window
495 allocate_main_ui(self
, context
)
496 account_for_view_bounds(main_window
)
498 context
.window_manager
.modal_handler_add(self
)
499 return {'RUNNING_MODAL'}
502 self
.report({'WARNING'}, "View3D not found, cannot run operator")
506 def allocate_main_ui(self
, context
):
507 main_window
= self
.areas
["Main Window"]
509 main_window
["width"] = 0
510 main_window
["height"] = 0
511 self
.areas
["Main Window"] = main_window
513 cur_width_pos
= main_window
["vert"][0]
514 cur_height_pos
= main_window
["vert"][1]
518 "vert": main_window
["vert"],
520 "height": round(23 * scale_factor()),
524 # add grab bar to areas
525 self
.areas
["Grab Bar"] = grab_bar
529 wt_indent_x
= spacer()*2
530 wt_y_offset
= round(spacer()/2)
532 "vert": main_window
["vert"],
534 "height": round(13 * scale_factor()),
535 "value": "Move Objects to QCD Slots"
538 x
= main_window
["vert"][0] + wt_indent_x
539 y
= main_window
["vert"][1] - window_title
["height"] - wt_y_offset
540 window_title
["vert"] = (x
, y
)
542 # add window title to areas
543 self
.areas
["Window Title"] = window_title
545 cur_height_pos
= window_title
["vert"][1]
549 button_size
= round(20 * scale_factor())
550 button_gap
= round(1 * scale_factor())
552 button_group_gap
= round(20 * scale_factor())
553 button_group_width
= button_size
* button_group
+ button_gap
* (button_group
- 1)
555 mba_indent_x
= spacer()*2
556 mba_outdent_x
= spacer()*2
557 mba_indent_y
= spacer()
558 x
= cur_width_pos
+ mba_indent_x
559 y
= cur_height_pos
- mba_indent_y
567 # add main button area to areas
568 self
.areas
["Main Button Area"] = main_button_area
570 # update current position
571 cur_width_pos
= main_button_area
["vert"][0]
572 cur_height_pos
= main_button_area
["vert"][1]
577 "vert": main_button_area
["vert"],
578 "width": button_group_width
,
579 "height": button_size
,
583 # add button row 1 A to areas
584 self
.areas
["Button Row 1 A"] = button_row_1_a
586 # advance width pos to start of next row
587 cur_width_pos
+= button_row_1_a
["width"]
588 cur_width_pos
+= button_group_gap
595 "width": button_group_width
,
596 "height": button_size
,
600 # add button row 1 B to areas
601 self
.areas
["Button Row 1 B"] = button_row_1_b
603 # reset width pos to start of main button area
604 cur_width_pos
= main_button_area
["vert"][0]
606 cur_height_pos
-= button_row_1_a
["height"]
607 # add gap between button rows
608 cur_height_pos
-= button_gap
616 "width": button_group_width
,
617 "height": button_size
,
621 # add button row 2 A to areas
622 self
.areas
["Button Row 2 A"] = button_row_2_a
624 # advance width pos to start of next row
625 cur_width_pos
+= button_row_2_a
["width"]
626 cur_width_pos
+= button_group_gap
633 "width": button_group_width
,
634 "height": button_size
,
638 # add button row 2 B to areas
639 self
.areas
["Button Row 2 B"] = button_row_2_b
642 selected_objects
= get_move_selection()
643 active_object
= get_move_active()
647 def get_buttons(button_row
, row_num
):
648 cur_width_pos
= button_row
["vert"][0]
649 cur_height_pos
= button_row
["vert"][1]
650 for num
in range(button_group
):
651 slot_num
= row_num
+ num
653 qcd_slot_name
= internals
.qcd_slots
.get_name(f
"{slot_num}")
656 qcd_laycol
= internals
.layer_collections
[qcd_slot_name
]["ptr"]
657 collection_objects
= qcd_laycol
.collection
.objects
664 "width": button_size
,
665 "height": button_size
,
669 self
.areas
[f
"Button {slot_num}"] = button
672 if active_object
and active_object
in selected_objects
and active_object
.name
in collection_objects
:
673 x
= cur_width_pos
+ round(button_size
/ 4)
674 y
= cur_height_pos
- round(button_size
/ 4)
675 active_object_indicator
= {
677 "width": floor(button_size
/ 2),
678 "height": floor(button_size
/ 2),
682 self
.areas
[f
"Button {slot_num} Active Object Indicator"] = active_object_indicator
684 elif not set(selected_objects
).isdisjoint(collection_objects
):
685 x
= cur_width_pos
+ round(button_size
/ 4) + floor(1 * scale_factor())
686 y
= cur_height_pos
- round(button_size
/ 4) - floor(1 * scale_factor())
687 selected_object_indicator
= {
689 "width": floor(button_size
/ 2) - floor(1 * scale_factor()),
690 "height": floor(button_size
/ 2) - floor(1 * scale_factor()),
694 self
.areas
[f
"Button {slot_num} Selected Object Indicator"] = selected_object_indicator
696 elif collection_objects
:
697 x
= cur_width_pos
+ floor(button_size
/ 4)
698 y
= cur_height_pos
- button_size
/ 2 + 1 * scale_factor()
701 "width": round(button_size
/ 2),
702 "height": round(2 * scale_factor()),
705 self
.areas
[f
"Button {slot_num} Object Indicator"] = object_indicator
708 x
= cur_width_pos
+ 2 * scale_factor()
709 y
= cur_height_pos
- 2 * scale_factor()
712 "width": button_size
- 4 * scale_factor(),
713 "height": button_size
- 4 * scale_factor(),
717 self
.areas
[f
"X_icon {slot_num}"] = X_icon
719 cur_width_pos
+= button_size
720 cur_width_pos
+= button_gap
722 get_buttons(button_row_1_a
, 1)
723 get_buttons(button_row_1_b
, 6)
724 get_buttons(button_row_2_a
, 11)
725 get_buttons(button_row_2_b
, 16)
728 # UPDATE DYNAMIC DIMENSIONS
729 width
= button_row_1_a
["width"] + button_group_gap
+ button_row_1_b
["width"]
730 height
= button_row_1_a
["height"] + button_gap
+ button_row_2_a
["height"]
731 update_area_dimensions(main_button_area
, width
, height
)
733 width
= main_button_area
["width"] + mba_indent_x
+ mba_outdent_x
734 height
= main_button_area
["height"] + mba_indent_y
* 2 + window_title
["height"] + wt_y_offset
735 update_area_dimensions(main_window
, width
, height
)
737 update_area_dimensions(grab_bar
, main_window
["width"])
740 def draw_callback_px(self
, context
):
741 allocate_main_ui(self
, context
)
743 shader
= gpu
.shader
.from_builtin('2D_UNIFORM_COLOR')
746 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
748 # main window background
749 main_window
= self
.areas
["Main Window"]
750 outline_color
= addon_prefs
.qcd_ogl_widget_menu_back_outline
751 background_color
= addon_prefs
.qcd_ogl_widget_menu_back_inner
752 draw_rounded_rect(main_window
, shader
, outline_color
[:] + (1,), outline
=True)
753 draw_rounded_rect(main_window
, shader
, background_color
)
756 window_title
= self
.areas
["Window Title"]
757 x
= window_title
["vert"][0]
758 y
= window_title
["vert"][1]
759 h
= window_title
["height"]
760 text
= window_title
["value"]
761 text_color
= addon_prefs
.qcd_ogl_widget_menu_back_text
763 blf
.position(font_id
, x
, y
, 0)
764 blf
.size(font_id
, int(h
), 72)
765 blf
.color(font_id
, text_color
[0], text_color
[1], text_color
[2], 1)
766 blf
.draw(font_id
, text
)
768 # refresh shader - not sure why this is needed
771 in_tooltip_area
= False
772 tooltip_slot_idx
= None
774 for num
in range(20):
776 qcd_slot_name
= internals
.qcd_slots
.get_name(f
"{slot_num}")
778 qcd_laycol
= internals
.layer_collections
[qcd_slot_name
]["ptr"]
779 collection_objects
= qcd_laycol
.collection
.objects
780 selected_objects
= get_move_selection()
781 active_object
= get_move_active()
782 button_area
= self
.areas
[f
"Button {slot_num}"]
785 button_color
= addon_prefs
.qcd_ogl_widget_tool_inner
786 icon_color
= addon_prefs
.qcd_ogl_widget_tool_text
787 if not qcd_laycol
.exclude
:
788 button_color
= addon_prefs
.qcd_ogl_widget_tool_inner_sel
789 icon_color
= addon_prefs
.qcd_ogl_widget_tool_text_sel
791 if mouse_in_area(self
.mouse_pos
, button_area
):
792 in_tooltip_area
= True
793 tooltip_slot_idx
= slot_num
797 if button_color
[0] + mod
> 1 or button_color
[1] + mod
> 1 or button_color
[2] + mod
> 1:
801 button_color
[0] + mod
,
802 button_color
[1] + mod
,
803 button_color
[2] + mod
,
809 tl
= tr
= bl
= br
= 0
813 if not internals
.qcd_slots
.contains(idx
=f
"{num+2}"):
816 if not internals
.qcd_slots
.contains(idx
=f
"{num}"):
819 if not internals
.qcd_slots
.contains(idx
=f
"{num+2}"):
822 if not internals
.qcd_slots
.contains(idx
=f
"{num}"):
835 outline_color
= addon_prefs
.qcd_ogl_widget_tool_outline
836 draw_rounded_rect(button_area
, shader
, outline_color
[:] + (1,), tl
, tr
, bl
, br
, outline
=True)
837 draw_rounded_rect(button_area
, shader
, button_color
, tl
, tr
, bl
, br
)
840 if active_object
and active_object
in selected_objects
and active_object
.name
in collection_objects
:
841 active_object_indicator
= self
.areas
[f
"Button {slot_num} Active Object Indicator"]
843 vertices
= get_circle_coords(active_object_indicator
)
844 shader
.uniform_float("color", icon_color
[:] + (1,))
845 batch
= batch_for_shader(shader
, 'TRI_FAN', {"pos": vertices
})
847 bgl
.glEnable(bgl
.GL_BLEND
)
851 bgl
.glDisable(bgl
.GL_BLEND
)
854 elif not set(selected_objects
).isdisjoint(collection_objects
):
855 selected_object_indicator
= self
.areas
[f
"Button {slot_num} Selected Object Indicator"]
857 alpha
= addon_prefs
.qcd_ogl_selected_icon_alpha
858 vertices
= get_circle_coords(selected_object_indicator
)
859 shader
.uniform_float("color", icon_color
[:] + (alpha
,))
860 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
862 bgl
.glLineWidth(2 * scale_factor())
863 bgl
.glEnable(bgl
.GL_BLEND
)
864 bgl
.glEnable(bgl
.GL_LINE_SMOOTH
)
865 bgl
.glHint(bgl
.GL_LINE_SMOOTH_HINT
, bgl
.GL_NICEST
)
869 bgl
.glDisable(bgl
.GL_LINE_SMOOTH
)
870 bgl
.glDisable(bgl
.GL_BLEND
)
873 elif collection_objects
:
874 object_indicator
= self
.areas
[f
"Button {slot_num} Object Indicator"]
876 alpha
= addon_prefs
.qcd_ogl_objects_icon_alpha
877 vertices
, indices
= get_coords(object_indicator
)
878 shader
.uniform_float("color", icon_color
[:] + (alpha
,))
879 batch
= batch_for_shader(shader
, 'TRIS', {"pos": vertices
}, indices
=indices
)
881 bgl
.glEnable(bgl
.GL_BLEND
)
885 bgl
.glDisable(bgl
.GL_BLEND
)
890 X_icon
= self
.areas
[f
"X_icon {slot_num}"]
891 X_icon_color
= addon_prefs
.qcd_ogl_widget_menu_back_text
893 vertices
, indices
= get_x_coords(X_icon
)
894 shader
.uniform_float("color", X_icon_color
[:] + (1,))
895 batch
= batch_for_shader(shader
, 'TRIS', {"pos": vertices
}, indices
=indices
)
897 bgl
.glEnable(bgl
.GL_BLEND
)
898 bgl
.glEnable(bgl
.GL_POLYGON_SMOOTH
)
899 bgl
.glHint(bgl
.GL_POLYGON_SMOOTH_HINT
, bgl
.GL_NICEST
)
903 bgl
.glDisable(bgl
.GL_POLYGON_SMOOTH
)
904 bgl
.glDisable(bgl
.GL_BLEND
)
907 if self
.draw_tooltip
:
908 slot_name
= internals
.qcd_slots
.get_name(f
"{tooltip_slot_idx}")
909 slot_string
= f
"QCD Slot {tooltip_slot_idx}: \"{slot_name}\"\n"
911 " * LMB - Move objects to slot.\n"
912 " * Shift+LMB - Toggle objects\' slot."
915 draw_tooltip(self
, context
, shader
, f
"{slot_string}{hotkey_string}")
917 self
.hover_time
= None
920 if not self
.hover_time
:
921 self
.hover_time
= time
.time()
924 def draw_tooltip(self
, context
, shader
, message
):
925 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
928 line_height
= 11 * scale_factor()
929 text_color
= addon_prefs
.qcd_ogl_widget_tooltip_text
930 blf
.size(font_id
, int(line_height
), 72)
931 blf
.color(font_id
, text_color
[0], text_color
[1], text_color
[2], 1)
933 lines
= message
.split("\n")
935 num_lines
= len(lines
)
938 w
, _
= blf
.dimensions(font_id
, line
)
944 w
, h
= blf
.dimensions(font_id
, longest
[1])
946 line_spacer
= 1 * scale_factor()
947 padding
= 4 * scale_factor()
951 "vert": self
.mouse_pos
,
952 "width": w
+ spacer()*2,
953 "height": (line_height
* num_lines
+ line_spacer
* num_lines
) + padding
*3,
957 x
= tooltip
["vert"][0] - spacer()*2
958 y
= tooltip
["vert"][1] + tooltip
["height"] + round(5 * scale_factor())
959 tooltip
["vert"] = (x
, y
)
961 account_for_view_bounds(tooltip
)
963 outline_color
= addon_prefs
.qcd_ogl_widget_tooltip_outline
964 background_color
= addon_prefs
.qcd_ogl_widget_tooltip_inner
965 draw_rounded_rect(tooltip
, shader
, outline_color
[:] + (1,), outline
=True)
966 draw_rounded_rect(tooltip
, shader
, background_color
)
968 line_pos
= padding
+ line_height
970 for num
, line
in enumerate(lines
):
971 x
= tooltip
["vert"][0] + spacer()
972 y
= tooltip
["vert"][1] - line_pos
973 blf
.position(font_id
, x
, y
, 0)
974 blf
.draw(font_id
, line
)
976 line_pos
+= line_height
+ line_spacer