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.

__init__.py 8.3KB

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