window-basic-transform.cpp 8.7 KB

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