[rkward/work/optionset_experiments] rkward: Incomplete attempt at implementing tabslide

Thomas Friedrichsmeier thomas.friedrichsmeier at ruhr-uni-bochum.de
Fri Oct 23 19:08:27 UTC 2015


Git commit 4302f657ea9c70c0f986f338af81a43c200af9c7 by Thomas Friedrichsmeier.
Committed on 01/10/2015 at 19:09.
Pushed by tfry into branch 'work/optionset_experiments'.

Incomplete attempt at implementing tabslide

M  +1    -0    rkward/misc/CMakeLists.txt
M  +95   -0    rkward/misc/rktabslide.cpp
M  +25   -37   rkward/misc/rktabslide.h
M  +7    -4    rkward/plugin/rkoptionset.cpp
M  +2    -0    rkward/plugin/rkoptionset.h

http://commits.kde.org/rkward/4302f657ea9c70c0f986f338af81a43c200af9c7

diff --git a/rkward/misc/CMakeLists.txt b/rkward/misc/CMakeLists.txt
index 285b90b..35988bc 100644
--- a/rkward/misc/CMakeLists.txt
+++ b/rkward/misc/CMakeLists.txt
@@ -26,6 +26,7 @@ SET(misc_STAT_SRCS
    rkmessagecatalog.cpp
    rkdbusapi.cpp
    rkfindbar.cpp
+   rktabslide.cpp
    )
 
 QT4_AUTOMOC(${misc_STAT_SRCS})
diff --git a/rkward/misc/rktabslide.cpp b/rkward/misc/rktabslide.cpp
index ae2ce5e..5d03824 100644
--- a/rkward/misc/rktabslide.cpp
+++ b/rkward/misc/rktabslide.cpp
@@ -17,3 +17,98 @@
 
 #include "rktabslide.h"
 
+#include <QSplitter>
+#include <QVBoxLayout>
+#include <QPainter>
+#include <kvbox.h>
+
+#include "../debug.h"
+
+RKTabSlide::RKTabSlide (QWidget* parent) : QWidget (parent) {
+	RK_TRACE (MISC);
+
+	new QVBoxLayout (this);
+	splitter = new QSplitter (this);
+	tab_bar = new RKTabSlideBar (0);
+	splitter->addWidget (tab_bar);
+	splitter->setCollapsible (0, false);
+	content = new KVBox;
+	splitter->addWidget (content);
+	layout ()->addWidget (splitter);
+
+	last_content_width = -1;
+
+	connect (tab_bar, SIGNAL (activated(int)), this, SLOT (activate(int)));
+}
+
+void RKTabSlide::activate (int index) {
+	RK_TRACE (MISC);
+
+	if (index < 0) {
+		int s = splitter->sizes ().value (1, 0);
+		if (s > 0) last_content_width = s;
+		splitter->setSizes (QList<int> () << width () << 0);
+		tab_bar->setWide (true);
+	} else {
+		tab_bar->setWide (false);
+		int s = last_content_width;
+		if (s <= 0) {
+			s = content->minimumWidth ();
+		}
+		splitter->setSizes (QList<int> () << width () - s << s);
+	}
+}
+
+RKTabSlideBar::RKTabSlideBar (QWidget* parent) : QTreeView (parent) {
+	RK_TRACE (MISC);
+
+	buttons = 0;
+	setWide (false);
+
+	QStyleOptionTabV3 toption;
+	toption.shape = QTabBar::RoundedWest;
+	tab_vspace = style()->pixelMetric (QStyle::PM_TabBarTabVSpace, &toption);
+	tab_hspace = style()->pixelMetric (QStyle::PM_TabBarTabVSpace, &toption);
+	tab_height = fontMetrics ().height () + tab_vspace;
+
+	setItemsExpandable (false);
+	setRootIsDecorated (false);
+	setSelectionBehavior (QAbstractItemView::SelectRows);
+	setSelectionMode (QAbstractItemView::SingleSelection);
+}
+#error Gaaaaah. Perhaps base on QListView + QItemDelegate w/o clipping, instead?
+void RKTabSlideBar::drawRow (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
+//	RK_TRACE (MISC);
+
+	QStyleOptionTabV3 toption;
+	toption.initFrom (this);
+	toption.shape = QTabBar::RoundedWest;
+	toption.rect = option.rect;
+	toption.rect.moveTop (option.rect.y () + dirtyRegionOffset ().y () + tab_vspace);
+	toption.rect.moveLeft (option.rect.x () + dirtyRegionOffset ().x () + tab_hspace);
+	toption.text = index.data ().toString ();
+
+	int current_row = currentIndex ().row ();
+	if (current_row > 0) {
+		int paint_row = index.row ();
+		if (current_row == paint_row) toption.state |= QStyle::State_Selected;
+		else if (current_row == (paint_row - 1)) toption.selectedPosition = QStyleOptionTabV3::PreviousIsSelected;
+		else if (current_row == (paint_row + 1)) toption.selectedPosition = QStyleOptionTabV3::NextIsSelected;
+	}
+
+	style ()->drawControl (QStyle::CE_TabBarTabShape, &toption, painter);
+	toption.shape = QTabBar::RoundedNorth;
+	style ()->drawControl (QStyle::CE_TabBarTabLabel, &toption, painter);
+}
+
+void RKTabSlideBar::setWide (bool wide_format) {
+	RK_TRACE (MISC);
+
+	is_wide = wide_format;
+	setHorizontalScrollBarPolicy (is_wide ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff);
+	// TODO: redraw
+}
+
+
+// KF5 TODO: remove:
+#include "rktabslide.moc"
diff --git a/rkward/misc/rktabslide.h b/rkward/misc/rktabslide.h
index 913dfc0..52e765c 100644
--- a/rkward/misc/rktabslide.h
+++ b/rkward/misc/rktabslide.h
@@ -20,65 +20,53 @@
 
 #include <QWidget>
 #include <QScrollArea>
