window-basic-transform.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "window-basic-transform.hpp"
  2. #include "window-basic-main.hpp"
  3. Q_DECLARE_METATYPE(OBSSceneItem);
  4. static OBSSceneItem FindASelectedItem(OBSScene scene)
  5. {
  6. auto func = [] (obs_scene_t *scene, obs_sceneitem_t *item, void *param)
  7. {
  8. OBSSceneItem &dst = *reinterpret_cast<OBSSceneItem*>(param);
  9. if (obs_sceneitem_selected(item)) {
  10. dst = item;
  11. return false;
  12. }
  13. UNUSED_PARAMETER(scene);
  14. return true;
  15. };
  16. OBSSceneItem item;
  17. obs_scene_enum_items(scene, func, &item);
  18. return item;
  19. }
  20. void OBSBasicTransform::HookWidget(QWidget *widget, const char *signal,
  21. const char *slot)
  22. {
  23. QObject::connect(widget, signal, this, slot);
  24. }
  25. #define COMBO_CHANGED SIGNAL(currentIndexChanged(int))
  26. #define DSCROLL_CHANGED SIGNAL(valueChanged(double))
  27. OBSBasicTransform::OBSBasicTransform(OBSBasic *parent)
  28. : QDialog (parent),
  29. ui (new Ui::OBSBasicTransform),
  30. main (parent)
  31. {
  32. ui->setupUi(this);
  33. HookWidget(ui->positionX, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  34. HookWidget(ui->positionY, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  35. HookWidget(ui->rotation, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  36. HookWidget(ui->sizeX, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  37. HookWidget(ui->sizeY, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  38. HookWidget(ui->align, COMBO_CHANGED, SLOT(OnControlChanged()));
  39. HookWidget(ui->boundsType, COMBO_CHANGED, SLOT(OnBoundsType(int)));
  40. HookWidget(ui->boundsAlign, COMBO_CHANGED, SLOT(OnControlChanged()));
  41. HookWidget(ui->boundsWidth, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  42. HookWidget(ui->boundsHeight, DSCROLL_CHANGED, SLOT(OnControlChanged()));
  43. installEventFilter(CreateShortcutFilter());
  44. OBSScene curScene = main->GetCurrentScene();
  45. SetScene(curScene);
  46. SetItem(FindASelectedItem(curScene));
  47. channelChangedSignal.Connect(obs_get_signal_handler(), "channel_change",
  48. OBSChannelChanged, this);
  49. }
  50. void OBSBasicTransform::SetScene(OBSScene scene)
  51. {
  52. transformSignal.Disconnect();
  53. selectSignal.Disconnect();
  54. deselectSignal.Disconnect();
  55. removeSignal.Disconnect();
  56. if (scene) {
  57. OBSSource source = obs_scene_get_source(scene);
  58. signal_handler_t *signal = obs_source_get_signal_handler(source);
  59. transformSignal.Connect(signal, "item_transform",
  60. OBSSceneItemTransform, this);
  61. removeSignal.Connect(signal, "item_remove",
  62. OBSSceneItemRemoved, this);
  63. selectSignal.Connect(signal, "item_select",
  64. OBSSceneItemSelect, this);
  65. deselectSignal.Connect(signal, "item_deselect",
  66. OBSSceneItemDeselect, this);
  67. }
  68. }
  69. void OBSBasicTransform::SetItem(OBSSceneItem newItem)
  70. {
  71. QMetaObject::invokeMethod(this, "SetItemQt",
  72. Q_ARG(OBSSceneItem, OBSSceneItem(newItem)));
  73. }
  74. void OBSBasicTransform::SetItemQt(OBSSceneItem newItem)
  75. {
  76. item = newItem;
  77. if (item)
  78. RefreshControls();
  79. setEnabled(!!item);
  80. }
  81. void OBSBasicTransform::OBSChannelChanged(void *param, calldata_t *data)
  82. {
  83. OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
  84. uint32_t channel = (uint32_t)calldata_int(data, "channel");
  85. OBSSource source = (obs_source_t*)calldata_ptr(data, "source");
  86. if (channel == 0) {
  87. OBSScene scene = obs_scene_from_source(source);
  88. window->SetScene(scene);
  89. if (!scene)
  90. window->SetItem(nullptr);
  91. else
  92. window->SetItem(FindASelectedItem(scene));
  93. }
  94. }
  95. void OBSBasicTransform::OBSSceneItemTransform(void *param, calldata_t *data)
  96. {
  97. OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
  98. OBSSceneItem item = (obs_sceneitem_t*)calldata_ptr(data, "item");
  99. if (item == window->item && !window->ignoreTransformSignal)
  100. QMetaObject::invokeMethod(window, "RefreshControls");
  101. }
  102. void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t *data)
  103. {
  104. OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
  105. OBSScene scene = (obs_scene_t*)calldata_ptr(data, "scene");
  106. OBSSceneItem item = (obs_sceneitem_t*)calldata_ptr(data, "item");
  107. if (item == window->item)
  108. window->SetItem(FindASelectedItem(scene));
  109. }
  110. void OBSBasicTransform::OBSSceneItemSelect(void *param, calldata_t *data)
  111. {
  112. OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
  113. OBSSceneItem item = (obs_sceneitem_t*)calldata_ptr(data, "item");
  114. if (item != window->item)
  115. window->SetItem(item);
  116. }
  117. void OBSBasicTransform::OBSSceneItemDeselect(void *param, calldata_t *data)
  118. {
  119. OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
  120. OBSScene scene = (obs_scene_t*)calldata_ptr(data, "scene");
  121. OBSSceneItem item = (obs_sceneitem_t*)calldata_ptr(data, "item");
  122. if (item == window->item)
  123. window->SetItem(FindASelectedItem(scene));
  124. }
  125. static const uint32_t listToAlign[] = {
  126. OBS_ALIGN_TOP | OBS_ALIGN_LEFT,
  127. OBS_ALIGN_TOP,
  128. OBS_ALIGN_TOP | OBS_ALIGN_RIGHT,
  129. OBS_ALIGN_LEFT,
  130. OBS_ALIGN_CENTER,
  131. OBS_ALIGN_RIGHT,
  132. OBS_ALIGN_BOTTOM | OBS_ALIGN_LEFT,
  133. OBS_ALIGN_BOTTOM,
  134. OBS_ALIGN_BOTTOM | OBS_ALIGN_RIGHT
  135. };
  136. static int AlignToList(uint32_t align)
  137. {
  138. int index = 0;
  139. for (uint32_t curAlign : listToAlign) {
  140. if (curAlign == align)
  141. return index;
  142. index++;
  143. }
  144. return 0;
  145. }
  146. void OBSBasicTransform::RefreshControls()
  147. {
  148. if (!item)
  149. return;
  150. obs_transform_info osi;
  151. obs_sceneitem_get_info(item, &osi);
  152. obs_source_t *source = obs_sceneitem_get_source(item);
  153. float width = float(obs_source_get_width(source));
  154. float height = float(obs_source_get_height(source));
  155. int alignIndex = AlignToList(osi.alignment);
  156. int boundsAlignIndex = AlignToList(osi.bounds_alignment);
  157. ignoreItemChange = true;
  158. ui->positionX->setValue(osi.pos.x);
  159. ui->positionY->setValue(osi.pos.y);
  160. ui->rotation->setValue(osi.rot);
  161. ui->sizeX->setValue(osi.scale.x * width);
  162. ui->sizeY->setValue(osi.scale.y * height);
  163. ui->align->setCurrentIndex(alignIndex);
  164. ui->boundsType->setCurrentIndex(int(osi.bounds_type));
  165. ui->boundsAlign->setCurrentIndex(boundsAlignIndex);
  166. ui->boundsWidth->setValue(osi.bounds.x);
  167. ui->boundsHeight->setValue(osi.bounds.y);
  168. ignoreItemChange = false;
  169. }
  170. void OBSBasicTransform::OnBoundsType(int index)
  171. {
  172. if (index == -1)
  173. return;
  174. obs_bounds_type type = (obs_bounds_type)index;
  175. bool enable = (type != OBS_BOUNDS_NONE);
  176. ui->boundsAlign->setEnabled(enable);
  177. ui->boundsWidth->setEnabled(enable);
  178. ui->boundsHeight->setEnabled(enable);
  179. if (!ignoreItemChange) {
  180. obs_bounds_type lastType = obs_sceneitem_get_bounds_type(item);
  181. if (lastType == OBS_BOUNDS_NONE) {
  182. OBSSource source = obs_sceneitem_get_source(item);
  183. int width = (int)obs_source_get_width(source);
  184. int height = (int)obs_source_get_height(source);
  185. ui->boundsWidth->setValue(width);
  186. ui->boundsHeight->setValue(height);
  187. }
  188. }
  189. OnControlChanged();
  190. }
  191. void OBSBasicTransform::OnControlChanged()
  192. {
  193. if (ignoreItemChange)
  194. return;
  195. obs_source_t *source = obs_sceneitem_get_source(item);
  196. double width = double(obs_source_get_width(source));
  197. double height = double(obs_source_get_height(source));
  198. obs_transform_info oti;
  199. oti.pos.x = float(ui->positionX->value());
  200. oti.pos.y = float(ui->positionY->value());
  201. oti.rot = float(ui->rotation->value());
  202. oti.scale.x = float(ui->sizeX->value() / width);
  203. oti.scale.y = float(ui->sizeY->value() / height);
  204. oti.alignment = listToAlign[ui->align->currentIndex()];
  205. oti.bounds_type = (obs_bounds_type)ui->boundsType->currentIndex();
  206. oti.bounds_alignment = listToAlign[ui->boundsAlign->currentIndex()];
  207. oti.bounds.x = float(ui->boundsWidth->value());
  208. oti.bounds.y = float(ui->boundsHeight->value());
  209. ignoreTransformSignal = true;
  210. obs_sceneitem_set_info(item, &oti);
  211. ignoreTransformSignal = false;
  212. }