VolumeName.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /******************************************************************************
  2. Copyright (C) 2025 by Taylor Giampaolo <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "VolumeName.hpp"
  15. #include <QHBoxLayout>
  16. #include <QLabel>
  17. #include <QResizeEvent>
  18. #include <QStyle>
  19. #include <QStyleOptionButton>
  20. #include <QStylePainter>
  21. #include "moc_VolumeName.cpp"
  22. VolumeName::VolumeName(obs_source_t *source, QWidget *parent)
  23. : QAbstractButton(parent),
  24. indicatorWidth(style()->pixelMetric(QStyle::PM_MenuButtonIndicator, nullptr, this))
  25. {
  26. renamedSignal = OBSSignal(obs_source_get_signal_handler(source), "rename", &VolumeName::obsSourceRenamed, this);
  27. removedSignal = OBSSignal(obs_source_get_signal_handler(source), "remove", &VolumeName::obsSourceRemoved, this);
  28. destroyedSignal =
  29. OBSSignal(obs_source_get_signal_handler(source), "destroy", &VolumeName::obsSourceDestroyed, this);
  30. QHBoxLayout *layout = new QHBoxLayout();
  31. setLayout(layout);
  32. label = new QLabel(this);
  33. layout->addWidget(label);
  34. layout->setContentsMargins(0, 0, indicatorWidth, 0);
  35. QString name = obs_source_get_name(source);
  36. setText(name);
  37. }
  38. VolumeName::~VolumeName() {}
  39. void VolumeName::setAlignment(Qt::Alignment alignment_)
  40. {
  41. if (textAlignment != alignment_) {
  42. textAlignment = alignment_;
  43. update();
  44. }
  45. }
  46. QSize VolumeName::sizeHint() const
  47. {
  48. QStyleOptionButton opt;
  49. opt.initFrom(this);
  50. const QFontMetrics metrics(font());
  51. QSize textSize = metrics.size(Qt::TextSingleLine, text());
  52. int width = textSize.width();
  53. int height = textSize.height();
  54. if (!opt.icon.isNull()) {
  55. height = std::max(height, indicatorWidth);
  56. }
  57. const int spacing = style()->pixelMetric(QStyle::PM_ButtonMargin, &opt, this) / 2;
  58. width += indicatorWidth + spacing;
  59. QSize contentsSize = style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(width, height), this);
  60. return contentsSize;
  61. }
  62. void VolumeName::obsSourceRenamed(void *data, calldata_t *params)
  63. {
  64. VolumeName *widget = static_cast<VolumeName *>(data);
  65. const char *name = calldata_string(params, "new_name");
  66. QMetaObject::invokeMethod(widget, "onRenamed", Qt::QueuedConnection, Q_ARG(QString, name));
  67. }
  68. void VolumeName::obsSourceRemoved(void *data, calldata_t *)
  69. {
  70. VolumeName *widget = static_cast<VolumeName *>(data);
  71. QMetaObject::invokeMethod(widget, "onRemoved", Qt::QueuedConnection);
  72. }
  73. void VolumeName::obsSourceDestroyed(void *data, calldata_t *)
  74. {
  75. VolumeName *widget = static_cast<VolumeName *>(data);
  76. QMetaObject::invokeMethod(widget, "onDestroyed", Qt::QueuedConnection);
  77. }
  78. void VolumeName::resizeEvent(QResizeEvent *event)
  79. {
  80. updateLabelText(text());
  81. QAbstractButton::resizeEvent(event);
  82. }
  83. void VolumeName::paintEvent(QPaintEvent *)
  84. {
  85. QStylePainter painter(this);
  86. QStyleOptionButton opt;
  87. opt.initFrom(this);
  88. painter.drawControl(QStyle::CE_PushButtonBevel, opt);
  89. QRect contentRect = style()->subElementRect(QStyle::SE_PushButtonContents, &opt, this);
  90. int paddingRight = opt.rect.right() - contentRect.right();
  91. int indicatorWidth = style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
  92. QStyleOption arrowOpt = opt;
  93. QRect arrowRect(opt.rect.right() - indicatorWidth - paddingRight / 2,
  94. opt.rect.center().y() - indicatorWidth / 2, indicatorWidth, indicatorWidth);
  95. arrowOpt.rect = arrowRect;
  96. painter.drawPrimitive(QStyle::PE_IndicatorArrowDown, arrowOpt);
  97. }
  98. void VolumeName::onRenamed(QString name)
  99. {
  100. setText(name);
  101. std::string nameStr = name.toStdString();
  102. emit renamed(nameStr.c_str());
  103. }
  104. void VolumeName::setText(const QString &text)
  105. {
  106. QAbstractButton::setText(text);
  107. updateLabelText(text);
  108. }
  109. void VolumeName::updateLabelText(const QString &name)
  110. {
  111. QString plainText = name;
  112. // Handle source names that use rich text.
  113. if (name.contains("<") && name.contains(">")) {
  114. QTextDocument doc;
  115. doc.setHtml(name);
  116. plainText = doc.toPlainText();
  117. }
  118. QFontMetrics metrics(label->font());
  119. QString elidedText = metrics.elidedText(plainText, Qt::ElideMiddle, width() - indicatorWidth * 2);
  120. bool useElidedText = metrics.boundingRect(plainText).width() > width() - indicatorWidth;
  121. bool isRichText = name != plainText;
  122. label->setText(useElidedText && !isRichText ? elidedText : name);
  123. }
  124. void VolumeName::onRemoved()
  125. {
  126. emit removed();
  127. }
  128. void VolumeName::onDestroyed()
  129. {
  130. emit destroyed();
  131. }