123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- /******************************************************************************
- Copyright (C) 2023 by Lain Bailey <[email protected]>
- Zachary Lund <[email protected]>
- Philippe Groarke <[email protected]>
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
- #include "OBSBasic.hpp"
- #include <utility/display-helpers.hpp>
- #include <widgets/OBSProjector.hpp>
- #include <qt-wrappers.hpp>
- #include <QColorDialog>
- #include <sstream>
- extern void undo_redo(const std::string &data);
- using namespace std;
- void OBSBasic::InitPrimitives()
- {
- ProfileScope("OBSBasic::InitPrimitives");
- obs_enter_graphics();
- gs_render_start(true);
- gs_vertex2f(0.0f, 0.0f);
- gs_vertex2f(0.0f, 1.0f);
- gs_vertex2f(1.0f, 0.0f);
- gs_vertex2f(1.0f, 1.0f);
- box = gs_render_save();
- gs_render_start(true);
- gs_vertex2f(0.0f, 0.0f);
- gs_vertex2f(0.0f, 1.0f);
- boxLeft = gs_render_save();
- gs_render_start(true);
- gs_vertex2f(0.0f, 0.0f);
- gs_vertex2f(1.0f, 0.0f);
- boxTop = gs_render_save();
- gs_render_start(true);
- gs_vertex2f(1.0f, 0.0f);
- gs_vertex2f(1.0f, 1.0f);
- boxRight = gs_render_save();
- gs_render_start(true);
- gs_vertex2f(0.0f, 1.0f);
- gs_vertex2f(1.0f, 1.0f);
- boxBottom = gs_render_save();
- gs_render_start(true);
- for (int i = 0; i <= 360; i += (360 / 20)) {
- float pos = RAD(float(i));
- gs_vertex2f(cosf(pos), sinf(pos));
- }
- circle = gs_render_save();
- InitSafeAreas(&actionSafeMargin, &graphicsSafeMargin, &fourByThreeSafeMargin, &leftLine, &topLine, &rightLine);
- obs_leave_graphics();
- }
- void OBSBasic::UpdatePreviewScalingMenu()
- {
- bool fixedScaling = ui->preview->IsFixedScaling();
- float scalingAmount = ui->preview->GetScalingAmount();
- if (!fixedScaling) {
- ui->actionScaleWindow->setChecked(true);
- ui->actionScaleCanvas->setChecked(false);
- ui->actionScaleOutput->setChecked(false);
- return;
- }
- obs_video_info ovi;
- obs_get_video_info(&ovi);
- ui->actionScaleWindow->setChecked(false);
- ui->actionScaleCanvas->setChecked(scalingAmount == 1.0f);
- ui->actionScaleOutput->setChecked(scalingAmount == float(ovi.output_width) / float(ovi.base_width));
- }
- void OBSBasic::DrawBackdrop(float cx, float cy)
- {
- if (!box)
- return;
- GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "DrawBackdrop");
- gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
- gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
- gs_technique_t *tech = gs_effect_get_technique(solid, "Solid");
- vec4 colorVal;
- vec4_set(&colorVal, 0.0f, 0.0f, 0.0f, 1.0f);
- gs_effect_set_vec4(color, &colorVal);
- gs_technique_begin(tech);
- gs_technique_begin_pass(tech, 0);
- gs_matrix_push();
- gs_matrix_identity();
- gs_matrix_scale3f(float(cx), float(cy), 1.0f);
- gs_load_vertexbuffer(box);
- gs_draw(GS_TRISTRIP, 0, 0);
- gs_matrix_pop();
- gs_technique_end_pass(tech);
- gs_technique_end(tech);
- gs_load_vertexbuffer(nullptr);
- GS_DEBUG_MARKER_END();
- }
- void OBSBasic::RenderMain(void *data, uint32_t, uint32_t)
- {
- GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "RenderMain");
- OBSBasic *window = static_cast<OBSBasic *>(data);
- obs_video_info ovi;
- obs_get_video_info(&ovi);
- window->previewCX = int(window->previewScale * float(ovi.base_width));
- window->previewCY = int(window->previewScale * float(ovi.base_height));
- gs_viewport_push();
- gs_projection_push();
- obs_display_t *display = window->ui->preview->GetDisplay();
- uint32_t width, height;
- obs_display_size(display, &width, &height);
- float right = float(width) - window->previewX;
- float bottom = float(height) - window->previewY;
- gs_ortho(-window->previewX, right, -window->previewY, bottom, -100.0f, 100.0f);
- window->ui->preview->DrawOverflow();
- /* --------------------------------------- */
- gs_ortho(0.0f, float(ovi.base_width), 0.0f, float(ovi.base_height), -100.0f, 100.0f);
- gs_set_viewport(window->previewX, window->previewY, window->previewCX, window->previewCY);
- if (window->IsPreviewProgramMode()) {
- window->DrawBackdrop(float(ovi.base_width), float(ovi.base_height));
- OBSScene scene = window->GetCurrentScene();
- obs_source_t *source = obs_scene_get_source(scene);
- if (source)
- obs_source_video_render(source);
- } else {
- obs_render_main_texture_src_color_only();
- }
- gs_load_vertexbuffer(nullptr);
- /* --------------------------------------- */
- gs_ortho(-window->previewX, right, -window->previewY, bottom, -100.0f, 100.0f);
- gs_reset_viewport();
- uint32_t targetCX = window->previewCX;
- uint32_t targetCY = window->previewCY;
- if (window->drawSafeAreas) {
- RenderSafeAreas(window->actionSafeMargin, targetCX, targetCY);
- RenderSafeAreas(window->graphicsSafeMargin, targetCX, targetCY);
- RenderSafeAreas(window->fourByThreeSafeMargin, targetCX, targetCY);
- RenderSafeAreas(window->leftLine, targetCX, targetCY);
- RenderSafeAreas(window->topLine, targetCX, targetCY);
- RenderSafeAreas(window->rightLine, targetCX, targetCY);
- }
- window->ui->preview->DrawSceneEditing();
- if (window->drawSpacingHelpers)
- window->ui->preview->DrawSpacingHelpers();
- /* --------------------------------------- */
- gs_projection_pop();
- gs_viewport_pop();
- GS_DEBUG_MARKER_END();
- }
- void OBSBasic::ResizePreview(uint32_t cx, uint32_t cy)
- {
- QSize targetSize;
- bool isFixedScaling;
- obs_video_info ovi;
- /* resize preview panel to fix to the top section of the window */
- targetSize = GetPixelSize(ui->preview);
- isFixedScaling = ui->preview->IsFixedScaling();
- obs_get_video_info(&ovi);
- if (isFixedScaling) {
- previewScale = ui->preview->GetScalingAmount();
- ui->preview->ClampScrollingOffsets();
- GetCenterPosFromFixedScale(int(cx), int(cy), targetSize.width() - PREVIEW_EDGE_SIZE * 2,
- targetSize.height() - PREVIEW_EDGE_SIZE * 2, previewX, previewY,
- previewScale);
- previewX += ui->preview->GetScrollX();
- previewY += ui->preview->GetScrollY();
- } else {
- GetScaleAndCenterPos(int(cx), int(cy), targetSize.width() - PREVIEW_EDGE_SIZE * 2,
- targetSize.height() - PREVIEW_EDGE_SIZE * 2, previewX, previewY, previewScale);
- }
- ui->preview->SetScalingAmount(previewScale);
- previewX += float(PREVIEW_EDGE_SIZE);
- previewY += float(PREVIEW_EDGE_SIZE);
- }
- void OBSBasic::on_preview_customContextMenuRequested()
- {
- CreateSourcePopupMenu(GetTopSelectedSourceItem(), true);
- }
- void OBSBasic::on_previewDisabledWidget_customContextMenuRequested()
- {
- QMenu popup(this);
- delete previewProjectorMain;
- QAction *action = popup.addAction(QTStr("Basic.Main.PreviewConextMenu.Enable"), this, &OBSBasic::TogglePreview);
- action->setCheckable(true);
- action->setChecked(obs_display_enabled(ui->preview->GetDisplay()));
- previewProjectorMain = new QMenu(QTStr("Projector.Open.Preview"));
- AddProjectorMenuMonitors(previewProjectorMain, this, &OBSBasic::OpenPreviewProjector);
- previewProjectorMain->addSeparator();
- previewProjectorMain->addAction(QTStr("Projector.Window"), this, &OBSBasic::OpenPreviewWindow);
- popup.addMenu(previewProjectorMain);
- popup.exec(QCursor::pos());
- }
- void OBSBasic::EnablePreviewDisplay(bool enable)
- {
- obs_display_set_enabled(ui->preview->GetDisplay(), enable);
- ui->previewContainer->setVisible(enable);
- ui->previewDisabledWidget->setVisible(!enable);
- }
- void OBSBasic::TogglePreview()
- {
- previewEnabled = !previewEnabled;
- EnablePreviewDisplay(previewEnabled);
- }
- void OBSBasic::EnablePreview()
- {
- if (previewProgramMode)
- return;
- previewEnabled = true;
- EnablePreviewDisplay(true);
- }
- void OBSBasic::DisablePreview()
- {
- if (previewProgramMode)
- return;
- previewEnabled = false;
- EnablePreviewDisplay(false);
- }
- static bool nudge_callback(obs_scene_t *, obs_sceneitem_t *item, void *param)
- {
- if (obs_sceneitem_locked(item))
- return true;
- struct vec2 &offset = *static_cast<struct vec2 *>(param);
- struct vec2 pos;
- if (!obs_sceneitem_selected(item)) {
- if (obs_sceneitem_is_group(item)) {
- struct vec3 offset3;
- vec3_set(&offset3, offset.x, offset.y, 0.0f);
- struct matrix4 matrix;
- obs_sceneitem_get_draw_transform(item, &matrix);
- vec4_set(&matrix.t, 0.0f, 0.0f, 0.0f, 1.0f);
- matrix4_inv(&matrix, &matrix);
- vec3_transform(&offset3, &offset3, &matrix);
- struct vec2 new_offset;
- vec2_set(&new_offset, offset3.x, offset3.y);
- obs_sceneitem_group_enum_items(item, nudge_callback, &new_offset);
- }
- return true;
- }
- obs_sceneitem_get_pos(item, &pos);
- vec2_add(&pos, &pos, &offset);
- obs_sceneitem_set_pos(item, &pos);
- return true;
- }
- void OBSBasic::Nudge(int dist, MoveDir dir)
- {
- if (ui->preview->Locked())
- return;
- struct vec2 offset;
- vec2_set(&offset, 0.0f, 0.0f);
- switch (dir) {
- case MoveDir::Up:
- offset.y = (float)-dist;
- break;
- case MoveDir::Down:
- offset.y = (float)dist;
- break;
- case MoveDir::Left:
- offset.x = (float)-dist;
- break;
- case MoveDir::Right:
- offset.x = (float)dist;
- break;
- }
- if (!recent_nudge) {
- recent_nudge = true;
- OBSDataAutoRelease wrapper = obs_scene_save_transform_states(GetCurrentScene(), true);
- std::string undo_data(obs_data_get_json(wrapper));
- nudge_timer = new QTimer;
- QObject::connect(nudge_timer, &QTimer::timeout, [this, &recent_nudge = recent_nudge, undo_data]() {
- OBSDataAutoRelease rwrapper = obs_scene_save_transform_states(GetCurrentScene(), true);
- std::string redo_data(obs_data_get_json(rwrapper));
- undo_s.add_action(QTStr("Undo.Transform").arg(obs_source_get_name(GetCurrentSceneSource())),
- undo_redo, undo_redo, undo_data, redo_data);
- recent_nudge = false;
- });
- connect(nudge_timer, &QTimer::timeout, nudge_timer, &QTimer::deleteLater);
- nudge_timer->setSingleShot(true);
- }
- if (nudge_timer) {
- nudge_timer->stop();
- nudge_timer->start(1000);
- } else {
- blog(LOG_ERROR, "No nudge timer!");
- }
- obs_scene_enum_items(GetCurrentScene(), nudge_callback, &offset);
- }
- void OBSBasic::on_actionLockPreview_triggered()
- {
- ui->preview->ToggleLocked();
- ui->actionLockPreview->setChecked(ui->preview->Locked());
- }
- void OBSBasic::on_scalingMenu_aboutToShow()
- {
- obs_video_info ovi;
- obs_get_video_info(&ovi);
- QAction *action = ui->actionScaleCanvas;
- QString text = QTStr("Basic.MainMenu.Edit.Scale.Canvas");
- text = text.arg(QString::number(ovi.base_width), QString::number(ovi.base_height));
- action->setText(text);
- action = ui->actionScaleOutput;
- text = QTStr("Basic.MainMenu.Edit.Scale.Output");
- text = text.arg(QString::number(ovi.output_width), QString::number(ovi.output_height));
- action->setText(text);
- action->setVisible(!(ovi.output_width == ovi.base_width && ovi.output_height == ovi.base_height));
- UpdatePreviewScalingMenu();
- }
- void OBSBasic::setPreviewScalingWindow()
- {
- ui->preview->SetFixedScaling(false);
- ui->preview->ResetScrollingOffset();
- emit ui->preview->DisplayResized();
- }
- void OBSBasic::setPreviewScalingCanvas()
- {
- ui->preview->SetFixedScaling(true);
- ui->preview->SetScalingLevel(0);
- emit ui->preview->DisplayResized();
- }
- void OBSBasic::setPreviewScalingOutput()
- {
- obs_video_info ovi;
- obs_get_video_info(&ovi);
- ui->preview->SetFixedScaling(true);
- float scalingAmount = float(ovi.output_width) / float(ovi.base_width);
- // log base ZOOM_SENSITIVITY of x = log(x) / log(ZOOM_SENSITIVITY)
- int32_t approxScalingLevel = int32_t(round(log(scalingAmount) / log(ZOOM_SENSITIVITY)));
- ui->preview->SetScalingLevelAndAmount(approxScalingLevel, scalingAmount);
- emit ui->preview->DisplayResized();
- }
- static void ConfirmColor(SourceTree *sources, const QColor &color, QModelIndexList selectedItems)
- {
- for (int x = 0; x < selectedItems.count(); x++) {
- SourceTreeItem *treeItem = sources->GetItemWidget(selectedItems[x].row());
- treeItem->setStyleSheet("background: " + color.name(QColor::HexArgb));
- treeItem->style()->unpolish(treeItem);
- treeItem->style()->polish(treeItem);
- OBSSceneItem sceneItem = sources->Get(selectedItems[x].row());
- OBSDataAutoRelease privData = obs_sceneitem_get_private_settings(sceneItem);
- obs_data_set_int(privData, "color-preset", 1);
- obs_data_set_string(privData, "color", QT_TO_UTF8(color.name(QColor::HexArgb)));
- }
- }
- void OBSBasic::ColorChange()
- {
- QModelIndexList selectedItems = ui->sources->selectionModel()->selectedIndexes();
- QAction *action = qobject_cast<QAction *>(sender());
- QPushButton *colorButton = qobject_cast<QPushButton *>(sender());
- if (selectedItems.count() == 0)
- return;
- if (colorButton) {
- int preset = colorButton->property("bgColor").value<int>();
- for (int x = 0; x < selectedItems.count(); x++) {
- SourceTreeItem *treeItem = ui->sources->GetItemWidget(selectedItems[x].row());
- treeItem->setStyleSheet("");
- treeItem->setProperty("bgColor", preset);
- treeItem->style()->unpolish(treeItem);
- treeItem->style()->polish(treeItem);
- OBSSceneItem sceneItem = ui->sources->Get(selectedItems[x].row());
- OBSDataAutoRelease privData = obs_sceneitem_get_private_settings(sceneItem);
- obs_data_set_int(privData, "color-preset", preset + 1);
- obs_data_set_string(privData, "color", "");
- }
- for (int i = 1; i < 9; i++) {
- stringstream button;
- button << "preset" << i;
- QPushButton *cButton =
- colorButton->parentWidget()->findChild<QPushButton *>(button.str().c_str());
- cButton->setStyleSheet("border: 1px solid black");
- }
- colorButton->setStyleSheet("border: 2px solid black");
- } else if (action) {
- int preset = action->property("bgColor").value<int>();
- if (preset == 1) {
- OBSSceneItem curSceneItem = GetCurrentSceneItem();
- SourceTreeItem *curTreeItem = GetItemWidgetFromSceneItem(curSceneItem);
- OBSDataAutoRelease curPrivData = obs_sceneitem_get_private_settings(curSceneItem);
- int oldPreset = obs_data_get_int(curPrivData, "color-preset");
- const QString oldSheet = curTreeItem->styleSheet();
- auto liveChangeColor = [=](const QColor &color) {
- if (color.isValid()) {
- curTreeItem->setStyleSheet("background: " + color.name(QColor::HexArgb));
- }
- };
- auto changedColor = [=](const QColor &color) {
- if (color.isValid()) {
- ConfirmColor(ui->sources, color, selectedItems);
- }
- };
- auto rejected = [=]() {
- if (oldPreset == 1) {
- curTreeItem->setStyleSheet(oldSheet);
- curTreeItem->setProperty("bgColor", 0);
- } else if (oldPreset == 0) {
- curTreeItem->setStyleSheet("background: none");
- curTreeItem->setProperty("bgColor", 0);
- } else {
- curTreeItem->setStyleSheet("");
- curTreeItem->setProperty("bgColor", oldPreset - 1);
- }
- curTreeItem->style()->unpolish(curTreeItem);
- curTreeItem->style()->polish(curTreeItem);
- };
- QColorDialog::ColorDialogOptions options = QColorDialog::ShowAlphaChannel;
- const char *oldColor = obs_data_get_string(curPrivData, "color");
- const char *customColor = *oldColor != 0 ? oldColor : "#55FF0000";
- #ifdef __linux__
- // TODO: Revisit hang on Ubuntu with native dialog
- options |= QColorDialog::DontUseNativeDialog;
- #endif
- QColorDialog *colorDialog = new QColorDialog(this);
- colorDialog->setOptions(options);
- colorDialog->setCurrentColor(QColor(customColor));
- connect(colorDialog, &QColorDialog::currentColorChanged, liveChangeColor);
- connect(colorDialog, &QColorDialog::colorSelected, changedColor);
- connect(colorDialog, &QColorDialog::rejected, rejected);
- colorDialog->open();
- } else {
- for (int x = 0; x < selectedItems.count(); x++) {
- SourceTreeItem *treeItem = ui->sources->GetItemWidget(selectedItems[x].row());
- treeItem->setStyleSheet("background: none");
- treeItem->setProperty("bgColor", preset);
- treeItem->style()->unpolish(treeItem);
- treeItem->style()->polish(treeItem);
- OBSSceneItem sceneItem = ui->sources->Get(selectedItems[x].row());
- OBSDataAutoRelease privData = obs_sceneitem_get_private_settings(sceneItem);
- obs_data_set_int(privData, "color-preset", preset);
- obs_data_set_string(privData, "color", "");
- }
- }
- }
- }
- void OBSBasic::UpdateProjectorHideCursor()
- {
- for (size_t i = 0; i < projectors.size(); i++)
- projectors[i]->SetHideCursor();
- }
- void OBSBasic::UpdateProjectorAlwaysOnTop(bool top)
- {
- for (size_t i = 0; i < projectors.size(); i++)
- SetAlwaysOnTop(projectors[i], top);
- }
- void OBSBasic::ResetProjectors()
- {
- OBSDataArrayAutoRelease savedProjectorList = SaveProjectors();
- ClearProjectors();
- LoadSavedProjectors(savedProjectorList);
- }
- void OBSBasic::UpdatePreviewSafeAreas()
- {
- drawSafeAreas = config_get_bool(App()->GetUserConfig(), "BasicWindow", "ShowSafeAreas");
- }
- void OBSBasic::UpdatePreviewOverflowSettings()
- {
- bool hidden = config_get_bool(App()->GetUserConfig(), "BasicWindow", "OverflowHidden");
- bool select = config_get_bool(App()->GetUserConfig(), "BasicWindow", "OverflowSelectionHidden");
- bool always = config_get_bool(App()->GetUserConfig(), "BasicWindow", "OverflowAlwaysVisible");
- ui->preview->SetOverflowHidden(hidden);
- ui->preview->SetOverflowSelectionHidden(select);
- ui->preview->SetOverflowAlwaysVisible(always);
- }
- static inline QColor color_from_int(long long val)
- {
- return QColor(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
- }
- QColor OBSBasic::GetSelectionColor() const
- {
- if (config_get_bool(App()->GetUserConfig(), "Accessibility", "OverrideColors")) {
- return color_from_int(config_get_int(App()->GetUserConfig(), "Accessibility", "SelectRed"));
- } else {
- return QColor::fromRgb(255, 0, 0);
- }
- }
- QColor OBSBasic::GetCropColor() const
- {
- if (config_get_bool(App()->GetUserConfig(), "Accessibility", "OverrideColors")) {
- return color_from_int(config_get_int(App()->GetUserConfig(), "Accessibility", "SelectGreen"));
- } else {
- return QColor::fromRgb(0, 255, 0);
- }
- }
- QColor OBSBasic::GetHoverColor() const
- {
- if (config_get_bool(App()->GetUserConfig(), "Accessibility", "OverrideColors")) {
- return color_from_int(config_get_int(App()->GetUserConfig(), "Accessibility", "SelectBlue"));
- } else {
- return QColor::fromRgb(0, 127, 255);
- }
- }
- void OBSBasic::UpdatePreviewSpacingHelpers()
- {
- drawSpacingHelpers = config_get_bool(App()->GetUserConfig(), "BasicWindow", "SpacingHelpersEnabled");
- }
- float OBSBasic::GetDevicePixelRatio()
- {
- return dpi;
- }
- void OBSBasic::UpdatePreviewControls()
- {
- const int scalingLevel = ui->preview->GetScalingLevel();
- if (!ui->preview->IsFixedScaling()) {
- ui->previewXScrollBar->setRange(0, 0);
- ui->previewYScrollBar->setRange(0, 0);
- ui->actionPreviewResetZoom->setEnabled(false);
- return;
- }
- const bool minZoom = scalingLevel == MAX_SCALING_LEVEL;
- const bool maxZoom = scalingLevel == -MAX_SCALING_LEVEL;
- ui->actionPreviewZoomIn->setEnabled(!minZoom);
- ui->previewZoomInButton->setEnabled(!minZoom);
- ui->actionPreviewZoomOut->setEnabled(!maxZoom);
- ui->previewZoomOutButton->setEnabled(!maxZoom);
- ui->actionPreviewResetZoom->setEnabled(scalingLevel != 0);
- }
- void OBSBasic::PreviewScalingModeChanged(int value)
- {
- switch (value) {
- case 0:
- setPreviewScalingWindow();
- break;
- case 1:
- setPreviewScalingCanvas();
- break;
- case 2:
- setPreviewScalingOutput();
- break;
- };
- }
|