window-basic-transform.cpp 8.9 KB

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