frontend: Add new appearance options
This commit is contained in:
parent
cce189011e
commit
c0c77071b5
@ -296,6 +296,9 @@ void OBSApp::InitUserConfigDefaults()
|
||||
config_set_default_bool(userConfig, "BasicWindow", "MultiviewDrawAreas", true);
|
||||
|
||||
config_set_default_bool(userConfig, "BasicWindow", "MediaControlsCountdownTimer", true);
|
||||
|
||||
config_set_default_int(userConfig, "Appearance", "FontScale", 10);
|
||||
config_set_default_int(userConfig, "Appearance", "Density", 1);
|
||||
}
|
||||
|
||||
static bool do_mkdir(const char *path)
|
||||
|
@ -204,7 +204,7 @@ static QColor ParseColor(CFParser &cfp)
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool ParseCalc(CFParser &cfp, QStringList &calc, vector<OBSThemeVariable> &vars)
|
||||
static bool ParseMath(CFParser &cfp, QStringList &values, vector<OBSThemeVariable> &vars)
|
||||
{
|
||||
int ret = cf_next_token_should_be(cfp, "(", ";", nullptr);
|
||||
if (ret != PARSE_SUCCESS)
|
||||
@ -216,36 +216,44 @@ static bool ParseCalc(CFParser &cfp, QStringList &calc, vector<OBSThemeVariable>
|
||||
if (cf_token_is(cfp, ";"))
|
||||
break;
|
||||
|
||||
if (cf_token_is(cfp, "calc")) {
|
||||
/* Internal calc's do not have proper names.
|
||||
if (cf_token_is(cfp, "calc") || cf_token_is(cfp, "max") || cf_token_is(cfp, "min")) {
|
||||
/* Internal math operations do not have proper names.
|
||||
* They are anonymous variables */
|
||||
OBSThemeVariable var;
|
||||
QStringList subcalc;
|
||||
QStringList subvalues;
|
||||
|
||||
var.name = QString("__unnamed_%1").arg(QRandomGenerator::global()->generate64());
|
||||
|
||||
if (!ParseCalc(cfp, subcalc, vars))
|
||||
OBSThemeVariable::VariableType varType;
|
||||
if (cf_token_is(cfp, "calc"))
|
||||
varType = OBSThemeVariable::Calc;
|
||||
else if (cf_token_is(cfp, "max"))
|
||||
varType = OBSThemeVariable::Max;
|
||||
else if (cf_token_is(cfp, "min"))
|
||||
varType = OBSThemeVariable::Min;
|
||||
|
||||
if (!ParseMath(cfp, subvalues, vars))
|
||||
return false;
|
||||
|
||||
var.type = OBSThemeVariable::Calc;
|
||||
var.value = subcalc;
|
||||
calc << var.name;
|
||||
var.type = varType;
|
||||
var.value = subvalues;
|
||||
values << var.name;
|
||||
vars.push_back(std::move(var));
|
||||
} else if (cf_token_is(cfp, "var")) {
|
||||
QString value;
|
||||
if (!ParseVarName(cfp, value))
|
||||
return false;
|
||||
|
||||
calc << value;
|
||||
values << value;
|
||||
} else {
|
||||
calc << QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len);
|
||||
values << QString::fromUtf8(cfp->cur_token->str.array, cfp->cur_token->str.len);
|
||||
}
|
||||
|
||||
if (!cf_next_token(cfp))
|
||||
return false;
|
||||
}
|
||||
|
||||
return !calc.isEmpty();
|
||||
return !values.isEmpty();
|
||||
}
|
||||
|
||||
static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
|
||||
@ -316,6 +324,11 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
|
||||
if (!cf_next_token(cfp))
|
||||
return vars;
|
||||
|
||||
/* Special values passed to the theme by OBS are prefixed with 'obs', so we
|
||||
* prevent theme variables from using it as a prefix. */
|
||||
if (key.startsWith("obs"))
|
||||
continue;
|
||||
|
||||
if (cfp->cur_token->type == CFTOKEN_NUM) {
|
||||
const char *ch = cfp->cur_token->str.array;
|
||||
const char *end = ch + cfp->cur_token->str.len;
|
||||
@ -348,14 +361,20 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
|
||||
|
||||
var.value = value;
|
||||
var.type = OBSThemeVariable::Alias;
|
||||
} else if (cf_token_is(cfp, "calc")) {
|
||||
QStringList calc;
|
||||
} else if (cf_token_is(cfp, "calc") || cf_token_is(cfp, "max") || cf_token_is(cfp, "min")) {
|
||||
QStringList values;
|
||||
|
||||
if (!ParseCalc(cfp, calc, vars))
|
||||
if (cf_token_is(cfp, "calc"))
|
||||
var.type = OBSThemeVariable::Calc;
|
||||
else if (cf_token_is(cfp, "max"))
|
||||
var.type = OBSThemeVariable::Max;
|
||||
else if (cf_token_is(cfp, "min"))
|
||||
var.type = OBSThemeVariable::Min;
|
||||
|
||||
if (!ParseMath(cfp, values, vars))
|
||||
continue;
|
||||
|
||||
var.type = OBSThemeVariable::Calc;
|
||||
var.value = calc;
|
||||
var.value = values;
|
||||
} else {
|
||||
var.type = OBSThemeVariable::String;
|
||||
BPtr strVal = cf_literal_to_str(cfp->cur_token->str.array, cfp->cur_token->str.len);
|
||||
@ -367,8 +386,9 @@ static vector<OBSThemeVariable> ParseThemeVariables(const char *themeData)
|
||||
|
||||
if (cf_token_is(cfp, "!") &&
|
||||
cf_next_token_should_be(cfp, "editable", nullptr, nullptr) == PARSE_SUCCESS) {
|
||||
if (var.type == OBSThemeVariable::Calc || var.type == OBSThemeVariable::Alias) {
|
||||
blog(LOG_WARNING, "Variable of calc/alias type cannot be editable: %s",
|
||||
if (var.type == OBSThemeVariable::Calc || var.type == OBSThemeVariable::Max ||
|
||||
var.type == OBSThemeVariable::Min || var.type == OBSThemeVariable::Alias) {
|
||||
blog(LOG_WARNING, "Math or alias variable type cannot be editable: %s",
|
||||
QT_TO_UTF8(var.name));
|
||||
} else {
|
||||
var.editable = true;
|
||||
@ -496,10 +516,10 @@ static bool ResolveVariable(const QHash<QString, OBSThemeVariable> &vars, OBSThe
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString EvalCalc(const QHash<QString, OBSThemeVariable> &vars, const OBSThemeVariable &var,
|
||||
const int recursion = 0);
|
||||
static QString EvalMath(const QHash<QString, OBSThemeVariable> &vars, const OBSThemeVariable &var,
|
||||
const OBSThemeVariable::VariableType type, const int recursion = 0);
|
||||
|
||||
static OBSThemeVariable ParseCalcVariable(const QHash<QString, OBSThemeVariable> &vars, const QString &value,
|
||||
static OBSThemeVariable ParseMathVariable(const QHash<QString, OBSThemeVariable> &vars, const QString &value,
|
||||
const int recursion = 0)
|
||||
{
|
||||
OBSThemeVariable var;
|
||||
@ -527,15 +547,17 @@ static OBSThemeVariable ParseCalcVariable(const QHash<QString, OBSThemeVariable>
|
||||
var.value = value;
|
||||
ResolveVariable(vars, var);
|
||||
|
||||
/* Handle nested calc()s */
|
||||
if (var.type == OBSThemeVariable::Calc) {
|
||||
QString val = EvalCalc(vars, var, recursion + 1);
|
||||
var = ParseCalcVariable(vars, val);
|
||||
/* Handle nested math calculations */
|
||||
if (var.type == OBSThemeVariable::Calc || var.type == OBSThemeVariable::Max ||
|
||||
var.type == OBSThemeVariable::Min) {
|
||||
QString val = EvalMath(vars, var, var.type, recursion + 1);
|
||||
var = ParseMathVariable(vars, val);
|
||||
}
|
||||
|
||||
/* Only number or size would be valid here */
|
||||
if (var.type != OBSThemeVariable::Number && var.type != OBSThemeVariable::Size) {
|
||||
blog(LOG_ERROR, "calc() operand is not a size or number: %s", QT_TO_UTF8(var.value.toString()));
|
||||
blog(LOG_ERROR, "Math operand is not a size or number: %s %s %d", QT_TO_UTF8(var.name),
|
||||
QT_TO_UTF8(var.value.toString()), var.type);
|
||||
throw invalid_argument("Operand not of numeric type");
|
||||
}
|
||||
}
|
||||
@ -543,69 +565,85 @@ static OBSThemeVariable ParseCalcVariable(const QHash<QString, OBSThemeVariable>
|
||||
return var;
|
||||
}
|
||||
|
||||
static QString EvalCalc(const QHash<QString, OBSThemeVariable> &vars, const OBSThemeVariable &var, const int recursion)
|
||||
static QString EvalMath(const QHash<QString, OBSThemeVariable> &vars, const OBSThemeVariable &var,
|
||||
const OBSThemeVariable::VariableType type, const int recursion)
|
||||
{
|
||||
if (recursion >= 10) {
|
||||
/* Abort after 10 levels of recursion */
|
||||
blog(LOG_ERROR, "Maximum calc() recursion levels hit!");
|
||||
blog(LOG_ERROR, "Maximum recursion levels hit!");
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
if (type != OBSThemeVariable::Calc && type != OBSThemeVariable::Max && type != OBSThemeVariable::Min) {
|
||||
blog(LOG_ERROR, "Invalid type for math operation!");
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
QStringList args = var.value.toStringList();
|
||||
if (args.length() != 3) {
|
||||
blog(LOG_ERROR, "calc() had invalid number of arguments: %lld (%s)", args.length(),
|
||||
QT_TO_UTF8(args.join(", ")));
|
||||
QString &opt = args[1];
|
||||
if (type == OBSThemeVariable::Calc && (opt != '*' && opt != '+' && opt != '-' && opt != '/')) {
|
||||
blog(LOG_ERROR, "Unknown/invalid calc() operator: %s", QT_TO_UTF8(opt));
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
QString &opt = args[1];
|
||||
if (opt != '*' && opt != '+' && opt != '-' && opt != '/') {
|
||||
blog(LOG_ERROR, "Unknown/invalid calc() operator: %s", QT_TO_UTF8(opt));
|
||||
if ((type == OBSThemeVariable::Max || type == OBSThemeVariable::Min) && opt != ',') {
|
||||
blog(LOG_ERROR, "Invalid math separator: %s", QT_TO_UTF8(opt));
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
if (args.length() != 3) {
|
||||
blog(LOG_ERROR, "Math parse had invalid number of arguments: %lld (%s)", args.length(),
|
||||
QT_TO_UTF8(args.join(", ")));
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
OBSThemeVariable val1, val2;
|
||||
try {
|
||||
val1 = ParseCalcVariable(vars, args[0], recursion);
|
||||
val2 = ParseCalcVariable(vars, args[2], recursion);
|
||||
val1 = ParseMathVariable(vars, args[0], 0);
|
||||
val2 = ParseMathVariable(vars, args[2], 0);
|
||||
} catch (...) {
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
/* Ensure that suffixes match (if any) */
|
||||
if (!val1.suffix.isEmpty() && !val2.suffix.isEmpty() && val1.suffix != val2.suffix) {
|
||||
blog(LOG_ERROR, "calc() requires suffixes to match or only one to be present! %s != %s",
|
||||
blog(LOG_ERROR, "Math operation requires suffixes to match or only one to be present! %s != %s",
|
||||
QT_TO_UTF8(val1.suffix), QT_TO_UTF8(val2.suffix));
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
double val = numeric_limits<double>::quiet_NaN();
|
||||
double d1 = val1.userValue.isValid() ? val1.userValue.toDouble() : val1.value.toDouble();
|
||||
double d2 = val2.userValue.isValid() ? val2.userValue.toDouble() : val2.value.toDouble();
|
||||
|
||||
if (!isfinite(d1) || !isfinite(d2)) {
|
||||
blog(LOG_ERROR,
|
||||
"calc() received at least one invalid value:"
|
||||
"At least one invalid math value:"
|
||||
" op1: %f, op2: %f",
|
||||
d1, d2);
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
|
||||
if (opt == "+")
|
||||
val = d1 + d2;
|
||||
else if (opt == "-")
|
||||
val = d1 - d2;
|
||||
else if (opt == "*")
|
||||
val = d1 * d2;
|
||||
else if (opt == "/")
|
||||
val = d1 / d2;
|
||||
double val = numeric_limits<double>::quiet_NaN();
|
||||
|
||||
if (!isnormal(val)) {
|
||||
blog(LOG_ERROR,
|
||||
"Invalid calc() math resulted in non-normal number:"
|
||||
" %f %s %f = %f",
|
||||
d1, QT_TO_UTF8(opt), d2, val);
|
||||
return "'Invalid expression'";
|
||||
if (type == OBSThemeVariable::Calc) {
|
||||
if (opt == "+")
|
||||
val = d1 + d2;
|
||||
else if (opt == "-")
|
||||
val = d1 - d2;
|
||||
else if (opt == "*")
|
||||
val = d1 * d2;
|
||||
else if (opt == "/")
|
||||
val = d1 / d2;
|
||||
|
||||
if (!isnormal(val)) {
|
||||
blog(LOG_ERROR, "Invalid calc() resulted in non-normal number: %f %s %f = %f", d1,
|
||||
QT_TO_UTF8(opt), d2, val);
|
||||
return "'Invalid expression'";
|
||||
}
|
||||
} else if (type == OBSThemeVariable::Max) {
|
||||
val = d1 > d2 ? d1 : d2;
|
||||
} else if (type == OBSThemeVariable::Min) {
|
||||
val = d1 < d2 ? d1 : d2;
|
||||
}
|
||||
|
||||
bool isInteger = ceill(val) == val;
|
||||
@ -661,8 +699,9 @@ static QString PrepareQSS(const QHash<QString, OBSThemeVariable> &vars, const QS
|
||||
|
||||
if (var.type == OBSThemeVariable::Color) {
|
||||
replace = value.value<QColor>().name(QColor::HexRgb);
|
||||
} else if (var.type == OBSThemeVariable::Calc) {
|
||||
replace = EvalCalc(vars, var);
|
||||
} else if (var.type == OBSThemeVariable::Calc || var.type == OBSThemeVariable::Max ||
|
||||
var.type == OBSThemeVariable::Min) {
|
||||
replace = EvalMath(vars, var, var.type);
|
||||
} else if (var.type == OBSThemeVariable::Size || var.type == OBSThemeVariable::Number) {
|
||||
double val = value.toDouble();
|
||||
bool isInteger = ceill(val) == val;
|
||||
@ -747,6 +786,23 @@ static QPalette PreparePalette(const QHash<QString, OBSThemeVariable> &vars, con
|
||||
return pal;
|
||||
}
|
||||
|
||||
static double getPaddingForDensityId(int id)
|
||||
{
|
||||
double paddingValue = 4;
|
||||
|
||||
if (id == -2) {
|
||||
paddingValue = 0.25;
|
||||
} else if (id == -3) {
|
||||
paddingValue = 2;
|
||||
} else if (id == -4) {
|
||||
paddingValue = 4;
|
||||
} else if (id == -5) {
|
||||
paddingValue = 6;
|
||||
}
|
||||
|
||||
return paddingValue;
|
||||
}
|
||||
|
||||
OBSTheme *OBSApp::GetTheme(const QString &name)
|
||||
{
|
||||
if (!themes.contains(name))
|
||||
@ -775,6 +831,22 @@ bool OBSApp::SetTheme(const QString &name)
|
||||
QStringList themeIds(theme->dependencies);
|
||||
themeIds << theme->id;
|
||||
|
||||
/* Inject Appearance settings into theme vars */
|
||||
OBSThemeVariable fontScale;
|
||||
fontScale.name = "obsFontScale";
|
||||
fontScale.type = OBSThemeVariable::Number;
|
||||
fontScale.value = QVariant::fromValue(config_get_int(App()->GetUserConfig(), "Appearance", "FontScale"));
|
||||
|
||||
const int density = config_get_int(App()->GetUserConfig(), "Appearance", "Density");
|
||||
|
||||
OBSThemeVariable padding;
|
||||
padding.name = "obsPadding";
|
||||
padding.type = OBSThemeVariable::Number;
|
||||
padding.value = QVariant::fromValue(getPaddingForDensityId(density));
|
||||
|
||||
vars[fontScale.name] = std::move(fontScale);
|
||||
vars[padding.name] = std::move(padding);
|
||||
|
||||
/* Find and add high contrast adjustment layer if available */
|
||||
if (HighContrastEnabled()) {
|
||||
for (const OBSTheme &theme_ : themes) {
|
||||
@ -805,6 +877,22 @@ bool OBSApp::SetTheme(const QString &name)
|
||||
contents.emplaceBack(content.constData());
|
||||
}
|
||||
|
||||
/* Check if OBS appearance settings are used in the theme */
|
||||
currentTheme->usesFontScale = false;
|
||||
currentTheme->usesDensity = false;
|
||||
for (const OBSThemeVariable &var_ : vars) {
|
||||
if (var_.type != OBSThemeVariable::Alias)
|
||||
continue;
|
||||
|
||||
if (var_.value.toString() == "obsFontScale") {
|
||||
currentTheme->usesFontScale = true;
|
||||
}
|
||||
|
||||
if (var_.value.toString() == "obsPadding") {
|
||||
currentTheme->usesDensity = true;
|
||||
}
|
||||
}
|
||||
|
||||
const QString stylesheet = PrepareQSS(vars, contents);
|
||||
const QPalette palette = PreparePalette(vars, defaultPalette);
|
||||
setPalette(palette);
|
||||
|
@ -1,16 +1,23 @@
|
||||
#include "AbsoluteSlider.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include "moc_AbsoluteSlider.cpp"
|
||||
|
||||
AbsoluteSlider::AbsoluteSlider(QWidget *parent) : SliderIgnoreScroll(parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
setMouseTracking(true);
|
||||
|
||||
tickColor.setRgb(0x5b, 0x62, 0x73);
|
||||
}
|
||||
|
||||
AbsoluteSlider::AbsoluteSlider(Qt::Orientation orientation, QWidget *parent) : SliderIgnoreScroll(orientation, parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
setMouseTracking(true);
|
||||
|
||||
tickColor.setRgb(0x5b, 0x62, 0x73);
|
||||
}
|
||||
|
||||
void AbsoluteSlider::mousePressEvent(QMouseEvent *event)
|
||||
@ -96,3 +103,64 @@ int AbsoluteSlider::posToRangeValue(QMouseEvent *event)
|
||||
|
||||
return sliderValue;
|
||||
}
|
||||
|
||||
bool AbsoluteSlider::getDisplayTicks() const
|
||||
{
|
||||
return displayTicks;
|
||||
}
|
||||
|
||||
void AbsoluteSlider::setDisplayTicks(bool display)
|
||||
{
|
||||
displayTicks = display;
|
||||
}
|
||||
|
||||
QColor AbsoluteSlider::getTickColor() const
|
||||
{
|
||||
return tickColor;
|
||||
}
|
||||
|
||||
void AbsoluteSlider::setTickColor(QColor c)
|
||||
{
|
||||
tickColor = std::move(c);
|
||||
}
|
||||
|
||||
void AbsoluteSlider::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
if (!getDisplayTicks()) {
|
||||
QSlider::paintEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
QStyleOptionSlider opt;
|
||||
initStyleOption(&opt);
|
||||
|
||||
QRect groove = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
|
||||
QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
|
||||
|
||||
const bool isHorizontal = orientation() == Qt::Horizontal;
|
||||
|
||||
const int sliderLength = isHorizontal ? groove.width() - handle.width() : groove.height() - handle.height();
|
||||
const int handleSize = isHorizontal ? handle.width() : handle.height();
|
||||
const int grooveSize = isHorizontal ? groove.height() : groove.width();
|
||||
const int grooveStart = isHorizontal ? groove.left() : groove.top();
|
||||
const int tickLinePos = isHorizontal ? groove.center().y() : groove.center().x();
|
||||
const int tickLength = std::max((int)(grooveSize * 1.5) + grooveSize, 8 + grooveSize);
|
||||
const int tickLineStart = tickLinePos - (tickLength / 2) + 1;
|
||||
|
||||
for (double offset = minimum(); offset <= maximum(); offset += singleStep()) {
|
||||
double tickPercent = (offset - minimum()) / (maximum() - minimum());
|
||||
const int tickLineOffset = grooveStart + std::floor(sliderLength * tickPercent) + (handleSize / 2);
|
||||
|
||||
const int xPos = isHorizontal ? tickLineOffset : tickLineStart;
|
||||
const int yPos = isHorizontal ? tickLineStart : tickLineOffset;
|
||||
|
||||
const int tickWidth = isHorizontal ? 1 : tickLength;
|
||||
const int tickHeight = isHorizontal ? tickLength : 1;
|
||||
|
||||
painter.fillRect(xPos, yPos, tickWidth, tickHeight, tickColor);
|
||||
}
|
||||
|
||||
QSlider::paintEvent(event);
|
||||
}
|
||||
|
@ -4,11 +4,18 @@
|
||||
|
||||
class AbsoluteSlider : public SliderIgnoreScroll {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QColor tickColor READ getTickColor WRITE setTickColor DESIGNABLE true)
|
||||
|
||||
public:
|
||||
AbsoluteSlider(QWidget *parent = nullptr);
|
||||
AbsoluteSlider(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||
|
||||
bool getDisplayTicks() const;
|
||||
void setDisplayTicks(bool display);
|
||||
|
||||
QColor getTickColor() const;
|
||||
void setTickColor(QColor c);
|
||||
|
||||
signals:
|
||||
void absoluteSliderHovered(int value);
|
||||
|
||||
@ -20,6 +27,11 @@ protected:
|
||||
|
||||
int posToRangeValue(QMouseEvent *event);
|
||||
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
bool dragging = false;
|
||||
bool displayTicks = false;
|
||||
|
||||
QColor tickColor;
|
||||
};
|
||||
|
@ -93,15 +93,9 @@
|
||||
|
||||
/* Layout */
|
||||
/* Configurable Values */
|
||||
|
||||
/* TODO: Min 8, Max 12, Step 1 */
|
||||
--font_base_value: 10;
|
||||
|
||||
/* TODO: Min 2, Max 7, Step 1 */
|
||||
--spacing_base_value: 4;
|
||||
|
||||
/* TODO: Min 0.25, Max 10, Step 2 */
|
||||
--padding_base_value: 4;
|
||||
--font_base_value: var(--obsFontScale);
|
||||
--padding_base_value: var(--obsPadding);
|
||||
--spacing_base_value: calc(2 + calc(var(--obsPadding) / 2));
|
||||
|
||||
/* TODO: Better Accessibility focus state */
|
||||
/* TODO: Move Accessibilty Colors to Theme config system */
|
||||
@ -111,26 +105,27 @@
|
||||
--os_mac_font_base_value: 12;
|
||||
|
||||
--font_base: calc(1pt * var(--font_base_value));
|
||||
--font_small: calc(0.9pt * var(--font_base_value));
|
||||
--font_xsmall: calc(0.85pt * var(--font_base_value));
|
||||
--font_small: max(7pt, calc(0.8pt * var(--font_base_value)));
|
||||
--font_xsmall: max(6.25pt, calc(0.85pt * var(--font_base_value)));
|
||||
--font_large: calc(1.1pt * var(--font_base_value));
|
||||
--font_xlarge: calc(1.5pt * var(--font_base_value));
|
||||
|
||||
--font_heading: calc(2.5pt * var(--font_base_value));
|
||||
|
||||
--icon_base: calc(6px + var(--font_base_value));
|
||||
--icon_base: calc(calc(max(2, var(--obsPadding)) * 1px) + 12px);
|
||||
|
||||
--spacing_base: calc(0.5px * var(--spacing_base_value));
|
||||
--spacing_large: calc(1px * var(--spacing_base_value));
|
||||
--spacing_small: calc(0.25px * var(--spacing_base_value));
|
||||
--spacing_base: min(max(1px, calc(0.4 * var(--spacing_base_value))), 2px);
|
||||
--spacing_large: min(max(2px, calc(1px * var(--spacing_base_value))), 4px);
|
||||
--spacing_small: max(1px, calc(0.25px * var(--spacing_base_value)));
|
||||
--spacing_title: 4px;
|
||||
|
||||
--padding_base: calc(0.5px * var(--padding_base_value));
|
||||
--padding_large: calc(1px * var(--padding_base_value));
|
||||
--padding_xlarge: calc(1.75px * var(--padding_base_value));
|
||||
--padding_small: calc(0.25px * var(--padding_base_value));
|
||||
--padding_large: min(max(1px, calc(1px * var(--padding_base_value))), 5px);
|
||||
--padding_xlarge: min(max(2px, calc(1.75px * var(--padding_base_value))), 10px);
|
||||
--padding_small: max(0px, calc(0.25px * var(--padding_base_value)));
|
||||
|
||||
--padding_wide: calc(8px + calc(2 * var(--padding_base_value)));
|
||||
--padding_container: max(4px, var(--padding_base));
|
||||
--padding_wide: min(calc(12px + max(var(--padding_base_value), 4)), 24px);
|
||||
--padding_menu: calc(4px + calc(2 * var(--padding_base_value)));
|
||||
|
||||
--padding_base_border: calc(var(--padding_base) + 1px);
|
||||
@ -154,9 +149,10 @@
|
||||
--input_font_scale: calc(var(--font_base_value) * 2.2);
|
||||
--input_font_padding: calc(var(--padding_base_value) * 2);
|
||||
|
||||
--input_height_base: calc(var(--input_font_scale) + var(--input_font_padding));
|
||||
--input_padding: var(--padding_large);
|
||||
--input_height: calc(var(--input_height_base) - calc(var(--input_padding) * 2));
|
||||
--input_height_base: max(calc(var(--input_font_scale) + var(--input_font_padding)), 24);
|
||||
--input_padding: calc(2px + var(--padding_base));
|
||||
--input_text_padding: max(calc(6px + var(--padding_base)), 8px);
|
||||
--input_height: calc(var(--input_height_base) - calc(var(--input_padding) * 2px));
|
||||
--input_height_half: calc(var(--input_height_base) / 2);
|
||||
|
||||
--input_bg: var(--grey4);
|
||||
@ -196,6 +192,8 @@
|
||||
--scrollbar_down: var(--grey8);
|
||||
--scrollbar_border: var(--grey2);
|
||||
|
||||
--preview_scale_width: calc(calc(var(--input_text_padding) * 3.5) * calc(var(--font_base_value) / 10));
|
||||
|
||||
--separator_hover: var(--white1);
|
||||
|
||||
--highlight: rgb(42, 130, 218);
|
||||
@ -449,6 +447,9 @@ QListWidget QWidget {
|
||||
border: 1px solid var(--bg_base);
|
||||
}
|
||||
|
||||
* {
|
||||
spacing: var(--spacing_small);
|
||||
}
|
||||
|
||||
/* Misc */
|
||||
|
||||
@ -612,7 +613,7 @@ OBSDock > QWidget {
|
||||
}
|
||||
|
||||
#transitionsFrame {
|
||||
padding: var(--padding_large);
|
||||
padding: var(--padding_container);
|
||||
}
|
||||
|
||||
OBSDock QLabel {
|
||||
@ -661,16 +662,15 @@ QScrollArea {
|
||||
* oversize it and use margin to crunch it back down
|
||||
*/
|
||||
OBSBasicStatusBar {
|
||||
margin-top: 4px;
|
||||
margin-top: var(--spacing_large);
|
||||
border-top: 1px solid var(--border_color);
|
||||
background: var(--bg_base);
|
||||
}
|
||||
|
||||
StatusBarWidget > QFrame {
|
||||
margin-top: 1px;
|
||||
border: 0px solid var(--border_color);
|
||||
border-left-width: 1px;
|
||||
padding: 0px 8px 2px;
|
||||
padding: 0px var(--padding_xlarge) var(--padding_small);
|
||||
}
|
||||
|
||||
/* Group Box */
|
||||
@ -803,6 +803,7 @@ QToolBar {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
margin: var(--spacing_base) 0px;
|
||||
spacing: var(--spacing_base);
|
||||
}
|
||||
|
||||
QToolBarExtension {
|
||||
@ -893,11 +894,10 @@ QTabBar QToolButton {
|
||||
QComboBox,
|
||||
QDateTimeEdit {
|
||||
background-color: var(--input_bg);
|
||||
border-style: solid;
|
||||
border: 1px solid var(--input_bg);
|
||||
border-radius: var(--border_radius);
|
||||
padding: var(--padding_large) var(--padding_large);
|
||||
padding-left: 10px;
|
||||
padding: var(--input_padding) var(--input_text_padding);
|
||||
height: var(--input_height);
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
@ -974,8 +974,7 @@ QPlainTextEdit {
|
||||
background-color: var(--input_bg);
|
||||
border: none;
|
||||
border-radius: var(--border_radius);
|
||||
padding: var(--input_padding) var(--padding_small) var(--input_padding) var(--input_padding);
|
||||
padding-left: 8px;
|
||||
padding: var(--input_padding) var(--input_text_padding);
|
||||
border: 1px solid var(--input_bg);
|
||||
height: var(--input_height);
|
||||
}
|
||||
@ -994,6 +993,13 @@ QPlainTextEdit:focus {
|
||||
border-color: var(--input_border_focus);
|
||||
}
|
||||
|
||||
QLineEdit:read-only,
|
||||
QLineEdit:read-only:hover,
|
||||
QLineEdit:read-only:focus {
|
||||
background-color: transparent;
|
||||
border-color: var(--input_bg);
|
||||
}
|
||||
|
||||
QTextEdit:!editable,
|
||||
QTextEdit:!editable:hover,
|
||||
QTextEdit:!editable:focus {
|
||||
@ -1007,8 +1013,8 @@ QDoubleSpinBox {
|
||||
background-color: var(--input_bg);
|
||||
border: 1px solid var(--input_bg);
|
||||
border-radius: var(--border_radius);
|
||||
padding: var(--input_padding) 0px var(--input_padding) var(--input_padding);
|
||||
padding-left: 8px;
|
||||
padding: var(--input_padding) var(--input_text_padding);
|
||||
height: var(--input_height);
|
||||
max-height: var(--input_height);
|
||||
}
|
||||
|
||||
@ -1096,7 +1102,7 @@ QDoubleSpinBox::down-arrow {
|
||||
|
||||
/* Controls Dock */
|
||||
#controlsFrame {
|
||||
padding: var(--padding_large);
|
||||
padding: var(--padding_container);
|
||||
}
|
||||
|
||||
#controlsFrame QPushButton {
|
||||
@ -1143,55 +1149,26 @@ QDoubleSpinBox::down-arrow {
|
||||
/* Buttons */
|
||||
|
||||
QPushButton {
|
||||
color: var(--text);
|
||||
background-color: var(--button_bg);
|
||||
color: var(--text);
|
||||
border: 1px solid var(--button_border);
|
||||
border-radius: var(--border_radius);
|
||||
height: var(--input_height);
|
||||
max-height: var(--input_height);
|
||||
margin-top: var(--spacing_input);
|
||||
margin-bottom: var(--spacing_input);
|
||||
padding: var(--input_padding) var(--padding_wide);
|
||||
icon-size: var(--icon_base);
|
||||
}
|
||||
|
||||
QPushButton {
|
||||
border: 1px solid var(--button_border);
|
||||
}
|
||||
|
||||
QToolButton {
|
||||
border: 1px solid var(--button_border);
|
||||
}
|
||||
|
||||
QToolButton,
|
||||
.btn-tool {
|
||||
background-color: var(--button_bg);
|
||||
padding: var(--padding_base) var(--padding_base);
|
||||
margin: 0px var(--spacing_base);
|
||||
border: 1px solid var(--button_border);
|
||||
border-radius: var(--border_radius);
|
||||
icon-size: var(--icon_base);
|
||||
}
|
||||
|
||||
QToolButton:last-child,
|
||||
.btn-tool:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
QPushButton:hover,
|
||||
QPushButton:focus {
|
||||
border-color: var(--button_border_hover);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
background-color: var(--button_bg_hover);
|
||||
}
|
||||
|
||||
QToolButton:hover,
|
||||
QToolButton:focus,
|
||||
.btn-tool:hover,
|
||||
.btn-tool:focus,
|
||||
.indicator-mute::indicator:hover,
|
||||
.indicator-mute::indicator:focus {
|
||||
border-color: var(--button_border);
|
||||
background-color: var(--button_bg_hover);
|
||||
QPushButton:hover,
|
||||
QPushButton:focus {
|
||||
border-color: var(--button_border_hover);
|
||||
}
|
||||
|
||||
QPushButton::flat {
|
||||
@ -1200,6 +1177,7 @@ QPushButton::flat {
|
||||
|
||||
QPushButton:checked {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary_light);
|
||||
}
|
||||
|
||||
QPushButton:checked:hover,
|
||||
@ -1213,6 +1191,47 @@ QPushButton:pressed:hover {
|
||||
border-color: var(--button_border);
|
||||
}
|
||||
|
||||
QPushButton:disabled {
|
||||
background-color: var(--button_bg_disabled);
|
||||
border-color: var(--button_border);
|
||||
}
|
||||
|
||||
QPushButton::menu-indicator {
|
||||
image: url(theme:Dark/down.svg);
|
||||
subcontrol-position: right;
|
||||
subcontrol-origin: padding;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
QToolButton {
|
||||
border: 1px solid var(--button_border);
|
||||
}
|
||||
|
||||
QToolButton,
|
||||
.btn-tool {
|
||||
background-color: var(--button_bg);
|
||||
padding: var(--padding_base) var(--padding_base);
|
||||
margin: 0px 0px;
|
||||
border: 1px solid var(--button_border);
|
||||
border-radius: var(--border_radius);
|
||||
icon-size: var(--icon_base);
|
||||
}
|
||||
|
||||
QToolButton:last-child,
|
||||
.btn-tool:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
QToolButton:hover,
|
||||
QToolButton:focus,
|
||||
.btn-tool:hover,
|
||||
.btn-tool:focus,
|
||||
.indicator-mute::indicator:hover,
|
||||
.indicator-mute::indicator:focus {
|
||||
border-color: var(--button_border);
|
||||
background-color: var(--button_bg_hover);
|
||||
}
|
||||
|
||||
QToolButton:pressed,
|
||||
QToolButton:pressed:hover,
|
||||
.btn-tool:pressed,
|
||||
@ -1221,24 +1240,12 @@ QToolButton:pressed:hover,
|
||||
border-color: var(--button_border);
|
||||
}
|
||||
|
||||
QPushButton:disabled {
|
||||
background-color: var(--button_bg_disabled);
|
||||
border-color: var(--button_border);
|
||||
}
|
||||
|
||||
QToolButton:disabled,
|
||||
.btn-tool:disabled {
|
||||
background-color: var(--button_bg_disabled);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
QPushButton::menu-indicator {
|
||||
image: url(theme:Dark/down.svg);
|
||||
subcontrol-position: right;
|
||||
subcontrol-origin: padding;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
/* Sliders */
|
||||
|
||||
QSlider::groove {
|
||||
@ -1309,7 +1316,7 @@ QSlider::handle:hover {
|
||||
}
|
||||
|
||||
QSlider::handle:pressed {
|
||||
background-color: var(--white5);
|
||||
background-color: var(--white3);
|
||||
}
|
||||
|
||||
QSlider::handle:disabled {
|
||||
@ -1349,6 +1356,15 @@ QSlider::handle:disabled {
|
||||
border-bottom: 1px solid #3c404b;
|
||||
}
|
||||
|
||||
VolControl {
|
||||
background: var(--bg_base);
|
||||
}
|
||||
|
||||
VolControl QLabel {
|
||||
font-size: var(--font_small);
|
||||
margin: var(--spacing_small) 0px;
|
||||
}
|
||||
|
||||
VolControl #volLabel {
|
||||
padding: var(--padding_base) 0px var(--padding_base);
|
||||
text-align: center;
|
||||
@ -1377,7 +1393,7 @@ VolControl #volLabel {
|
||||
}
|
||||
|
||||
#vMixerScrollArea VolControl {
|
||||
padding: var(--padding_large) 0px var(--padding_base);
|
||||
padding: var(--padding_container) 0px var(--padding_container);
|
||||
border-right: 1px solid var(--border_color);
|
||||
}
|
||||
|
||||
@ -1407,6 +1423,7 @@ VolControl #volLabel {
|
||||
}
|
||||
|
||||
#vMixerScrollArea VolControl QPushButton {
|
||||
margin-left: var(--spacing_base);
|
||||
margin-right: var(--padding_xlarge);
|
||||
}
|
||||
|
||||
@ -1414,10 +1431,6 @@ VolControl #volLabel {
|
||||
margin-left: var(--padding_xlarge);
|
||||
}
|
||||
|
||||
VolControl {
|
||||
background: var(--bg_base);
|
||||
}
|
||||
|
||||
VolumeMeter {
|
||||
background: transparent;
|
||||
}
|
||||
@ -1527,6 +1540,7 @@ QGroupBox::indicator,
|
||||
QTableView::indicator {
|
||||
width: var(--icon_base);
|
||||
height: var(--icon_base);
|
||||
margin-right: var(--spacing_large);
|
||||
}
|
||||
|
||||
QGroupBox::indicator {
|
||||
@ -1952,7 +1966,7 @@ OBSBasicAdvAudio #scrollAreaWidgetContents {
|
||||
font-size: var(--font_xsmall);
|
||||
height: 14px;
|
||||
max-height: 14px;
|
||||
padding: 0px var(--padding_xlarge);
|
||||
padding: 0px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
@ -1962,7 +1976,13 @@ OBSBasicAdvAudio #scrollAreaWidgetContents {
|
||||
border: 1px solid var(--grey6);
|
||||
}
|
||||
|
||||
#previewScalePercent {
|
||||
padding: 0px var(--input_text_padding);
|
||||
min-width: var(--preview_scale_width);
|
||||
}
|
||||
|
||||
#previewScalingMode {
|
||||
padding: 0px var(--input_text_padding);
|
||||
border: 1px solid var(--grey6);
|
||||
}
|
||||
|
||||
|
@ -24,23 +24,13 @@
|
||||
--primary_light: rgb(33,71,109);
|
||||
|
||||
/* Layout */
|
||||
--font_base_value: 9;
|
||||
--spacing_base_value: 2;
|
||||
--padding_base_value: 0.25;
|
||||
--font_small: max(7pt, calc(0.5pt * var(--font_base_value)));
|
||||
|
||||
/* OS Fixes */
|
||||
--os_mac_font_base_value: 11;
|
||||
--padding_large: min(max(0px, calc(1px * var(--padding_base_value))), 5px);
|
||||
|
||||
--font_small: calc(0.75pt * var(--font_base_value));
|
||||
--padding_container: max(2px, var(--padding_base));
|
||||
|
||||
--icon_base: calc(6px + var(--font_base_value));
|
||||
|
||||
--padding_xlarge: calc(2px + calc(0.5px * var(--padding_base_value)));
|
||||
|
||||
--padding_wide: calc(18px + calc(0.25 * var(--padding_base_value)));
|
||||
--padding_menu: calc(8px + calc(1 * var(--padding_base_value)));
|
||||
|
||||
--input_height_base: calc(1px + calc(var(--input_font_scale) + var(--input_font_padding)));
|
||||
/* Inputs / Controls */
|
||||
|
||||
--border_color: var(--grey6);
|
||||
|
||||
@ -48,6 +38,10 @@
|
||||
--border_radius_small: 1px;
|
||||
--border_radius_large: 2px;
|
||||
|
||||
--input_height_base: max(calc(var(--input_font_scale) + var(--input_font_padding)), 20);
|
||||
--input_padding: calc(0px + var(--padding_base));
|
||||
--input_text_padding: max(calc(6px + var(--padding_base)), 8px);
|
||||
|
||||
--input_bg: var(--grey4);
|
||||
--input_bg_hover: var(--grey1);
|
||||
--input_bg_focus: var(--grey6);
|
||||
@ -263,7 +257,6 @@ QPushButton[toolButton="true"] {
|
||||
|
||||
#vMixerScrollArea QLabel {
|
||||
font-size: var(--font_small);
|
||||
margin: var(--padding_xlarge) 0px;
|
||||
}
|
||||
|
||||
#vMixerScrollArea #volLabel {
|
||||
|
@ -979,7 +979,7 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="appearanceGeneral">
|
||||
<property name="title">
|
||||
<string>Basic.Settings.Appearance.General</string>
|
||||
<string>Basic.Settings.Appearance</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
@ -1021,6 +1021,200 @@
|
||||
<widget class="QComboBox" name="themeVariant"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="appearanceSettingLabelFontScale">
|
||||
<property name="text">
|
||||
<string>Font Size</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>appearanceFontScale</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_23" stretch="0,5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="appearanceFontScaleText">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AbsoluteSlider" name="appearanceFontScale">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBothSides</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Density</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QFrame" name="frame_5">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_34">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="appearanceDensity1">
|
||||
<property name="text">
|
||||
<string>Classic</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">appearanceDensityButtonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="appearanceDensity2">
|
||||
<property name="text">
|
||||
<string>Compact</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">appearanceDensityButtonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="appearanceDensity3">
|
||||
<property name="text">
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">appearanceDensityButtonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="appearanceDensity4">
|
||||
<property name="text">
|
||||
<string>Comfortable</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoExclusive">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">appearanceDensityButtonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="horizontalSpacer_17">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@ -1028,7 +1222,7 @@
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>170</width>
|
||||
<height>0</height>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
@ -1049,6 +1243,31 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="appearanceOptionsWarning">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_35">
|
||||
<item>
|
||||
<widget class="QLabel" name="appearanceOptionsWarningLabel">
|
||||
<property name="text">
|
||||
<string>Some appearance options are not available for this style.</string>
|
||||
</property>
|
||||
<property name="class" stdset="0">
|
||||
<string>text-warning</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -2898,8 +3117,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>766</width>
|
||||
<height>592</height>
|
||||
<width>424</width>
|
||||
<height>175</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
@ -3304,8 +3523,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>766</width>
|
||||
<height>558</height>
|
||||
<width>509</width>
|
||||
<height>371</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -3945,8 +4164,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>766</width>
|
||||
<height>558</height>
|
||||
<width>625</width>
|
||||
<height>489</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_27">
|
||||
@ -4495,8 +4714,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>766</width>
|
||||
<height>592</height>
|
||||
<width>258</width>
|
||||
<height>510</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_28">
|
||||
@ -8479,6 +8698,11 @@
|
||||
<extends>QLineEdit</extends>
|
||||
<header>settings/OBSHotkeyEdit.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AbsoluteSlider</class>
|
||||
<extends>QSlider</extends>
|
||||
<header>components/AbsoluteSlider.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>listWidget</tabstop>
|
||||
@ -9058,4 +9282,7 @@
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="appearanceDensityButtonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
@ -297,6 +297,7 @@ void RestrictResetBitrates(initializer_list<QComboBox *> boxes, int maxbitrate);
|
||||
#define SCROLL_CHANGED &QSpinBox::valueChanged
|
||||
#define DSCROLL_CHANGED &QDoubleSpinBox::valueChanged
|
||||
#define TEXT_CHANGED &QPlainTextEdit::textChanged
|
||||
#define SLIDER_CHANGED &QSlider::valueChanged
|
||||
|
||||
#define GENERAL_CHANGED &OBSBasicSettings::GeneralChanged
|
||||
#define STREAM1_CHANGED &OBSBasicSettings::Stream1Changed
|
||||
@ -368,6 +369,11 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
||||
HookWidget(ui->multiviewLayout, COMBO_CHANGED, GENERAL_CHANGED);
|
||||
HookWidget(ui->theme, COMBO_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->themeVariant, COMBO_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->appearanceFontScale, SLIDER_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->appearanceDensity1, CHECK_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->appearanceDensity2, CHECK_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->appearanceDensity3, CHECK_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->appearanceDensity4, CHECK_CHANGED, APPEAR_CHANGED);
|
||||
HookWidget(ui->service, COMBO_CHANGED, STREAM1_CHANGED);
|
||||
HookWidget(ui->server, COMBO_CHANGED, STREAM1_CHANGED);
|
||||
HookWidget(ui->customServer, EDIT_CHANGED, STREAM1_CHANGED);
|
||||
|
@ -225,6 +225,8 @@ private:
|
||||
|
||||
/* Appearance */
|
||||
void InitAppearancePage();
|
||||
void enableAppearanceFontControls(bool enable);
|
||||
void enableAppearanceDensityControls(bool enable);
|
||||
|
||||
bool IsCustomServer();
|
||||
|
||||
@ -346,6 +348,7 @@ private:
|
||||
private slots:
|
||||
void on_theme_activated(int idx);
|
||||
void on_themeVariant_activated(int idx);
|
||||
void updateAppearanceControls();
|
||||
|
||||
void on_listWidget_itemSelectionChanged();
|
||||
void on_buttonBox_clicked(QAbstractButton *button);
|
||||
|
@ -21,6 +21,15 @@ void OBSBasicSettings::InitAppearancePage()
|
||||
ui->theme->setCurrentIndex(idx);
|
||||
|
||||
ui->themeVariant->setPlaceholderText(QTStr("Basic.Settings.Appearance.General.NoVariant"));
|
||||
|
||||
ui->appearanceFontScale->setDisplayTicks(true);
|
||||
|
||||
connect(ui->appearanceFontScale, &QSlider::valueChanged, ui->appearanceFontScaleText,
|
||||
[this](int value) { ui->appearanceFontScaleText->setText(QString::number(value)); });
|
||||
ui->appearanceFontScaleText->setText(QString::number(ui->appearanceFontScale->value()));
|
||||
|
||||
connect(App(), &OBSApp::StyleChanged, this, &OBSBasicSettings::updateAppearanceControls);
|
||||
updateAppearanceControls();
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadThemeList(bool reload)
|
||||
@ -83,6 +92,16 @@ void OBSBasicSettings::LoadAppearanceSettings(bool reload)
|
||||
|
||||
App()->SetTheme(themeId);
|
||||
}
|
||||
|
||||
int fontScale = config_get_int(App()->GetUserConfig(), "Appearance", "FontScale");
|
||||
ui->appearanceFontScale->setValue(fontScale);
|
||||
|
||||
int densityId = config_get_int(App()->GetUserConfig(), "Appearance", "Density");
|
||||
QAbstractButton *densityButton = ui->appearanceDensityButtonGroup->button(densityId);
|
||||
if (densityButton) {
|
||||
densityButton->setChecked(true);
|
||||
}
|
||||
updateAppearanceControls();
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SaveAppearanceSettings()
|
||||
@ -93,6 +112,13 @@ void OBSBasicSettings::SaveAppearanceSettings()
|
||||
if (savedTheme != currentTheme) {
|
||||
config_set_string(config, "Appearance", "Theme", QT_TO_UTF8(currentTheme->id));
|
||||
}
|
||||
|
||||
config_set_int(config, "Appearance", "FontScale", ui->appearanceFontScale->value());
|
||||
|
||||
int densityId = ui->appearanceDensityButtonGroup->checkedId();
|
||||
config_set_int(config, "Appearance", "Density", densityId);
|
||||
|
||||
App()->SetTheme(currentTheme->id);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::on_theme_activated(int)
|
||||
@ -104,3 +130,30 @@ void OBSBasicSettings::on_themeVariant_activated(int)
|
||||
{
|
||||
LoadAppearanceSettings(true);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::updateAppearanceControls()
|
||||
{
|
||||
OBSTheme *theme = App()->GetTheme();
|
||||
enableAppearanceFontControls(theme->usesFontScale);
|
||||
enableAppearanceDensityControls(theme->usesDensity);
|
||||
if (!theme->usesFontScale || !theme->usesDensity) {
|
||||
ui->appearanceOptionsWarning->setVisible(true);
|
||||
} else {
|
||||
ui->appearanceOptionsWarning->setVisible(false);
|
||||
}
|
||||
style()->polish(ui->appearanceOptionsWarningLabel);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::enableAppearanceFontControls(bool enable)
|
||||
{
|
||||
ui->appearanceFontScale->setEnabled(enable);
|
||||
ui->appearanceFontScaleText->setEnabled(enable);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::enableAppearanceDensityControls(bool enable)
|
||||
{
|
||||
const QList<QAbstractButton *> buttons = ui->appearanceDensityButtonGroup->buttons();
|
||||
for (QAbstractButton *button : buttons) {
|
||||
button->setEnabled(enable);
|
||||
}
|
||||
}
|
||||
|
@ -41,4 +41,7 @@ struct OBSTheme {
|
||||
bool isVisible; /* Whether it should be shown to the user */
|
||||
bool isBaseTheme; /* Whether it is a "style" or variant */
|
||||
bool isHighContrast; /* Whether it is a high-contrast adjustment layer */
|
||||
|
||||
bool usesFontScale = false; /* Whether the generated QSS uses the font scale option */
|
||||
bool usesDensity = false; /* Whether the generated QSS uses the density option */
|
||||
};
|
||||
|
@ -28,6 +28,8 @@ struct OBSThemeVariable {
|
||||
String, /* Raw string (e.g. color name, border style, etc.) */
|
||||
Alias, /* Points at another variable, value will be the key */
|
||||
Calc, /* Simple calculation with two operands */
|
||||
Min, /* Get the smallest of two Size or Number */
|
||||
Max, /* Get the largest of two Size or Number */
|
||||
};
|
||||
|
||||
/* Whether the variable should be editable in the UI */
|
||||
|
Loading…
x
Reference in New Issue
Block a user