DIY Qt Creator redesign



Many of those who are developing in C ++ / Qt are familiar with such an environment as Qt Creator, the creators of which worked on the design no less than on the functionality. But I, as a lover of dark color schemes and flat minimalism, always did not like the light background of the panels and gradient headers.

It would seem open source - take it and change it, but inexperience and laziness stopped me until I found out about such a thing as Qt Style Sheets, which allows you to describe the type of widgets in css format.



I warn you in advance: The following may be not very dirty, but a hack . Of course, he will open a security hole, steal your passwords and send them to Prague hackers, but various artifacts in the interface are possible.

Environment preparation


UPD: Patching anything inappropriately Instead, on the advice of cyberbobs, it’s enough to run QtCreator with the -stylesheet = stylesheet.css parameter, so immediately proceed to redraw, but if you really want to

then continue
First, take the source code of the environment. Unpack and add to the constructor MainWindow::MainWindow() located approximately in ./src/plugins/coreplugin/mainwindow.cpp:199your crutch, providing it with identification marks, so that in which case you can quickly find and destroy :
//$$MARKER
//HACK: Injecting css to change appearance
//Получаем путь к папке с файлами приложения
//В Linux: /home/shed/.local/share/data/Nokia/QtCreator
//В Windows: C:\Document and Settings\user\Local Settings\Application Data
QString csspath = QDesktopServices::storageLocation(QDesktopServices::DataLocation)+"/stylesheet.css";
QFile css(csspath);
if (css.open(QIODevice::ReadOnly | QIODevice::Text)){
    qDebug() << "NOTE: stylesheet loaded from" << csspath;
    QString style = QTextStream(&css).readAll();
    qApp->setStyleSheet(style);
} else {
    qDebug() << "NOTE: stylesheet not found in " << csspath;
}
//$$MARKEREND

lazy can take the modified file for the latest stable version 2.5.0
then
qmake && make && ./bin/qtcreator
if everything went smoothly on the output we get
NOTE: stylesheet not found in <путь-к-таблице-стилей>/stylesheet.css

Now create this stylesheet.css and write there for verification
background: blue; color: red;

we restart qtcreator (to save nerves, we should configure the editor to start qtcreator with one click) and we see such an extravaganza:

As follows, setStyle colored everything blue, but two renegades appeared: a list of classes and methods of the current document and switches for output panels. I have two assumptions why this is so: either these elements are not descendants of the QWidget that they’re vryatli, or they use their own way of rendering bypassing the Qt style system, which is quite possible, given their non-standard appearance.


Redrawing


As you know, the style sheet is a set of records of the form:

	<Селектор>[, <Селектор>, ...] {
		<Параметр>: <Значение>;
		<Параметр>: <Значение>;
		...
		<Параметр>: <Значение>;
	}

If you've never written anything like this before, a few lessons from any tutorial will give you an idea of ​​what will happen below. You should read the Qt Style Sheet documentation and examples later .


Selectors


In demonology, to call a daemon, you need to know its name, in our case, to compile a selector, you need to know the class name, objectName, or the value of any property specified using Q_PROPERTY () and setProperty ().
Qt supports all CSS2 selectors . The most useful according to the documentation:


Universal selector*Matches all widgets.
Type selectorQPushButtonCorresponds to instances of the QPushButton class and its subclasses.
Property selectorQPushButton [flat = "false"]Corresponds to instances of the QPushButton class that are not flat. You can use this selector to check any Qt property specified using Q_PROPERTY ().
Instead of = you can also use ~ = to check if the Qt property of type QStringList contains the given QString string.
Class selectors.QPushButtonCorresponds to instances of the QPushButton class, but not its subclasses.
Equivalent to the expression * [class ~ = "QPushButton"].
ID selectorQPushButton # okButtonMatches all instances of the QPushButton class whose objectName is okButton.
Descendant selectorQDialog QPushButtonMatches all instances of the QPushButton class that are descendants of the QDialog class (children, grandchildren, etc.).
Child selectorQDialog> QPushButtonMatches all instances of the QPushButton class that are direct descendants of QDialog.

So far, we are only interested in a type selector, it would be more flexible and correct to use properties, but this requires intervention in the code.


Now let's play designers.

Let me remind you, we wanted to make a dark background for the panels. To do this, we need to select the selector. What do we usually see in these panels? Trees in "Projects", "Class Overview", "Type Hierarchy" and "Contour" (in the name of "Outline"), lists in the "File System", "Open Documents" and "Bookmarks" and tables in the debug panels, etc. e. the standard QListView, QTreeView and QTableVeiw are named QAbstractItemView .
Therefore, we will write the following in our stylesheet.css:

QAbstractItemView {
	color: #EAEAEA;
	background: #232323; 
	font-size: 9pt;
}

We start, reduce the window size to a minimum so that more elements

come out and see: We got what we wanted, but our (albeit unloved) panels lost their appearance, and without our team. If someone ran his eyes over MainWindow :: MainWindow (), perhaps he noticed an inconspicuous line qApp->setStyle(new ManhattanStyle(baseName));, those who were particularly persistent could click on ManhattanStyle and notice that he was inheriting from QProxyStyle i.e. it is he who redefines the drawing of our panels. And it is he who goes backstage as soon as we set the style.
Anticipating a bunch of petty beauty work in these faded buttons, I decided not to be petty, and besides QAbstractItemView, I also saw QMainWindow , the father of all widgets:

QAbstractItemView, QMainWindow {
	color: #EAEAEA;
	background: #232323; 
	font-size: 9pt;
}

Run:

Almost what you need. It remains to overshadow the white spots of tabs, headers and scrollbars.

Subelements and conditions


