1 /*
2  * LmmsStyle.cpp - the graphical style used by LMMS to create a consistent
3  *				  interface
4  *
5  * Copyright (c) 2007-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6  *
7  * This file is part of LMMS - https://lmms.io
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this program (see COPYING); if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301 USA.
23  *
24  */
25 
26 
27 #include <QFile>
28 #include <QApplication>
29 #include <QFrame>
30 #include <QPainter>
31 #include <QPainterPath>
32 #include <QStyleFactory>
33 #include <QStyleOption>
34 
35 #include "LmmsStyle.h"
36 
37 QPalette * LmmsStyle::s_palette = NULL;
38 
getGradient(const QColor & _col,const QRectF & _rect)39 QLinearGradient getGradient( const QColor & _col, const QRectF & _rect )
40 {
41 	QLinearGradient g( _rect.topLeft(), _rect.bottomLeft() );
42 
43 	qreal hue = _col.hueF();
44 	qreal value = _col.valueF();
45 	qreal saturation = _col.saturationF();
46 
47 	QColor c = _col;
48 	c.setHsvF( hue, 0.42 * saturation, 0.98 * value ); // TODO: pattern: 1.08
49 	g.setColorAt( 0, c );
50 	c.setHsvF( hue, 0.58 * saturation, 0.95 * value ); // TODO: pattern: 1.05
51 	g.setColorAt( 0.25, c );
52 	c.setHsvF( hue, 0.70 * saturation, 0.93 * value ); // TODO: pattern: 1.03
53 	g.setColorAt( 0.5, c );
54 
55 	c.setHsvF( hue, 0.95 * saturation, 0.9 * value );
56 	g.setColorAt( 0.501, c );
57 	c.setHsvF( hue * 0.95, 0.95 * saturation, 0.95 * value );
58 	g.setColorAt( 0.75, c );
59 	c.setHsvF( hue * 0.90, 0.95 * saturation, 1 * value );
60 	g.setColorAt( 1.0, c );
61 
62 	return g;
63 }
64 
65 
66 
darken(const QLinearGradient & _gradient)67 QLinearGradient darken( const QLinearGradient & _gradient )
68 {
69 	QGradientStops stops = _gradient.stops();
70 	for (int i = 0; i < stops.size(); ++i) {
71 		QColor color = stops.at(i).second;
72 		stops[i].second = color.lighter(133);
73 	}
74 
75 	QLinearGradient g = _gradient;
76 	g.setStops(stops);
77 	return g;
78 }
79 
80 
81 
drawPath(QPainter * p,const QPainterPath & path,const QColor & col,const QColor & borderCol,bool dark=false)82 void drawPath( QPainter *p, const QPainterPath &path,
83 			   const QColor &col, const QColor &borderCol,
84 			   bool dark = false )
85 {
86 	const QRectF pathRect = path.boundingRect();
87 
88 	const QLinearGradient baseGradient = getGradient(col, pathRect);
89 	const QLinearGradient darkGradient = darken(baseGradient);
90 
91 	p->setOpacity(0.25);
92 
93 	// glow
94 	if (dark)
95 		p->strokePath(path, QPen(darkGradient, 4));
96 	else
97 		p->strokePath(path, QPen(baseGradient, 4));
98 
99 	p->setOpacity(1.0);
100 
101 	// fill
102 	if (dark)
103 		p->fillPath(path, darkGradient);
104 	else
105 		p->fillPath(path, baseGradient);
106 
107 	// TODO: Remove??
108 	/*
109 	QLinearGradient g(pathRect.topLeft(), pathRect.topRight());
110 	g.setCoordinateMode(QGradient::ObjectBoundingMode);
111 
112 	p->setOpacity(0.2);
113 	p->fillPath(path, g);*/
114 	// END: Remove??
115 
116 	p->setOpacity(0.5);
117 
118 	// highlight (bb)
119 	if (dark)
120 		p->strokePath(path, QPen(borderCol.lighter(133), 2));
121 	else
122 		p->strokePath(path, QPen(borderCol, 2));
123 }
124 
125 
126 
LmmsStyle()127 LmmsStyle::LmmsStyle() :
128 	QProxyStyle()
129 {
130 	QFile file( "resources:style.css" );
131 	file.open( QIODevice::ReadOnly );
132 	qApp->setStyleSheet( file.readAll() );
133 
134 	if( s_palette != NULL ) { qApp->setPalette( *s_palette ); }
135 
136 #if QT_VERSION >= 0x050000
137 	setBaseStyle( QStyleFactory::create( "Fusion" ) );
138 #else
139 	setBaseStyle( QStyleFactory::create( "Plastique" ) );
140 #endif
141 }
142 
143 
144 
145 
standardPalette(void) const146 QPalette LmmsStyle::standardPalette( void ) const
147 {
148 	if( s_palette != NULL) { return * s_palette; }
149 
150 	QPalette pal = QProxyStyle::standardPalette();
151 
152 	return( pal );
153 }
154 
155 
drawComplexControl(ComplexControl control,const QStyleOptionComplex * option,QPainter * painter,const QWidget * widget) const156 void LmmsStyle::drawComplexControl( ComplexControl control,
157 					const QStyleOptionComplex * option,
158 					QPainter *painter,
159 						const QWidget *widget ) const
160 {
161 	// fix broken titlebar styling on win32
162 	if( control == CC_TitleBar )
163 	{
164 		const QStyleOptionTitleBar * titleBar =
165 			qstyleoption_cast<const QStyleOptionTitleBar *>(option );
166 		if( titleBar )
167 		{
168 			QStyleOptionTitleBar so( *titleBar );
169 			so.palette = standardPalette();
170 			so.palette.setColor( QPalette::HighlightedText,
171 				( titleBar->titleBarState & State_Active ) ?
172 					QColor( 255, 255, 255 ) :
173 						QColor( 192, 192, 192 ) );
174 			so.palette.setColor( QPalette::Text,
175 							QColor( 64, 64, 64 ) );
176 			QProxyStyle::drawComplexControl( control, &so,
177 							painter, widget );
178 			return;
179 		}
180 	}
181 	else if (control == CC_MdiControls)
182 	{
183 		QStyleOptionComplex so(*option);
184 		so.palette.setColor(QPalette::Button, QColor(223, 228, 236));
185 		QProxyStyle::drawComplexControl(control, &so, painter, widget);
186 		return;
187 	}
188 /*	else if( control == CC_ScrollBar )
189 	{
190 		painter->fillRect( option->rect, QApplication::palette().color( QPalette::Active,
191 							QPalette::Background ) );
192 
193 	}*/
194 	QProxyStyle::drawComplexControl( control, option, painter, widget );
195 }
196 
197 
198 
199 
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const200 void LmmsStyle::drawPrimitive( PrimitiveElement element,
201 		const QStyleOption *option, QPainter *painter,
202 		const QWidget *widget) const
203 {
204 	if( element == QStyle::PE_Frame ||
205 			element == QStyle::PE_FrameLineEdit ||
206 			element == QStyle::PE_PanelLineEdit )
207 	{
208 		const QRect rect = option->rect;
209 
210 		QColor black = QColor( 0, 0, 0 );
211 		QColor shadow = option->palette.shadow().color();
212 		QColor highlight = option->palette.highlight().color();
213 
214 		int a100 = 165;
215 		int a75 = static_cast<int>( a100 * .75 );
216 		int a50 = static_cast<int>( a100 * .6 );
217 		int a25 = static_cast<int>( a100 * .33 );
218 
219 		QLine lines[4];
220 		QPoint points[4];
221 
222 		// black inside lines
223 		// 50%
224 		black.setAlpha(a100);
225 		painter->setPen(QPen(black, 0));
226 		lines[0] = QLine(rect.left() + 2, rect.top() + 1,
227 					rect.right() - 2, rect.top() + 1);
228 		lines[1] = QLine(rect.left() + 2, rect.bottom() - 1,
229 					rect.right() - 2, rect.bottom() - 1);
230 		lines[2] = QLine(rect.left() + 1, rect.top() + 2,
231 					rect.left() + 1, rect.bottom() - 2);
232 		lines[3] = QLine(rect.right() - 1, rect.top() + 2,
233 					rect.right() - 1, rect.bottom() - 2);
234 		painter->drawLines(lines, 4);
235 
236 		// black inside dots
237 		black.setAlpha(a50);
238 		painter->setPen(QPen(black, 0));
239 		points[0] = QPoint(rect.left() + 2, rect.top() + 2);
240 		points[1] = QPoint(rect.left() + 2, rect.bottom() - 2);
241 		points[2] = QPoint(rect.right() - 2, rect.top() + 2);
242 		points[3] = QPoint(rect.right() - 2, rect.bottom() - 2);
243 		painter->drawPoints(points, 4);
244 
245 
246 		// outside lines - shadow
247 		// 100%
248 		shadow.setAlpha(a75);
249 		painter->setPen(QPen(shadow, 0));
250 		lines[0] = QLine(rect.left() + 2, rect.top(),
251 						rect.right() - 2, rect.top());
252 		lines[1] = QLine(rect.left(), rect.top() + 2,
253 						rect.left(), rect.bottom() - 2);
254 		painter->drawLines(lines, 2);
255 
256 		// outside corner dots - shadow
257 		// 75%
258 		shadow.setAlpha(a50);
259 		painter->setPen(QPen(shadow, 0));
260 		points[0] = QPoint(rect.left() + 1, rect.top() + 1);
261 		points[1] = QPoint(rect.right() - 1, rect.top() + 1);
262 		painter->drawPoints(points, 2);
263 
264 		// outside end dots - shadow
265 		// 50%
266 		shadow.setAlpha(a25);
267 		painter->setPen(QPen(shadow, 0));
268 		points[0] = QPoint(rect.left() + 1, rect.top());
269 		points[1] = QPoint(rect.left(), rect.top() + 1);
270 		points[2] = QPoint(rect.right() - 1, rect.top());
271 		points[3] = QPoint(rect.left(), rect.bottom() - 1);
272 		painter->drawPoints(points, 4);
273 
274 
275 		// outside lines - highlight
276 		// 100%
277 		highlight.setAlpha(a75);
278 		painter->setPen(QPen(highlight, 0));
279 		lines[0] = QLine(rect.left() + 2, rect.bottom(),
280 					rect.right() - 2, rect.bottom());
281 		lines[1] = QLine(rect.right(), rect.top() + 2,
282 					rect.right(), rect.bottom() - 2);
283 		painter->drawLines(lines, 2);
284 
285 		// outside corner dots - highlight
286 		// 75%
287 		highlight.setAlpha(a50);
288 		painter->setPen(QPen(highlight, 0));
289 		points[0] = QPoint(rect.left() + 1, rect.bottom() - 1);
290 		points[1] = QPoint(rect.right() - 1, rect.bottom() - 1);
291 		painter->drawPoints(points, 2);
292 
293 		// outside end dots - highlight
294 		// 50%
295 		highlight.setAlpha(a25);
296 		painter->setPen(QPen(highlight, 0));
297 		points[0] = QPoint(rect.right() - 1, rect.bottom());
298 		points[1] = QPoint(rect.right(), rect.bottom() - 1);
299 		points[2] = QPoint(rect.left() + 1, rect.bottom());
300 		points[3] = QPoint(rect.right(), rect.top() + 1);
301 		painter->drawPoints(points, 4);
302 	}
303 	else
304 	{
305 		QProxyStyle::drawPrimitive( element, option, painter, widget );
306 	}
307 
308 }
309 
310 
pixelMetric(PixelMetric _metric,const QStyleOption * _option,const QWidget * _widget) const311 int LmmsStyle::pixelMetric( PixelMetric _metric, const QStyleOption * _option,
312 						const QWidget * _widget ) const
313 {
314 	switch( _metric )
315 	{
316 		case QStyle::PM_ButtonMargin:
317 			return 3;
318 
319 		case QStyle::PM_ButtonIconSize:
320 			return 20;
321 
322 		case QStyle::PM_ToolBarItemMargin:
323 			return 1;
324 
325 		case QStyle::PM_ToolBarItemSpacing:
326 			return 2;
327 
328 		case QStyle::PM_TitleBarHeight:
329 			return 24;
330 
331 		default:
332 			return QProxyStyle::pixelMetric( _metric, _option, _widget );
333 	}
334 }
335 
336 
colorizeXpm(const char * const * xpm,const QBrush & fill) const337 QImage LmmsStyle::colorizeXpm( const char * const * xpm, const QBrush& fill ) const
338 {
339 	QImage arrowXpm( xpm );
340 	QImage arrow( arrowXpm.size(), QImage::Format_ARGB32 );
341 	QPainter arrowPainter( &arrow );
342 	arrowPainter.fillRect( arrow.rect(), fill );
343 	arrowPainter.end();
344 	arrow.setAlphaChannel( arrowXpm );
345 
346 	return arrow;
347 }
348 
349 
hoverColors(bool sunken,bool hover,bool active,QColor & color,QColor & blend) const350 void LmmsStyle::hoverColors( bool sunken, bool hover, bool active, QColor& color, QColor& blend ) const
351 {
352 	if( active )
353 	{
354 		if( sunken )
355 		{
356 			color = QColor( 75, 75, 75 );
357 			blend = QColor( 65, 65, 65 );
358 		}
359 		else if( hover )
360 		{
361 			color = QColor( 100, 100, 100 );
362 			blend = QColor( 75, 75, 75 );
363 		}
364 		else
365 		{
366 			color = QColor( 21, 21, 21 );
367 			blend = QColor( 33, 33, 33 );
368 		}
369 	}
370 	else
371 	{
372 		color = QColor( 21, 21, 21 );
373 		blend = QColor( 33, 33, 33 );
374 	}
375 }
376