Improve time tab (#34)

* add support for weekdays and allow reordering on time tab

* add option to use time relative to streaming/recording start on time tab
This commit is contained in:
WarmUpTill
2020-09-13 00:03:38 +02:00
committed by GitHub
parent a5c8d776f3
commit 21a788b48b
6 changed files with 292 additions and 35 deletions

View File

@@ -2917,13 +2917,23 @@
<attribute name="title">
<string notr="true">Time</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_10">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_42">
<item>
<widget class="QComboBox" name="timeTrigger">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_55">
<property name="text">
<string>At</string>
<string>at</string>
</property>
</widget>
</item>
@@ -2989,12 +2999,12 @@
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_99">
<layout class="QHBoxLayout" name="horizontalLayout_51">
<item>
<widget class="QPushButton" name="timeAdd">
<property name="maximumSize">
@@ -3027,6 +3037,91 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_110">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="Line" name="line_36">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_111">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="timeUp">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>../../../forms/images/up.svg</normaloff>../../../forms/images/up.svg</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="themeID" stdset="0">
<string>upArrowIconSmall</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="timeDown">
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>../../../forms/images/down.svg</normaloff>../../../forms/images/down.svg</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="themeID" stdset="0">
<string>downArrowIconSmall</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_39">
<property name="orientation">

View File

@@ -367,6 +367,16 @@ void handleSceneChange(SwitcherData *s)
s->autoStartedRecently = false;
}
void setLiveTime(SwitcherData *s)
{
s->liveTime = QDateTime::currentDateTime();
}
void resetLiveTime(SwitcherData *s)
{
s->liveTime = QDateTime();
}
static void OBSEvent(enum obs_frontend_event event, void *switcher)
{
switch (event) {
@@ -376,6 +386,14 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
handleSceneChange((SwitcherData *)switcher);
break;
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
setLiveTime((SwitcherData *)switcher);
break;
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
resetLiveTime((SwitcherData *)switcher);
break;
default:
break;
}

View File

@@ -42,7 +42,7 @@ public:
int executableFindByData(const QString &exe);
int IgnoreIdleWindowsFindByData(const QString &window);
int randomFindByData(const QString &scene);
int timeFindByData(const QString &timeStr);
int timeFindByData(const timeTrigger &trigger, const QTime &time);
void UpdateNonMatchingScene(const QString &name);
void UpdateAutoStopScene(const QString &name);
@@ -172,6 +172,8 @@ public slots:
void on_timeSwitches_currentRowChanged(int idx);
void on_timeAdd_clicked();
void on_timeRemove_clicked();
void on_timeUp_clicked();
void on_timeDown_clicked();
void on_priorityUp_clicked();
void on_priorityDown_clicked();

View File

@@ -235,16 +235,18 @@ struct MediaSwitch {
struct TimeSwitch {
OBSWeakSource scene;
OBSWeakSource transition;
timeTrigger trigger;
QTime time;
bool matched;
bool usePreviousScene;
std::string timeSwitchStr;
inline TimeSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
QTime time_, bool usePreviousScene_,
std::string timeSwitchStr_)
timeTrigger trigger_, QTime time_,
bool usePreviousScene_, std::string timeSwitchStr_)
: scene(scene_),
transition(transition_),
trigger(trigger_),
time(time_),
usePreviousScene(usePreviousScene_),
timeSwitchStr(timeSwitchStr_)
@@ -324,6 +326,7 @@ struct SwitcherData {
std::vector<MediaSwitch> mediaSwitches;
std::vector<TimeSwitch> timeSwitches;
QDateTime liveTime;
std::vector<int> functionNamesByPriority = std::vector<int>{
DEFAULT_PRIORITY_0, DEFAULT_PRIORITY_1, DEFAULT_PRIORITY_2,

View File

@@ -2,7 +2,6 @@
#include <obs.hpp>
#include <QString>
#include <obs-frontend-api.h>
#include "switcher-data-structs.hpp"
static inline bool WeakSourceValid(obs_weak_source_t *ws)
{
@@ -170,12 +169,58 @@ MakeMediaSwitchName(const QString &source, const QString &scene,
return switchName;
}
typedef enum {
ANY_DAY = 0,
MONDAY = 1,
TUSEDAY = 2,
WEDNESDAY = 3,
THURSDAY = 4,
FRIDAY = 5,
SATURDAY = 6,
SUNDAY = 7,
LIVE = 8
} timeTrigger;
static inline QString MakeTimeSwitchName(const QString &scene,
const QString &transition, QTime &time)
const QString &transition,
const timeTrigger &trigger,
const QTime &time)
{
QString switchName = QStringLiteral("At ") + time.toString() +
QStringLiteral(" switch to ") + scene +
QStringLiteral(" using ") + transition;
QString switchName;
switch (trigger) {
case ANY_DAY:
switchName = QStringLiteral("On any weekday");
break;
case MONDAY:
switchName = QStringLiteral("Mondays");
break;
case TUSEDAY:
switchName = QStringLiteral("Tusedays");
break;
case WEDNESDAY:
switchName = QStringLiteral("Wednesdays");
break;
case THURSDAY:
switchName = QStringLiteral("Thursdays");
break;
case FRIDAY:
switchName = QStringLiteral("Fridays");
break;
case SATURDAY:
switchName = QStringLiteral("Saturdays");
break;
case SUNDAY:
switchName = QStringLiteral("Sundays");
break;
case LIVE:
switchName = QStringLiteral(
"Relative to starting streaming / recording");
break;
}
switchName += QStringLiteral(" at ") + time.toString() +
QStringLiteral(" switch to ") + scene +
QStringLiteral(" using ") + transition;
return switchName;
}

View File

@@ -1,5 +1,16 @@
#include "headers/advanced-scene-switcher.hpp"
static std::vector<std::pair<std::string, timeTrigger>> triggerTable = {
{"On any day", timeTrigger::ANY_DAY},
{"Mondays", timeTrigger::MONDAY},
{"Tuesdays", timeTrigger::TUSEDAY},
{"Wednesdays", timeTrigger::WEDNESDAY},
{"Thursdays", timeTrigger::THURSDAY},
{"Fridays", timeTrigger::FRIDAY},
{"Saturdays", timeTrigger::SATURDAY},
{"Sundays", timeTrigger::SUNDAY},
{"Atfer streaming/recording start", timeTrigger::LIVE}};
void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
{
if (loading)
@@ -18,6 +29,7 @@ void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
QString transitionName =
GetWeakSourceName(s.transition).c_str();
ui->timeScenes->setCurrentText(sceneName);
ui->timeTrigger->setCurrentIndex(s.trigger);
ui->timeEdit->setTime(s.time);
ui->timeTransitions->setCurrentText(transitionName);
break;
@@ -25,9 +37,10 @@ void SceneSwitcher::on_timeSwitches_currentRowChanged(int idx)
}
}
int SceneSwitcher::timeFindByData(const QString &timeStr)
int SceneSwitcher::timeFindByData(const timeTrigger &trigger, const QTime &time)
{
QRegExp rx("At " + timeStr + " switch to .*");
QRegExp rx(MakeTimeSwitchName(QStringLiteral(".*"),
QStringLiteral(".*"), trigger, time));
int count = ui->timeSwitches->count();
for (int i = 0; i < count; i++) {
@@ -53,15 +66,25 @@ void SceneSwitcher::on_timeAdd_clicked()
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString text = MakeTimeSwitchName(sceneName, transitionName, time);
std::string triggerStr = ui->timeTrigger->currentText().toStdString();
auto it = std::find_if(
triggerTable.begin(), triggerTable.end(),
[&triggerStr](
const std::pair<std::string, timeTrigger> &element) {
return element.first == triggerStr;
});
timeTrigger trigger = it->second;
QString text =
MakeTimeSwitchName(sceneName, transitionName, trigger, time);
QVariant v = QVariant::fromValue(text);
int idx = timeFindByData(time.toString());
int idx = timeFindByData(trigger, time);
if (idx == -1) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->timeSwitches.emplace_back(
source, transition, time,
source, transition, trigger, time,
(sceneName == QString(PREVIOUS_SCENE_NAME)),
text.toUtf8().constData());
@@ -76,7 +99,7 @@ void SceneSwitcher::on_timeAdd_clicked()
{
std::lock_guard<std::mutex> lock(switcher->m);
for (auto &s : switcher->timeSwitches) {
if (s.time == time) {
if (s.trigger == trigger && s.time == time) {
s.scene = source;
s.transition = transition;
s.usePreviousScene =
@@ -88,8 +111,6 @@ void SceneSwitcher::on_timeAdd_clicked()
}
}
}
ui->timeSwitches->sortItems();
}
}
@@ -119,24 +140,83 @@ void SceneSwitcher::on_timeRemove_clicked()
delete item;
}
void SceneSwitcher::on_timeUp_clicked()
{
int index = ui->timeSwitches->currentRow();
if (index != -1 && index != 0) {
ui->timeSwitches->insertItem(index - 1,
ui->timeSwitches->takeItem(index));
ui->timeSwitches->setCurrentRow(index - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->timeSwitches.begin() + index,
switcher->timeSwitches.begin() + index - 1);
}
}
void SceneSwitcher::on_timeDown_clicked()
{
int index = ui->timeSwitches->currentRow();
if (index != -1 && index != ui->timeSwitches->count() - 1) {
ui->timeSwitches->insertItem(index + 1,
ui->timeSwitches->takeItem(index));
ui->timeSwitches->setCurrentRow(index + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->timeSwitches.begin() + index,
switcher->timeSwitches.begin() + index + 1);
}
}
bool timesAreInInterval(QTime &time1, QTime &time2, int &interval)
{
bool ret = false;
QTime validSwitchTimeWindow = time1.addMSecs(interval);
ret = time1 <= time2 && time2 <= validSwitchTimeWindow;
// check for overflow
if (!ret && validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
ret = time2 >= time1 || time2 <= validSwitchTimeWindow;
}
return ret;
}
bool checkLiveTime(TimeSwitch &s, QDateTime &start, int &interval)
{
if (start.isNull())
return false;
QDateTime now = QDateTime::currentDateTime();
QTime timePassed = QTime(0, 0).addMSecs(start.msecsTo(now));
return timesAreInInterval(s.time, timePassed, interval);
}
bool checkRegularTime(TimeSwitch &s, int &interval)
{
bool match = false;
if (s.trigger != ANY_DAY &&
s.trigger != QDate::currentDate().dayOfWeek())
return false;
QTime now = QTime::currentTime();
return timesAreInInterval(s.time, now, interval);
}
void SwitcherData::checkTimeSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
if (timeSwitches.size() == 0)
return;
QTime now = QTime::currentTime();
for (TimeSwitch &s : timeSwitches) {
QTime validSwitchTimeWindow = s.time.addMSecs(interval);
match = s.time <= now && now <= validSwitchTimeWindow;
if (!match &&
validSwitchTimeWindow.msecsSinceStartOfDay() < interval) {
// check for overflow
match = now >= s.time || now <= validSwitchTimeWindow;
}
if (s.trigger == LIVE)
match = checkLiveTime(s, liveTime, interval);
else
match = checkRegularTime(s, interval);
if (match) {
scene = (s.usePreviousScene) ? previousScene : s.scene;
@@ -172,6 +252,7 @@ void SwitcherData::saveTimeSwitches(obs_data_t *obj)
: sceneName);
obs_data_set_string(array_obj, "transition",
transitionName);
obs_data_set_int(array_obj, "trigger", s.trigger);
obs_data_set_string(
array_obj, "time",
s.time.toString().toStdString().c_str());
@@ -199,17 +280,19 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
const char *scene = obs_data_get_string(array_obj, "scene");
const char *transition =
obs_data_get_string(array_obj, "transition");
timeTrigger trigger =
(timeTrigger)obs_data_get_int(array_obj, "trigger");
QTime time = QTime::fromString(
obs_data_get_string(array_obj, "time"));
std::string timeSwitchStr =
MakeTimeSwitchName(scene, transition, time)
MakeTimeSwitchName(scene, transition, trigger, time)
.toUtf8()
.constData();
switcher->timeSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakTransitionByName(transition), time,
GetWeakTransitionByName(transition), trigger, time,
(strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
timeSwitchStr);
@@ -223,13 +306,24 @@ void SceneSwitcher::setupTimeTab()
populateSceneSelection(ui->timeScenes, true);
populateTransitionSelection(ui->timeTransitions);
for (auto t : triggerTable) {
ui->timeTrigger->addItem(t.first.c_str());
}
// assuming the streaming / recording entry is always last
ui->timeTrigger->setItemData(
(int)triggerTable.size() - 1,
"The time relative to the start of streaming / recording will be used",
Qt::ToolTipRole);
for (auto &s : switcher->timeSwitches) {
std::string sceneName = (s.usePreviousScene)
? PREVIOUS_SCENE_NAME
: GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeTimeSwitchName(
sceneName.c_str(), transitionName.c_str(), s.time);
QString listText = MakeTimeSwitchName(sceneName.c_str(),
transitionName.c_str(),
s.trigger, s.time);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->timeSwitches);