Like CCS2, Qt Style Sheet supports subelements and states, i.e. record selector in the form:
<Селектор>::<Субэлемент>:<Состояние>

For example, QScrollBar::left-arrow:horizontalselects all the left arrows of the horizontal scrollbars.
Let's see how it works on our white spots.

Making QTreeView and QAbstractItemView


First, change the appearance of the selected item in QAbstractItemView to a darker one with:
QAbstractItemView::item:selected {
	color: #EAEAEA;
	background-color: #151515;
}
	

Compare:


Now let's deal with QTreeView .
Each line of it consists of one subelement :: item and one or more :: branch:

:: branch in addition to standard states supports 4 more:
* Blue - elements with the desired state
:open:adjoins-item:has-children:has-subling

Thinking, I decided to forget about the boring arrows and make a small gray point opposite the grouped elements. So we need :closed:adjoins-item:has-children. Twitching the parameters we get something like:

QTreeView::branch:closed:adjoins-item:has-children {
     background:  solid #777777;
     margin: 6px;
     height: 6px;
     width: 6px;
     border-radius: 3px;
 }
	



If you like arrows, you should like the url (filename) construct, which is passed to image: or border-image: will set the image stored on the hard drive or in the Qt resource system as the background or border.

Modify QScrollBar


In the eyes of Qt Style Sheets, the standard scrollbar consists of the following subelements:

Cynically transform this three-dimensional magnificence into a dull gray-gray strip, and send the buttons along with the arrows for the “Unnecessary 2012” award with the following lines:

QScrollBar {
     border: none;
     background: #494949;
     height: 6px;
     width: 6px;
     margin: 0px;
}
QScrollBar::handle {
     background: #DBDBDB;
     min-width: 20px;
     min-height: 20px;
}
 QScrollBar::add-line,  QScrollBar::sub-line {
     background: none;
     border: none;
}
 QScrollBar::add-page, QScrollBar::sub-page {
     background: none;
}
	

We get:



Modify QTabBar


Without further ado, we proceed to redo our living room tabs. Oh, and developers didn’t cheat on this widget:
  • Subelements: :: tear (tab delimiter) and :: scroller (scroll button)
  • A whole bunch of additional states of the tabs:: only-one,: first,: last,: middle,: previous - selected,: next-selected,: selected, the purposes of which I hope are clear from the names.
  • Pseudo-states: top,: left,: right,: bottom depending on the orientation of the panel.
  • Negative fields that can be used to create overlaps

There is a place for fantasy.
There is only one thing to remember, QTabBar is on QTabWidget, so you should change the background through the widget, and the properties of the tabs through the panel. But we are unpretentious people, besides, QMainWindow took care of the background, so we blur the thin inconspicuous tabs with lines:

QMainWindow, 
QAbstractItemView,  
QTreeView::branch, 
QTabBar::tab
{
...
QTabBar::tab:selected {
      font: bold;
     border-color: #9B9B9B;
     border-bottom-color: #C2C7CB; 
 }
QTabBar::tab:!selected {
     margin-top: 2px;
 }
	



Modify QHeaderView


For those who did not know, all of these table headers in Qt is QHeaderView. It has one subelement :: section which has the same states as QTabBar :: tab.

This time, I decided to step back from the tradition and make a gradient fill (yes, here it is possible). To do this, use the constructions qlineargradient, qradialgradient, qconicalgradient. Gradients are specified in the Object Bounding Mode. Imagine a rectangle in which a gradient is rendered, the upper left corner of which is at (0, 0), and the lower right corner is at (1, 1). The gradient parameters in this case are indicated as a fraction between 0 and 1. These values ​​are extrapolated to the real coordinates of the rectangle at run time. It is possible to set values ​​that lie outside the bounding box (for example, -0.6 or 1.8).
I used the following design:

QHeaderView::section {
     background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                       stop:0 #616161, stop: 0.5 #505050,
                                       stop: 0.6 #434343, stop:1 #656565);
     color: white;
     padding-left: 4px;
     border: 1px solid #6c6c6c;
}
	


That is what we sought.

We persuade stubborn socket


Only one small problem

remained : This renegade remained completely indifferent to our efforts, moreover, he remained indifferent even when we indicated the great-grandfather of QWidget as a selector. Despite this, I still went through different selectors. For the first time, I managed to penetrate it with selectors with QComboBox and QLabel:

QComboBox, QComboBox::drop-down {
     color: #EAEAEA;
     background: #232323; 
     font-size: 9pt;
     border: none;
     padding: 1px 18px 1px 3px;
     min-width: 6em;
 }
QLabel {
     border-style: solid;
     color: #EAEAEA;
     background: #232323; 
     font-size: 9pt;
}
	



Cons on the face. A little inexorable border-style border around the splinter, so also a heavy heredity leaked everywhere inappropriately.

Here, incidentally, drops of common sense appeared. Children, what is so thin at the top of the window with buttons in a row? Of course this is QToolBar!
We try:

QToolBar {
     border-style: solid;
     border-style: outset;
     color: #EAEAEA;
     background: #333333; 
     font-size: 9pt;
}



Bingo! All traces of a serious illness disappeared and the renegade obediently joined the general view.


Summary



stylesheet.css

TODO:


It would be more correct not to encode colors, but to take them from a palette that, at best, could be filled in according to the color scheme of the editor. In addition, it would be possible to arrange all this in the form of a correct addition and add your own settings page with a choice of style, and possibly an editor. Well, the most desirable thing is of course to lose weight in a comfortable but thick side panel. removing the text and accessing its design from our css file, but this requires a deeper intervention in the code and, in general, a completely different story.

Also popular now: