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 # Copyright 2011, Ryan Inch
22 from math
import cos
, sin
, pi
, floor
27 from gpu_extras
.batch
import batch_for_shader
29 from bpy
.types
import Operator
30 from .internals
import (
34 from . import qcd_operators
38 return round(spacer
* scale_factor())
41 return bpy
.context
.preferences
.system
.ui_scale
50 (x
, y
-h
), # bottom left
51 (x
+w
, y
-h
), # bottom right
58 return vertices
, indices
60 def get_x_coords(area
):
68 (x
+(w
*0.1), y
), # top left B
69 (x
+w
, y
), # top right A
70 (x
+w
-(w
*0.1), y
), # top right B
71 (x
, y
-h
), # bottom left A
72 (x
+(w
*0.1), y
-h
), # bottom left B
73 (x
+w
, y
-h
), # bottom right A
74 (x
+w
-(w
*0.1), y
-h
), # bottom right B
75 (x
+(w
/2)-(w
*0.05), y
-(h
/2)), # center left
76 (x
+(w
/2)+(w
*0.05), y
-(h
/2)) # center right
80 (0,1,8), (1,8,9), # top left bar
81 (2,3,9), (3,9,8), # top right bar
82 (4,5,8), (5,8,9), # bottom left bar
83 (6,7,8), (6,9,8) # bottom right bar
86 return vertices
, indices
88 def get_circle_coords(area
):
90 x
= area
["vert"][0] + area
["width"] / 2
91 y
= area
["vert"][1] - area
["width"] / 2
92 radius
= area
["width"] / 2
94 vertices
= [(radius
* cos(side
* 2 * pi
/ sides
) + x
,
95 radius
* sin(side
* 2 * pi
/ sides
) + y
)
96 for side
in range(sides
+ 1)]
100 def draw_rounded_rect(area
, shader
, color
, tl
=5, tr
=5, bl
=5, br
=5, outline
=False):
103 tl
= round(tl
* scale_factor())
104 tr
= round(tr
* scale_factor())
105 bl
= round(bl
* scale_factor())
106 br
= round(br
* scale_factor())
108 bgl
.glEnable(bgl
.GL_BLEND
)
111 thickness
= round(2 * scale_factor())
112 thickness
= max(thickness
, 2)
114 bgl
.glLineWidth(thickness
)
115 bgl
.glEnable(bgl
.GL_LINE_SMOOTH
)
116 bgl
.glHint(bgl
.GL_LINE_SMOOTH_HINT
, bgl
.GL_NICEST
)
118 draw_type
= 'TRI_FAN' if not outline
else 'LINE_STRIP'
121 vert_x
= area
["vert"][0] + tl
122 vert_y
= area
["vert"][1] - tl
123 tl_vert
= (vert_x
, vert_y
)
124 vertices
= [(vert_x
, vert_y
)] if not outline
else []
126 for side
in range(sides
+1):
128 cosine
= tl
* cos(side
* 2 * pi
/ sides
) + vert_x
129 sine
= tl
* sin(side
* 2 * pi
/ sides
) + vert_y
130 vertices
.append((cosine
,sine
))
132 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
134 shader
.uniform_float("color", color
)
138 vert_x
= area
["vert"][0] + area
["width"] - tr
139 vert_y
= area
["vert"][1] - tr
140 tr_vert
= (vert_x
, vert_y
)
141 vertices
= [(vert_x
, vert_y
)] if not outline
else []
143 for side
in range(sides
+1):
145 cosine
= tr
* cos(side
* 2 * pi
/ sides
) + vert_x
146 sine
= tr
* sin(side
* 2 * pi
/ sides
) + vert_y
147 vertices
.append((cosine
,sine
))
149 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
151 shader
.uniform_float("color", color
)
155 vert_x
= area
["vert"][0] + bl
156 vert_y
= area
["vert"][1] - area
["height"] + bl
157 bl_vert
= (vert_x
, vert_y
)
158 vertices
= [(vert_x
, vert_y
)] if not outline
else []
160 for side
in range(sides
+1):
162 cosine
= bl
* cos(side
* 2 * pi
/ sides
) + vert_x
163 sine
= bl
* sin(side
* 2 * pi
/ sides
) + vert_y
164 vertices
.append((cosine
,sine
))
166 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
168 shader
.uniform_float("color", color
)
171 # bottom right corner
172 vert_x
= area
["vert"][0] + area
["width"] - br
173 vert_y
= area
["vert"][1] - area
["height"] + br
174 br_vert
= (vert_x
, vert_y
)
175 vertices
= [(vert_x
, vert_y
)] if not outline
else []
177 for side
in range(sides
+1):
179 cosine
= br
* cos(side
* 2 * pi
/ sides
) + vert_x
180 sine
= br
* sin(side
* 2 * pi
/ sides
) + vert_y
181 vertices
.append((cosine
,sine
))
183 batch
= batch_for_shader(shader
, draw_type
, {"pos": vertices
})
185 shader
.uniform_float("color", color
)
198 (le_x
+width
, tl_vert
[1]),
200 (le_x
+width
, bl_vert
[1])
203 (base_ind
,base_ind
+1,base_ind
+2),
204 (base_ind
+2,base_ind
+3,base_ind
+1)
213 (re_x
-width
, tr_vert
[1]),
215 (re_x
-width
, br_vert
[1])
218 (base_ind
,base_ind
+1,base_ind
+2),
219 (base_ind
+2,base_ind
+3,base_ind
+1)
228 (tl_vert
[0], te_y
-width
),
230 (tr_vert
[0], te_y
-width
)
233 (base_ind
,base_ind
+1,base_ind
+2),
234 (base_ind
+2,base_ind
+3,base_ind
+1)
243 (bl_vert
[0], be_y
+width
),
245 (br_vert
[0], be_y
+width
)
248 (base_ind
,base_ind
+1,base_ind
+2),
249 (base_ind
+2,base_ind
+3,base_ind
+1)
261 (base_ind
,base_ind
+1,base_ind
+2),
262 (base_ind
+2,base_ind
+3,base_ind
+1)
265 batch
= batch_for_shader(shader
, 'TRIS', {"pos": vertices
}, indices
=indices
)
267 shader
.uniform_float("color", color
)
271 overlap
= round(thickness
/ 2 - scale_factor() / 2)
276 (le_x
, tl_vert
[1] + (overlap
if tl
== 0 else 0)),
277 (le_x
, bl_vert
[1] - (overlap
if bl
== 0 else 0))
280 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
286 (re_x
, tr_vert
[1] + (overlap
if tr
== 0 else 0)),
287 (re_x
, br_vert
[1] - (overlap
if br
== 0 else 0))
290 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
296 (tl_vert
[0] - (overlap
if tl
== 0 else 0), te_y
),
297 (tr_vert
[0] + (overlap
if tr
== 0 else 0), te_y
)
300 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
306 (bl_vert
[0] - (overlap
if bl
== 0 else 0), be_y
),
307 (br_vert
[0] + (overlap
if br
== 0 else 0), be_y
)
310 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
313 bgl
.glDisable(bgl
.GL_LINE_SMOOTH
)
315 bgl
.glDisable(bgl
.GL_BLEND
)
317 def mouse_in_area(mouse_pos
, area
, buf
= 0):
322 if x
+buf
< area
["vert"][0]:
326 if x
-buf
> area
["vert"][0] + area
["width"]:
330 if y
-buf
> area
["vert"][1]:
334 if y
+buf
< area
["vert"][1] - area
["height"]:
337 # if we reach here we're in the area
340 def account_for_view_bounds(area
):
341 # make sure it renders in the 3d view
343 if area
["vert"][0] < 0:
347 area
["vert"] = (x
, y
)
350 if area
["vert"][0] + area
["width"] > bpy
.context
.region
.width
:
351 x
= bpy
.context
.region
.width
- area
["width"]
354 area
["vert"] = (x
, y
)
357 if area
["vert"][1] > bpy
.context
.region
.height
:
359 y
= bpy
.context
.region
.height
361 area
["vert"] = (x
, y
)
364 if area
["vert"][1] - area
["height"] < 0:
368 area
["vert"] = (x
, y
)
370 def update_area_dimensions(area
, w
=0, h
=0):
374 class QCDMoveWidget(Operator
):
375 """QCD Move Widget"""
376 bl_idname
= "view3d.qcd_move_widget"
377 bl_label
= "QCD Move Widget"
395 def modal(self
, context
, event
):
396 if event
.type == 'TIMER':
397 if self
.hover_time
and self
.hover_time
+ 0.5 < time
.time():
398 self
.draw_tooltip
= True
400 context
.area
.tag_redraw()
401 return {'RUNNING_MODAL'}
404 context
.area
.tag_redraw()
406 if len(self
.areas
) == 1:
407 return {'RUNNING_MODAL'}
409 if self
.last_type
== 'LEFTMOUSE' and event
.value
== 'PRESS' and event
.type == 'MOUSEMOVE':
410 if mouse_in_area(self
.mouse_pos
, self
.areas
["Grab Bar"]):
411 x_offset
= self
.areas
["Main Window"]["vert"][0] - self
.mouse_pos
[0]
412 x
= event
.mouse_region_x
+ x_offset
414 y_offset
= self
.areas
["Main Window"]["vert"][1] - self
.mouse_pos
[1]
415 y
= event
.mouse_region_y
+ y_offset
417 self
.areas
["Main Window"]["vert"] = (x
, y
)
419 self
.mouse_pos
= (event
.mouse_region_x
, event
.mouse_region_y
)
421 elif event
.type == 'MOUSEMOVE':
422 self
.draw_tooltip
= False
423 self
.hover_time
= None
424 self
.mouse_pos
= (event
.mouse_region_x
, event
.mouse_region_y
)
426 if not mouse_in_area(self
.mouse_pos
, self
.areas
["Main Window"], 50 * scale_factor()):
427 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
430 bpy
.ops
.ed
.undo_push()
434 elif event
.value
== 'PRESS' and event
.type == 'LEFTMOUSE':
435 if not mouse_in_area(self
.mouse_pos
, self
.areas
["Main Window"], 10 * scale_factor()):
436 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
439 bpy
.ops
.ed
.undo_push()
443 for num
in range(20):
444 if not self
.areas
.get(f
"Button {num + 1}", None):
447 if mouse_in_area(self
.mouse_pos
, self
.areas
[f
"Button {num + 1}"]):
448 bpy
.ops
.view3d
.move_to_qcd_slot(slot
=str(num
+ 1), toggle
=event
.shift
)
451 elif event
.type in {'RIGHTMOUSE', 'ESC'}:
452 bpy
.types
.SpaceView3D
.draw_handler_remove(self
._handle
, 'WINDOW')
456 if event
.value
== 'PRESS' and event
.type in self
.slots
:
457 move_to
= self
.slots
[event
.type]
463 bpy
.ops
.view3d
.move_to_qcd_slot(slot
=str(move_to
), toggle
=True)
465 bpy
.ops
.view3d
.move_to_qcd_slot(slot
=str(move_to
), toggle
=False)
469 if event
.type != 'MOUSEMOVE' and event
.type != 'INBETWEEN_MOUSEMOVE':
470 self
.last_type
= event
.type
472 return {'RUNNING_MODAL'}
474 def invoke(self
, context
, event
):
475 if context
.area
.type == 'VIEW_3D':
476 # the arguments we pass the the callback
477 args
= (self
, context
)
478 # Add the region OpenGL drawing callback
479 # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
480 self
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(draw_callback_px
, args
, 'WINDOW', 'POST_PIXEL')
481 self
._timer
= context
.window_manager
.event_timer_add(0.1, window
=context
.window
)
483 self
.mouse_pos
= (event
.mouse_region_x
, event
.mouse_region_y
)
485 self
.draw_tooltip
= False
487 self
.hover_time
= None
491 # MAIN WINDOW BACKGROUND
492 x
= self
.mouse_pos
[0] - spacer()*2
493 y
= self
.mouse_pos
[1] + spacer()*2
501 account_for_view_bounds(main_window
)
503 # add main window background to areas
504 self
.areas
["Main Window"] = main_window
506 context
.window_manager
.modal_handler_add(self
)
507 return {'RUNNING_MODAL'}
509 self
.report({'WARNING'}, "View3D not found, cannot run operator")
513 def allocate_main_ui(self
, context
):
514 main_window
= self
.areas
["Main Window"]
516 main_window
["width"] = 0
517 main_window
["height"] = 0
518 self
.areas
["Main Window"] = main_window
520 cur_width_pos
= main_window
["vert"][0]
521 cur_height_pos
= main_window
["vert"][1]
525 "vert": main_window
["vert"],
527 "height": round(23 * scale_factor()),
531 # add grab bar to areas
532 self
.areas
["Grab Bar"] = grab_bar
536 wt_indent_x
= spacer()*2
537 wt_y_offset
= round(spacer()/2)
539 "vert": main_window
["vert"],
541 "height": round(13 * scale_factor()),
542 "value": "Move Objects to QCD Slots"
545 x
= main_window
["vert"][0] + wt_indent_x
546 y
= main_window
["vert"][1] - window_title
["height"] - wt_y_offset
547 window_title
["vert"] = (x
, y
)
549 # add window title to areas
550 self
.areas
["Window Title"] = window_title
552 cur_height_pos
= window_title
["vert"][1]
556 button_size
= round(20 * scale_factor())
557 button_gap
= round(1 * scale_factor())
559 button_group_gap
= round(20 * scale_factor())
560 button_group_width
= button_size
* button_group
+ button_gap
* (button_group
- 1)
562 mba_indent_x
= spacer()*2
563 mba_outdent_x
= spacer()*2
564 mba_indent_y
= spacer()
565 x
= cur_width_pos
+ mba_indent_x
566 y
= cur_height_pos
- mba_indent_y
574 # add main button area to areas
575 self
.areas
["Main Button Area"] = main_button_area
577 # update current position
578 cur_width_pos
= main_button_area
["vert"][0]
579 cur_height_pos
= main_button_area
["vert"][1]
584 "vert": main_button_area
["vert"],
585 "width": button_group_width
,
586 "height": button_size
,
590 # add button row 1 A to areas
591 self
.areas
["Button Row 1 A"] = button_row_1_a
593 # advance width pos to start of next row
594 cur_width_pos
+= button_row_1_a
["width"]
595 cur_width_pos
+= button_group_gap
602 "width": button_group_width
,
603 "height": button_size
,
607 # add button row 1 B to areas
608 self
.areas
["Button Row 1 B"] = button_row_1_b
610 # reset width pos to start of main button area
611 cur_width_pos
= main_button_area
["vert"][0]
613 cur_height_pos
-= button_row_1_a
["height"]
614 # add gap between button rows
615 cur_height_pos
-= button_gap
623 "width": button_group_width
,
624 "height": button_size
,
628 # add button row 2 A to areas
629 self
.areas
["Button Row 2 A"] = button_row_2_a
631 # advance width pos to start of next row
632 cur_width_pos
+= button_row_2_a
["width"]
633 cur_width_pos
+= button_group_gap
640 "width": button_group_width
,
641 "height": button_size
,
645 # add button row 2 B to areas
646 self
.areas
["Button Row 2 B"] = button_row_2_b
650 def get_buttons(button_row
, row_num
):
651 cur_width_pos
= button_row
["vert"][0]
652 cur_height_pos
= button_row
["vert"][1]
653 for num
in range(button_group
):
654 slot_num
= row_num
+ num
656 qcd_slot_name
= qcd_slots
.get_name(f
"{slot_num}")
659 qcd_laycol
= layer_collections
[qcd_slot_name
]["ptr"]
660 collection_objects
= qcd_laycol
.collection
.objects
661 selected_objects
= qcd_operators
.get_move_selection()
662 active_object
= qcd_operators
.get_move_active()
669 "width": button_size
,
670 "height": button_size
,
674 self
.areas
[f
"Button {slot_num}"] = button
677 if active_object
and active_object
in selected_objects
and active_object
.name
in collection_objects
:
678 x
= cur_width_pos
+ round(button_size
/ 4)
679 y
= cur_height_pos
- round(button_size
/ 4)
680 active_object_indicator
= {
682 "width": floor(button_size
/ 2),
683 "height": floor(button_size
/ 2),
687 self
.areas
[f
"Button {slot_num} Active Object Indicator"] = active_object_indicator
689 elif not set(selected_objects
).isdisjoint(collection_objects
):
690 x
= cur_width_pos
+ round(button_size
/ 4) + floor(1 * scale_factor())
691 y
= cur_height_pos
- round(button_size
/ 4) - floor(1 * scale_factor())
692 selected_object_indicator
= {
694 "width": floor(button_size
/ 2) - floor(1 * scale_factor()),
695 "height": floor(button_size
/ 2) - floor(1 * scale_factor()),
699 self
.areas
[f
"Button {slot_num} Selected Object Indicator"] = selected_object_indicator
701 elif collection_objects
:
702 x
= cur_width_pos
+ floor(button_size
/ 4)
703 y
= cur_height_pos
- button_size
/ 2 + 1 * scale_factor()
706 "width": round(button_size
/ 2),
707 "height": round(2 * scale_factor()),
710 self
.areas
[f
"Button {slot_num} Object Indicator"] = object_indicator
713 x
= cur_width_pos
+ 2 * scale_factor()
714 y
= cur_height_pos
- 2 * scale_factor()
717 "width": button_size
- 4 * scale_factor(),
718 "height": button_size
- 4 * scale_factor(),
722 self
.areas
[f
"X_icon {slot_num}"] = X_icon
724 cur_width_pos
+= button_size
725 cur_width_pos
+= button_gap
727 get_buttons(button_row_1_a
, 1)
728 get_buttons(button_row_1_b
, 6)
729 get_buttons(button_row_2_a
, 11)
730 get_buttons(button_row_2_b
, 16)
733 # UPDATE DYNAMIC DIMENSIONS
734 width
= button_row_1_a
["width"] + button_group_gap
+ button_row_1_b
["width"]
735 height
= button_row_1_a
["height"] + button_gap
+ button_row_2_a
["height"]
736 update_area_dimensions(main_button_area
, width
, height
)
738 width
= main_button_area
["width"] + mba_indent_x
+ mba_outdent_x
739 height
= main_button_area
["height"] + mba_indent_y
* 2 + window_title
["height"] + wt_y_offset
740 update_area_dimensions(main_window
, width
, height
)
742 update_area_dimensions(grab_bar
, main_window
["width"])
745 def draw_callback_px(self
, context
):
746 allocate_main_ui(self
, context
)
748 shader
= gpu
.shader
.from_builtin('2D_UNIFORM_COLOR')
751 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
753 # main window background
754 main_window
= self
.areas
["Main Window"]
755 outline_color
= addon_prefs
.qcd_ogl_widget_menu_back_outline
756 background_color
= addon_prefs
.qcd_ogl_widget_menu_back_inner
757 draw_rounded_rect(main_window
, shader
, outline_color
[:] + (1,), outline
=True)
758 draw_rounded_rect(main_window
, shader
, background_color
)
761 window_title
= self
.areas
["Window Title"]
762 x
= window_title
["vert"][0]
763 y
= window_title
["vert"][1]
764 h
= window_title
["height"]
765 text
= window_title
["value"]
766 text_color
= addon_prefs
.qcd_ogl_widget_menu_back_text
768 blf
.position(font_id
, x
, y
, 0)
769 blf
.size(font_id
, int(h
), 72)
770 blf
.color(font_id
, text_color
[0], text_color
[1], text_color
[2], 1)
771 blf
.draw(font_id
, text
)
773 # refresh shader - not sure why this is needed
776 in_tooltip_area
= False
777 tooltip_slot_idx
= None
779 for num
in range(20):
781 qcd_slot_name
= qcd_slots
.get_name(f
"{slot_num}")
783 qcd_laycol
= layer_collections
[qcd_slot_name
]["ptr"]
784 collection_objects
= qcd_laycol
.collection
.objects
785 selected_objects
= qcd_operators
.get_move_selection()
786 active_object
= qcd_operators
.get_move_active()
787 button_area
= self
.areas
[f
"Button {slot_num}"]
790 button_color
= addon_prefs
.qcd_ogl_widget_tool_inner
791 icon_color
= addon_prefs
.qcd_ogl_widget_tool_text
792 if not qcd_laycol
.exclude
:
793 button_color
= addon_prefs
.qcd_ogl_widget_tool_inner_sel
794 icon_color
= addon_prefs
.qcd_ogl_widget_tool_text_sel
796 if mouse_in_area(self
.mouse_pos
, button_area
):
797 in_tooltip_area
= True
798 tooltip_slot_idx
= slot_num
802 if button_color
[0] + mod
> 1 or button_color
[1] + mod
> 1 or button_color
[2] + mod
> 1:
806 button_color
[0] + mod
,
807 button_color
[1] + mod
,
808 button_color
[2] + mod
,
814 tl
= tr
= bl
= br
= 0
818 if not qcd_slots
.contains(idx
=f
"{num+2}"):
821 if not qcd_slots
.contains(idx
=f
"{num}"):
824 if not qcd_slots
.contains(idx
=f
"{num+2}"):
827 if not qcd_slots
.contains(idx
=f
"{num}"):
840 outline_color
= addon_prefs
.qcd_ogl_widget_tool_outline
841 draw_rounded_rect(button_area
, shader
, outline_color
[:] + (1,), tl
, tr
, bl
, br
, outline
=True)
842 draw_rounded_rect(button_area
, shader
, button_color
, tl
, tr
, bl
, br
)
845 if active_object
and active_object
in selected_objects
and active_object
.name
in collection_objects
:
846 active_object_indicator
= self
.areas
[f
"Button {slot_num} Active Object Indicator"]
848 vertices
= get_circle_coords(active_object_indicator
)
849 shader
.uniform_float("color", icon_color
[:] + (1,))
850 batch
= batch_for_shader(shader
, 'TRI_FAN', {"pos": vertices
})
852 bgl
.glEnable(bgl
.GL_BLEND
)
856 bgl
.glDisable(bgl
.GL_BLEND
)
859 elif not set(selected_objects
).isdisjoint(collection_objects
):
860 selected_object_indicator
= self
.areas
[f
"Button {slot_num} Selected Object Indicator"]
862 alpha
= addon_prefs
.qcd_ogl_selected_icon_alpha
863 vertices
= get_circle_coords(selected_object_indicator
)
864 shader
.uniform_float("color", icon_color
[:] + (alpha
,))
865 batch
= batch_for_shader(shader
, 'LINE_STRIP', {"pos": vertices
})
867 bgl
.glLineWidth(2 * scale_factor())
868 bgl
.glEnable(bgl
.GL_BLEND
)
869 bgl
.glEnable(bgl
.GL_LINE_SMOOTH
)
870 bgl
.glHint(bgl
.GL_LINE_SMOOTH_HINT
, bgl
.GL_NICEST
)
874 bgl
.glDisable(bgl
.GL_LINE_SMOOTH
)
875 bgl
.glDisable(bgl
.GL_BLEND
)
878 elif collection_objects
:
879 object_indicator
= self
.areas
[f
"Button {slot_num} Object Indicator"]
881 alpha
= addon_prefs
.qcd_ogl_objects_icon_alpha
882 vertices
, indices
= get_coords(object_indicator
)
883 shader
.uniform_float("color", icon_color
[:] + (alpha
,))
884 batch
= batch_for_shader(shader
, 'TRIS', {"pos": vertices
}, indices
=indices
)
886 bgl
.glEnable(bgl
.GL_BLEND
)
890 bgl
.glDisable(bgl
.GL_BLEND
)
895 X_icon
= self
.areas
[f
"X_icon {slot_num}"]
896 X_icon_color
= addon_prefs
.qcd_ogl_widget_menu_back_text
898 vertices
, indices
= get_x_coords(X_icon
)
899 shader
.uniform_float("color", X_icon_color
[:] + (1,))
900 batch
= batch_for_shader(shader
, 'TRIS', {"pos": vertices
}, indices
=indices
)
902 bgl
.glEnable(bgl
.GL_BLEND
)
903 bgl
.glEnable(bgl
.GL_POLYGON_SMOOTH
)
904 bgl
.glHint(bgl
.GL_POLYGON_SMOOTH_HINT
, bgl
.GL_NICEST
)
908 bgl
.glDisable(bgl
.GL_POLYGON_SMOOTH
)
909 bgl
.glDisable(bgl
.GL_BLEND
)
912 if self
.draw_tooltip
:
913 slot_name
= qcd_slots
.get_name(f
"{tooltip_slot_idx}")
914 slot_string
= f
"QCD Slot {tooltip_slot_idx}: \"{slot_name}\"\n"
915 hotkey_string
= " * Shift+LMB - Toggle objects\' slot."
917 draw_tooltip(self
, context
, shader
, f
"{slot_string}{hotkey_string}")
919 self
.hover_time
= None
922 if not self
.hover_time
:
923 self
.hover_time
= time
.time()
926 def draw_tooltip(self
, context
, shader
, message
):
927 addon_prefs
= context
.preferences
.addons
[__package__
].preferences
930 line_height
= 11 * scale_factor()
931 text_color
= addon_prefs
.qcd_ogl_widget_tooltip_text
932 blf
.size(font_id
, int(line_height
), 72)
933 blf
.color(font_id
, text_color
[0], text_color
[1], text_color
[2], 1)
935 lines
= message
.split("\n")
937 num_lines
= len(lines
)
940 w
, _
= blf
.dimensions(font_id
, line
)
946 w
, h
= blf
.dimensions(font_id
, longest
[1])
948 line_spacer
= 1 * scale_factor()
949 padding
= 4 * scale_factor()
953 "vert": self
.mouse_pos
,
954 "width": w
+ spacer()*2,
955 "height": (line_height
* num_lines
+ line_spacer
* num_lines
) + padding
*3,
959 x
= tooltip
["vert"][0] - spacer()*2
960 y
= tooltip
["vert"][1] + tooltip
["height"] + round(5 * scale_factor())
961 tooltip
["vert"] = (x
, y
)
963 account_for_view_bounds(tooltip
)
965 outline_color
= addon_prefs
.qcd_ogl_widget_tooltip_outline
966 background_color
= addon_prefs
.qcd_ogl_widget_tooltip_inner
967 draw_rounded_rect(tooltip
, shader
, outline_color
[:] + (1,), outline
=True)
968 draw_rounded_rect(tooltip
, shader
, background_color
)
970 line_pos
= padding
+ line_height
972 for num
, line
in enumerate(lines
):
973 x
= tooltip
["vert"][0] + spacer()
974 y
= tooltip
["vert"][1] - line_pos
975 blf
.position(font_id
, x
, y
, 0)
976 blf
.draw(font_id
, line
)
978 line_pos
+= line_height
+ line_spacer