-#include <QPushButton>
+#include <QTreeView>
 
+class QSplitter;
 class RKTabSlideBar;
 class RKTabSlide : public QWidget {
+	Q_OBJECT
+public:
+	RKTabSlide (QWidget *parent);
 
+	RKTabSlideBar *tabBar () const { return tab_bar; };
+	QWidget *contentArea () const { return content; };
+public slots:
+	void activate (int index);
 private:
 	RKTabSlideBar *tab_bar;
 	QSplitter *splitter;
 	QWidget *content;
+	int last_content_width;
 };
 
-class RKTabButton;
-class RKTabSlideBar : public QScrollArea {
+class RKTabSlideBar : public QTreeView {  // basing on QTreeView, rather than QTableView, as the former is already designed for drawing row by row, rather than cell by cell
 	Q_OBJECT
 public:
 	RKTabSlideBar (QWidget* parent);
 
-	void insertTab (int index, const QString &short_label, const QString &long_label, const QString &tip);
-	void changeTab (int index, const QString &short_label, const QString &long_label, const QString &tip);
-	void removeTab (int index);
-signals:
-	void deleteClicked (int index);
-	void insertClicked (int index);
-	void activated (int index);
-private:
-friend class RKTabButton;
-	void deleteClicked (RKTabButton*);
-	void insertClicked (RKTabButton*);
-	void editClicked (RKTabButton*);
-	int currentindex;
-	QList<RKTabButton*> tabs;
-	QWidget* vbox;
-	QVBoxLayout *vlayout;
-};
-
-class RKTabButton : public QPushButton {
-	Q_OBJECT
-private:
-friend class RKTabSlideBar;
-	RKTabButton (QWidget *parent, RKTabSlideBar *bar);
-
-	void change (const QString &short_label, const QString &long_label);
-	void setWide (bool make_wide);
 	enum InternalButtons {
 		Delete,
 		Insert,
 		Edit
 	};
 	void setInternalButtons (int buttons);
+
+	void setWide (bool wide_format);
+signals:
+	void deleteClicked (int index);
+	void insertClicked (int index);
+	void activated (int index);
 protected:
-	void paintEvent (QPaintEvent *event);
+	void drawRow (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; // re-implemented from QTreeView
+	int sizeHintForRow (int) const { return tab_height; }; // re-implemented from QAbstractItemView: Rows have uniform size. TODO: Guess we also need a QItemDelegate implementing sizeHint().
 private:
-	QString short_label;
-	QString long_label;
-private slots:
-	void buttonClicked (); // To relay clicked()-signal without additional mapper
-	int index;
+	int currentindex;
+	bool is_wide;
+	int buttons;
+	int tab_height;
+	int tab_vspace;
+	int tab_hspace;
 };
 
 #endif
-
-
diff --git a/rkward/plugin/rkoptionset.cpp b/rkward/plugin/rkoptionset.cpp
index 6a38df2..a9b367f 100644
--- a/rkward/plugin/rkoptionset.cpp
+++ b/rkward/plugin/rkoptionset.cpp
@@ -29,6 +29,7 @@
 
 #include "rkstandardcomponent.h"
 #include "../misc/rkcommonfunctions.h"
+#include "../misc/rktabslide.h"
 #include "../misc/rkstandardicons.h"
 #include "../misc/xmlhelper.h"
 
@@ -47,7 +48,7 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
 	min_rows = xml->getIntAttribute (element, "min_rows", 0, DL_INFO);
 	min_rows_if_any = xml->getIntAttribute (element, "min_rows_if_any", 1, DL_INFO);
 	max_rows = xml->getIntAttribute (element, "max_rows", INT_MAX, DL_INFO);
-	exp_mode = (ExperimentalMode) xml->getMultiChoiceAttribute (element, "exp_mode", "regular;detached;tabbed", 1, DL_INFO);
+	exp_mode = (ExperimentalMode) xml->getMultiChoiceAttribute (element, "exp_mode", "regular;detached;tabbed", 2, DL_INFO);
 
 	// build UI framework
 	QVBoxLayout *layout = new QVBoxLayout (this);
@@ -55,6 +56,7 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
 	if (exp_mode != Detached) layout->addWidget (switcher);
 	user_area = new KVBox (this);
 	switcher->addWidget (user_area);
+	if (exp_mode == Tabbed) tabslide = new RKTabSlide (user_area);
 	updating_notice = new QLabel (i18n ("Updating status, please wait"), this);
 	switcher->addWidget (updating_notice);
 	update_timer.setInterval (0);
@@ -78,10 +80,10 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
 	// first build the contents, as we will need to refer to the elements inside, later
 	model = 0;
 	display = 0;	// will be created from the builder, on demand -> createDisplay ()
-	contents_container = new RKComponent (this, user_area);
+	contents_container = new RKComponent (this, exp_mode == Tabbed ? tabslide->contentArea () : user_area);
 	QDomElement content_element = xml->getChildElement (element, "content", DL_ERROR);
 	RKComponentBuilder *builder = new RKComponentBuilder (contents_container, content_element);
-	builder->buildElement (content_element, *xml, user_area, false);	// NOTE that parent widget != parent component, here, by intention. The point is that the display should not be disabled along with the contents
+	builder->buildElement (content_element, *xml, exp_mode == Tabbed ? tabslide->contentArea () : user_area, false);	// NOTE that parent widget != parent component, here, by intention. The point is that the display should not be disabled along with the contents
 	builder->parseLogic (xml->getChildElement (element, "logic", DL_INFO), *xml, false);
 	builder->makeConnections ();
 	addChild ("contents", contents_container);
@@ -214,6 +216,7 @@ RKComponent *RKOptionSet::createDisplay (bool show_index, QWidget *parent) {
 		display_show_index = show_index;
 		model = new RKOptionSetDisplayModel (this);
 		if (exp_mode == Detached) display->setItemDelegate (new RKOptionSetDelegate (this));
+		if (exp_mode == Tabbed) tabslide->tabBar ()->setModel (model);
 	}
 
 	display_buttons = new KHBox (dummy);
@@ -893,7 +896,7 @@ void RKOptionSetDelegate::paint (QPainter *painter, const QStyleOptionViewItem &
 		button.rect = option.rect;
 		button.text = i18n ("Edit");
 		button.state = QStyle::State_Enabled;
-		QApplication::style()->drawControl( QStyle::CE_PushButton, &button, painter);
+		QApplication::style ()->drawControl (QStyle::CE_PushButton, &button, painter);
 	} else {
 		QItemDelegate::paint (painter, option, index);
 	}
diff --git a/rkward/plugin/rkoptionset.h b/rkward/plugin/rkoptionset.h
index fe6be90..cf93d44 100644
--- a/rkward/plugin/rkoptionset.h
+++ b/rkward/plugin/rkoptionset.h
@@ -25,6 +25,7 @@
 #include <QTimer>
 #include <QSet>
 
+class RKTabSlide;
 class QTreeView;
 class QPushButton;
 class RKOptionSetDisplayModel;
@@ -119,6 +120,7 @@ friend class RKOptionSetDisplayModel;
 	QStackedWidget *switcher;
 	QWidget *updating_notice;
 	QWidget *user_area;
+	RKTabSlide *tabslide;
 	void updateUnfinishedRows ();
 	int return_to_row;
 	QTimer update_timer;



More information about the rkward-tracker mailing list