"Fossies" - the Fresh Open Source Software Archive

Member "ssr-0.4.2/src/GUI/WidgetRack.cpp" (18 May 2020, 7708 Bytes) of package /linux/privat/ssr-0.4.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "WidgetRack.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.4.1_vs_0.4.2.

    1 /*
    2 Copyright (c) 2012-2014 Maarten Baert <maarten-baert@hotmail.com>
    3 
    4 This file is part of SimpleScreenRecorder.
    5 
    6 SimpleScreenRecorder is free software: you can redistribute it and/or modify
    7 it under the terms of the GNU General Public License as published by
    8 the Free Software Foundation, either version 3 of the License, or
    9 (at your option) any later version.
   10 
   11 SimpleScreenRecorder is distributed in the hope that it will be useful,
   12 but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 GNU General Public License for more details.
   15 
   16 You should have received a copy of the GNU General Public License
   17 along with SimpleScreenRecorder.  If not, see <http://www.gnu.org/licenses/>.
   18 */
   19 
   20 #include "WidgetRack.h"
   21 
   22 static QSize GetWidgetSize(QWidget* widget) {
   23     QSize size = widget->sizeHint();
   24     if(!size.isValid())
   25         size = QSize(0, 0);
   26     QSize minimumsize = widget->minimumSize();
   27     if(!minimumsize.isValid())
   28         minimumsize = widget->minimumSizeHint();
   29     if(minimumsize.isValid())
   30         size = size.expandedTo(minimumsize);
   31     QSize maximumsize = widget->maximumSize();
   32     if(maximumsize.isValid())
   33         size = size.boundedTo(maximumsize);
   34     return size;
   35 }
   36 
   37 WidgetRack::WidgetRack(QWidget* parent)
   38     : QAbstractScrollArea(parent) {
   39 
   40     m_selected_widget = NO_SELECTION;
   41 
   42     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   43     //setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // buggy with GTK style, maximumViewportSize() doesn't take the border into account :(
   44     verticalScrollBar()->setSingleStep(20);
   45 
   46     viewport()->setBackgroundRole(QPalette::Dark);
   47     viewport()->setAutoFillBackground(true);
   48 
   49     connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(OnFocusChange(QWidget*, QWidget*)));
   50 
   51     UpdateRange();
   52 
   53 }
   54 
   55 WidgetRack::~WidgetRack() {
   56 
   57 }
   58 
   59 unsigned int WidgetRack::GetWidgetCount() {
   60     return m_widgets.size();
   61 }
   62 
   63 QWidget* WidgetRack::GetWidget(unsigned int index) {
   64     assert(index < m_widgets.size());
   65     return m_widgets[index];
   66 }
   67 
   68 unsigned int WidgetRack::GetSelected() {
   69     return m_selected_widget;
   70 }
   71 
   72 void WidgetRack::SetSelected(unsigned int index) {
   73     assert(index == NO_SELECTION || index < m_widgets.size());
   74     m_selected_widget = index;
   75     UpdateSelection();
   76 }
   77 
   78 void WidgetRack::AddWidget(unsigned int index, QWidget* widget) {
   79     assert(index <= m_widgets.size());
   80     assert(widget->parent() == viewport());
   81 
   82     widget->setAutoFillBackground(true);
   83     widget->setBackgroundRole(QPalette::Base);
   84     if(widget->focusPolicy() == Qt::NoFocus)
   85         widget->setFocusPolicy(Qt::ClickFocus);
   86     widget->show();
   87 
   88     m_widgets.insert(m_widgets.begin() + index, widget);
   89     UpdateFocusChain();
   90     UpdateRange();
   91     UpdateLayout();
   92 
   93     if(m_selected_widget != NO_SELECTION && m_selected_widget >= index)
   94         ++m_selected_widget;
   95 
   96 }
   97 
   98 void WidgetRack::RemoveWidget(unsigned int index) {
   99     assert(index < m_widgets.size());
  100 
  101     delete m_widgets[index];
  102     m_widgets.erase(m_widgets.begin() + index);
  103     UpdateFocusChain();
  104     UpdateRange();
  105     UpdateLayout();
  106 
  107     if(m_selected_widget != NO_SELECTION) {
  108         if(m_selected_widget == index) {
  109             m_selected_widget = NO_SELECTION;
  110         } else if(m_selected_widget > index) {
  111             --m_selected_widget;
  112         }
  113     }
  114 
  115 }
  116 
  117 void WidgetRack::MoveWidget(unsigned int from, unsigned int to) {
  118     assert(from < m_widgets.size());
  119     assert(to < m_widgets.size());
  120 
  121     QWidget *widget = m_widgets[from];
  122     m_widgets.erase(m_widgets.begin() + from);
  123     m_widgets.insert(m_widgets.begin() + to, widget);
  124     UpdateFocusChain();
  125     UpdateLayout();
  126 
  127     if(m_selected_widget != NO_SELECTION) {
  128         if(m_selected_widget == from) {
  129             m_selected_widget = to;
  130         } else {
  131             if(m_selected_widget > from && m_selected_widget <= to)
  132                 --m_selected_widget;
  133             if(m_selected_widget < from && m_selected_widget >= to)
  134                 ++m_selected_widget;
  135         }
  136     }
  137 
  138 }
  139 
  140 void WidgetRack::MakeVisible(QWidget* widget) {
  141     assert(viewport()->isAncestorOf(widget));
  142     QRect widget_rect(widget->mapTo(viewport(), QPoint(0, verticalScrollBar()->value())), widget->size());
  143     QRect visible_rect(QPoint(0, verticalScrollBar()->value()), viewport()->size());
  144     if(widget_rect.height() > visible_rect.height()) {
  145         if(widget_rect.top() > visible_rect.top()) {
  146             verticalScrollBar()->setValue(widget_rect.top());
  147         } else if(widget_rect.bottom() < visible_rect.bottom()) {
  148             verticalScrollBar()->setValue(visible_rect.top() + widget_rect.bottom() - visible_rect.bottom());
  149         }
  150     } else {
  151         if(widget_rect.top() < visible_rect.top()) {
  152             verticalScrollBar()->setValue(widget_rect.top());
  153         } else if(widget_rect.bottom() > visible_rect.bottom()) {
  154             verticalScrollBar()->setValue(visible_rect.top() + widget_rect.bottom() - visible_rect.bottom());
  155         }
  156     }
  157 }
  158 
  159 bool WidgetRack::viewportEvent(QEvent* event) {
  160     switch(event->type()) {
  161         case QEvent::LayoutRequest: {
  162             UpdateRange();
  163             UpdateLayout();
  164             event->accept();
  165             return true;
  166         }
  167         default: return QAbstractScrollArea::viewportEvent(event);
  168     }
  169 }
  170 
  171 void WidgetRack::resizeEvent(QResizeEvent* event) {
  172     Q_UNUSED(event);
  173     UpdateRange();
  174     UpdateLayout();
  175 }
  176 
  177 void WidgetRack::scrollContentsBy(int dx, int dy) {
  178     if(dx == 0 && dy == 0)
  179         return;
  180     UpdateLayout();
  181 }
  182 
  183 bool WidgetRack::focusNextPrevChild(bool next) {
  184     return QWidget::focusNextPrevChild(next); //TODO// remove?
  185 }
  186 
  187 void WidgetRack::UpdateFocusChain() {
  188     /*
  189     This algorithm assumes that all direct and indirect childs of widgets in the rack are created right after the widget itself,
  190     with no non-child widgets in between. It also assumes that the focus policy of widgets won't change after they have been added to the rack.
  191     If these assumptions are incorrect, the focus chain will probably be messed up, but it won't cause any serious problems.
  192     There's probably some clever way to do this without an intermediate std::vector,
  193     but I don't want to depend too much on Qt internals such as the exact implementation of setTabOrder().
  194     */
  195     QWidget *prev = this;
  196     while(prev->focusPolicy() == Qt::NoFocus) {
  197         prev = prev->previousInFocusChain();
  198         if(prev == this)
  199             break;
  200     }
  201     std::vector<QWidget*> focuschain; // keep this outside the loop to reuse memory
  202     for(unsigned int i = 0; i < m_widgets.size(); ++i) {
  203         focuschain.clear();
  204         QWidget *curr = m_widgets[i];
  205         while(curr != NULL && m_widgets[i]->isAncestorOf(curr)) {
  206             if(curr->focusPolicy() != Qt::NoFocus) // setTabOrder() won't accept these
  207                 focuschain.push_back(curr);
  208             curr = curr->nextInFocusChain();
  209             if(curr == m_widgets[i])
  210                 break;
  211         }
  212         for(QWidget *w : focuschain) {
  213             setTabOrder(prev, w);
  214             prev = w;
  215         }
  216     }
  217 }
  218 
  219 void WidgetRack::UpdateRange() {
  220     int height = 0;
  221     for(unsigned int i = 0; i < m_widgets.size(); ++i) {
  222         QSize size = GetWidgetSize(m_widgets[i]);
  223         height += size.height() + 1;
  224     }
  225     verticalScrollBar()->setPageStep(viewport()->height());
  226     verticalScrollBar()->setRange(0, std::max(0, height - 1 - viewport()->height()));
  227 }
  228 
  229 void WidgetRack::UpdateLayout() {
  230     int y = -verticalScrollBar()->value();
  231     for(unsigned int i = 0; i < m_widgets.size(); ++i) {
  232         QSize size = GetWidgetSize(m_widgets[i]);
  233         m_widgets[i]->setGeometry(0, y, viewport()->width(), size.height());
  234         y += size.height() + 1;
  235     }
  236 }
  237 
  238 void WidgetRack::UpdateSelection() {
  239     assert(m_selected_widget < m_widgets.size() || m_selected_widget == NO_SELECTION);
  240     for(unsigned int i = 0; i < m_widgets.size(); ++i) {
  241         m_widgets[i]->setBackgroundRole((i == m_selected_widget)? QPalette::Highlight : QPalette::Base);
  242     }
  243 }
  244 
  245 void WidgetRack::OnFocusChange(QWidget* old_widget, QWidget* new_widget) {
  246     Q_UNUSED(old_widget);
  247     for(unsigned int i = 0; i < m_widgets.size(); ++i) {
  248         if(m_widgets[i]->isAncestorOf(new_widget)) {
  249             SetSelected(i);
  250             MakeVisible(m_widgets[i]);
  251             break;
  252         }
  253     }
  254     if(viewport()->isAncestorOf(new_widget)) {
  255         MakeVisible(new_widget);
  256     }
  257 }