Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
7.9KB

  1. #!/usr/bin/env python3
  2. # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
  3. # SPDX-License-Identifier: GPL-2.0-or-later
  4. # ------------------------------------------------------------------------------------------------------------
  5. # Imports (Global)
  6. from qt_compat import qt_config
  7. if qt_config == 5:
  8. from PyQt5.QtCore import QPointF, QRectF
  9. from PyQt5.QtWidgets import QGraphicsItem
  10. elif qt_config == 6:
  11. from PyQt6.QtCore import QPointF, QRectF
  12. from PyQt6.QtWidgets import QGraphicsItem
  13. # ------------------------------------------------------------------------------------------------------------
  14. # Imports (Theme)
  15. from .theme import getDefaultThemeName
  16. # ------------------------------------------------------------------------------------------------------------
  17. # Maximum Id for a plugin, treated as invalid/zero if above this value
  18. MAX_PLUGIN_ID_ALLOWED = 0x7FF
  19. # Port Mode
  20. PORT_MODE_NULL = 0
  21. PORT_MODE_INPUT = 1
  22. PORT_MODE_OUTPUT = 2
  23. # Port Type
  24. PORT_TYPE_NULL = 0
  25. PORT_TYPE_AUDIO_JACK = 1
  26. PORT_TYPE_MIDI_JACK = 2
  27. PORT_TYPE_MIDI_ALSA = 3
  28. PORT_TYPE_PARAMETER = 4
  29. # Callback Action
  30. ACTION_GROUP_INFO = 0 # group_id, N, N
  31. ACTION_GROUP_RENAME = 1 # group_id, N, N
  32. ACTION_GROUP_SPLIT = 2 # group_id, N, N
  33. ACTION_GROUP_JOIN = 3 # group_id, N, N
  34. ACTION_GROUP_POSITION = 4 # group_id, N, N, "x1:y1:x2:y2"
  35. ACTION_PORT_INFO = 5 # group_id, port_id, N
  36. ACTION_PORT_RENAME = 6 # group_id, port_id, N
  37. ACTION_PORTS_CONNECT = 7 # N, N, "outG:outP:inG:inP"
  38. ACTION_PORTS_DISCONNECT = 8 # conn_id, N, N
  39. ACTION_PLUGIN_CLONE = 9 # plugin_id, N, N
  40. ACTION_PLUGIN_EDIT = 10 # plugin_id, N, N
  41. ACTION_PLUGIN_RENAME = 11 # plugin_id, N, N
  42. ACTION_PLUGIN_REPLACE = 12 # plugin_id, N, N
  43. ACTION_PLUGIN_REMOVE = 13 # plugin_id, N, N
  44. ACTION_PLUGIN_SHOW_UI = 14 # plugin_id, N, N
  45. ACTION_BG_RIGHT_CLICK = 15 # N, N, N
  46. ACTION_INLINE_DISPLAY = 16 # plugin_id, N, N
  47. # Icon
  48. ICON_APPLICATION = 0
  49. ICON_HARDWARE = 1
  50. ICON_DISTRHO = 2
  51. ICON_FILE = 3
  52. ICON_PLUGIN = 4
  53. ICON_LADISH_ROOM = 5
  54. # Split Option
  55. SPLIT_UNDEF = 0
  56. SPLIT_NO = 1
  57. SPLIT_YES = 2
  58. # Antialiasing Option
  59. ANTIALIASING_NONE = 0
  60. ANTIALIASING_SMALL = 1
  61. ANTIALIASING_FULL = 2
  62. # Eye-Candy Option
  63. EYECANDY_NONE = 0
  64. EYECANDY_SMALL = 1
  65. EYECANDY_FULL = 2
  66. # ------------------------------------------------------------------------------------------------------------
  67. # object types
  68. CanvasBoxType = QGraphicsItem.UserType + 1
  69. CanvasIconType = QGraphicsItem.UserType + 2
  70. CanvasPortType = QGraphicsItem.UserType + 3
  71. CanvasLineType = QGraphicsItem.UserType + 4
  72. CanvasBezierLineType = QGraphicsItem.UserType + 5
  73. CanvasLineMovType = QGraphicsItem.UserType + 6
  74. CanvasBezierLineMovType = QGraphicsItem.UserType + 7
  75. CanvasRubberbandType = QGraphicsItem.UserType + 8
  76. # ------------------------------------------------------------------------------------------------------------
  77. # Canvas options
  78. class options_t(object):
  79. __slots__ = [
  80. 'theme_name',
  81. 'auto_hide_groups',
  82. 'auto_select_items',
  83. 'use_bezier_lines',
  84. 'antialiasing',
  85. 'eyecandy',
  86. 'inline_displays'
  87. ]
  88. # Canvas features
  89. class features_t(object):
  90. __slots__ = [
  91. 'group_info',
  92. 'group_rename',
  93. 'port_info',
  94. 'port_rename',
  95. 'handle_group_pos'
  96. ]
  97. # Main Canvas object
  98. class Canvas(object):
  99. def __init__(self):
  100. self.qobject = None
  101. self.settings = None
  102. self.theme = None
  103. self.initiated = False
  104. self.group_list = []
  105. self.port_list = []
  106. self.connection_list = []
  107. self.animation_list = []
  108. self.group_plugin_map = {}
  109. self.old_group_pos = {}
  110. self.callback = self.callback
  111. self.debug = False
  112. self.scene = None
  113. self.last_z_value = 0
  114. self.last_connection_id = 0
  115. self.initial_pos = QPointF(0, 0)
  116. self.size_rect = QRectF()
  117. def callback(self, action, value1, value2, value_str):
  118. print("Canvas::callback({}, {}, {}, {})".format(action, value1, value2, value_str))
  119. # ------------------------------------------------------------------------------------------------------------
  120. # object lists
  121. class group_dict_t(object):
  122. __slots__ = [
  123. 'group_id',
  124. 'group_name',
  125. 'split',
  126. 'icon',
  127. 'plugin_id',
  128. 'plugin_ui',
  129. 'plugin_inline',
  130. 'widgets'
  131. ]
  132. class port_dict_t(object):
  133. __slots__ = [
  134. 'group_id',
  135. 'port_id',
  136. 'port_name',
  137. 'port_mode',
  138. 'port_type',
  139. 'is_alternate',
  140. 'widget'
  141. ]
  142. class connection_dict_t(object):
  143. __slots__ = [
  144. 'connection_id',
  145. 'group_in_id',
  146. 'port_in_id',
  147. 'group_out_id',
  148. 'port_out_id',
  149. 'widget'
  150. ]
  151. class animation_dict_t(object):
  152. __slots__ = [
  153. 'animation',
  154. 'item'
  155. ]
  156. # ------------------------------------------------------------------------------------------------------------
  157. # Internal functions
  158. def bool2str(check):
  159. return "True" if check else "False"
  160. def port_mode2str(port_mode):
  161. if port_mode == PORT_MODE_NULL:
  162. return "PORT_MODE_NULL"
  163. elif port_mode == PORT_MODE_INPUT:
  164. return "PORT_MODE_INPUT"
  165. elif port_mode == PORT_MODE_OUTPUT:
  166. return "PORT_MODE_OUTPUT"
  167. else:
  168. return "PORT_MODE_???"
  169. def port_type2str(port_type):
  170. if port_type == PORT_TYPE_NULL:
  171. return "PORT_TYPE_NULL"
  172. elif port_type == PORT_TYPE_AUDIO_JACK:
  173. return "PORT_TYPE_AUDIO_JACK"
  174. elif port_type == PORT_TYPE_MIDI_JACK:
  175. return "PORT_TYPE_MIDI_JACK"
  176. elif port_type == PORT_TYPE_MIDI_ALSA:
  177. return "PORT_TYPE_MIDI_ALSA"
  178. elif port_type == PORT_TYPE_PARAMETER:
  179. return "PORT_TYPE_MIDI_PARAMETER"
  180. else:
  181. return "PORT_TYPE_???"
  182. def icon2str(icon):
  183. if icon == ICON_APPLICATION:
  184. return "ICON_APPLICATION"
  185. elif icon == ICON_HARDWARE:
  186. return "ICON_HARDWARE"
  187. elif icon == ICON_DISTRHO:
  188. return "ICON_DISTRHO"
  189. elif icon == ICON_FILE:
  190. return "ICON_FILE"
  191. elif icon == ICON_PLUGIN:
  192. return "ICON_PLUGIN"
  193. elif icon == ICON_LADISH_ROOM:
  194. return "ICON_LADISH_ROOM"
  195. else:
  196. return "ICON_???"
  197. def split2str(split):
  198. if split == SPLIT_UNDEF:
  199. return "SPLIT_UNDEF"
  200. elif split == SPLIT_NO:
  201. return "SPLIT_NO"
  202. elif split == SPLIT_YES:
  203. return "SPLIT_YES"
  204. else:
  205. return "SPLIT_???"
  206. # ------------------------------------------------------------------------------------------------------------
  207. # Global objects
  208. canvas = Canvas()
  209. options = options_t()
  210. options.theme_name = getDefaultThemeName()
  211. options.auto_hide_groups = False
  212. options.auto_select_items = False
  213. options.use_bezier_lines = True
  214. options.antialiasing = ANTIALIASING_SMALL
  215. options.eyecandy = EYECANDY_SMALL
  216. options.inline_displays = False
  217. features = features_t()
  218. features.group_info = False
  219. features.group_rename = False
  220. features.port_info = False
  221. features.port_rename = False
  222. features.handle_group_pos = False
  223. # PatchCanvas API
  224. def setOptions(new_options):
  225. if canvas.initiated: return
  226. options.theme_name = new_options.theme_name
  227. options.auto_hide_groups = new_options.auto_hide_groups
  228. options.auto_select_items = new_options.auto_select_items
  229. options.use_bezier_lines = new_options.use_bezier_lines
  230. options.antialiasing = new_options.antialiasing
  231. options.eyecandy = new_options.eyecandy
  232. options.inline_displays = new_options.inline_displays
  233. def setFeatures(new_features):
  234. if canvas.initiated: return
  235. features.group_info = new_features.group_info
  236. features.group_rename = new_features.group_rename
  237. features.port_info = new_features.port_info
  238. features.port_rename = new_features.port_rename
  239. features.handle_group_pos = new_features.handle_group_pos