• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeutils API Reference
  • KDE Home
  • Contact Us
 

filelight

  • sources
  • kde-4.12
  • kdeutils
  • filelight
  • src
  • part
  • radialMap
map.cpp
Go to the documentation of this file.
1 /***********************************************************************
2 * Copyright 2003-2004 Max Howell <max.howell@methylblue.com>
3 * Copyright 2008-2009 Martin Sandsmark <martin.sandsmark@kde.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License or (at your option) version 3 or any later version
9 * accepted by the membership of KDE e.V. (or its successor approved
10 * by the membership of KDE e.V.), which shall act as a proxy
11 * defined in Section 14 of version 3 of the license.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ***********************************************************************/
21 
22 #include <QtGui/QApplication> //make()
23 #include <QtGui/QImage> //make() & paint()
24 #include <QtGui/QFont> //ctor
25 #include <QtGui/QFontMetrics> //ctor
26 #include <QtGui/QPainter>
27 
28 #include <KCursor> //make()
29 #include <KDebug>
30 #include <KGlobalSettings> //kdeColours
31 
32 #include "builder.h"
33 #include "part/Config.h"
34 #include "part/fileTree.h"
35 #define SINCOS_H_IMPLEMENTATION (1)
36 #include "sincos.h"
37 #include "widget.h"
38 
39 RadialMap::Map::Map(bool summary)
40  : m_signature(NULL)
41  , m_visibleDepth(DEFAULT_RING_DEPTH)
42  , m_ringBreadth(MIN_RING_BREADTH)
43  , m_innerRadius(0)
44  , m_summary(summary)
45 {
46 
47  //FIXME this is all broken. No longer is a maximum depth!
48  const int fmh = QFontMetrics(QFont()).height();
49  const int fmhD4 = fmh / 4;
50  MAP_2MARGIN = 2 * (fmh - (fmhD4 - LABEL_MAP_SPACER)); //margin is dependent on fitting in labels at top and bottom
51 }
52 
53 RadialMap::Map::~Map()
54 {
55  delete [] m_signature;
56 }
57 
58 void RadialMap::Map::invalidate()
59 {
60  delete [] m_signature;
61  m_signature = NULL;
62 
63  m_visibleDepth = Config::defaultRingDepth;
64 }
65 
66 void RadialMap::Map::make(const Folder *tree, bool refresh)
67 {
68  //slow operation so set the wait cursor
69  QApplication::setOverrideCursor(Qt::WaitCursor);
70 
71  {
72  //build a signature of visible components
73  delete [] m_signature;
74  Builder builder(this, tree, refresh);
75  }
76 
77  //colour the segments
78  colorise();
79 
80  m_centerText = tree->humanReadableSize();
81 
82  //paint the pixmap
83  paint();
84 
85  QApplication::restoreOverrideCursor();
86 }
87 
88 void RadialMap::Map::setRingBreadth()
89 {
90  //FIXME called too many times on creation
91 
92  m_ringBreadth = (height() - MAP_2MARGIN) / (2 * m_visibleDepth + 4);
93 
94  if (m_ringBreadth < MIN_RING_BREADTH)
95  m_ringBreadth = MIN_RING_BREADTH;
96 
97  else if (m_ringBreadth > MAX_RING_BREADTH)
98  m_ringBreadth = MAX_RING_BREADTH;
99 }
100 
101 bool RadialMap::Map::resize(const QRect &rect)
102 {
103  //there's a MAP_2MARGIN border
104 
105 #define mw width()
106 #define mh height()
107 #define cw rect.width()
108 #define ch rect.height()
109 
110  if (cw < mw || ch < mh || (cw > mw && ch > mh))
111  {
112  uint size = ((cw < ch) ? cw : ch) - MAP_2MARGIN;
113 
114  //this also causes uneven sizes to always resize when resizing but map is small in that dimension
115  //size -= size % 2; //even sizes mean less staggered non-antialiased resizing
116 
117  {
118  const uint minSize = MIN_RING_BREADTH * 2 * (m_visibleDepth + 2);
119 
120  if (size < minSize)
121  size = minSize;
122 
123  //this QRect is used by paint()
124  m_rect.setRect(0,0,size,size);
125  }
126  m_pixmap = QPixmap(m_rect.size());
127 
128  //resize the pixmap
129  size += MAP_2MARGIN;
130 
131  if (m_signature != NULL)
132  {
133  setRingBreadth();
134  paint();
135  }
136 
137  return true;
138  }
139 
140 #undef mw
141 #undef mh
142 #undef cw
143 #undef ch
144 
145  return false;
146 }
147 
148 void RadialMap::Map::colorise()
149 {
150  QColor cp, cb;
151  double darkness = 1;
152  double contrast = (double)Config::contrast / (double)100;
153  int h, s1, s2, v1, v2;
154 
155  QColor kdeColour[2] = { KGlobalSettings::inactiveTitleColor(), KGlobalSettings::activeTitleColor() };
156 
157  double deltaRed = (double)(kdeColour[0].red() - kdeColour[1].red()) / 2880; //2880 for semicircle
158  double deltaGreen = (double)(kdeColour[0].green() - kdeColour[1].green()) / 2880;
159  double deltaBlue = (double)(kdeColour[0].blue() - kdeColour[1].blue()) / 2880;
160 
161  for (uint i = 0; i <= m_visibleDepth; ++i, darkness += 0.04)
162  {
163  for (Iterator<Segment> it = m_signature[i].iterator(); it != m_signature[i].end(); ++it)
164  {
165  if (m_summary){ // Summary view has its own colors, special cased.
166  if ((*it)->file()->name() == QLatin1String("Used")) {
167  cb = QApplication::palette().highlight().color();
168  cb.getHsv(&h, &s1, &v1);
169 
170  if (s1 > 80)
171  s1 = 80;
172 
173  v2 = v1 - int(contrast * v1);
174  s2 = s1 + int(contrast * (255 - s1));
175 
176  cb.setHsv(h, s1, v1);
177  cp.setHsv(h, s2, v2);
178  }
179  else
180  {
181  cp = Qt::gray;
182  cb = Qt::white;
183  }
184 
185  (*it)->setPalette(cp, cb);
186  }
187  else
188  {
189  switch (Config::scheme)
190  {
191  case Filelight::KDE:
192  {
193  //gradient will work by figuring out rgb delta values for 360 degrees
194  //then each component is angle*delta
195 
196  int a = (*it)->start();
197 
198  if (a > 2880) a = 2880 - (a - 2880);
199 
200  h = (int)(deltaRed * a) + kdeColour[1].red();
201  s1 = (int)(deltaGreen * a) + kdeColour[1].green();
202  v1 = (int)(deltaBlue * a) + kdeColour[1].blue();
203 
204  cb.setRgb(h, s1, v1);
205  cb.getHsv(&h, &s1, &v1);
206 
207  break;
208  }
209 
210  case Filelight::HighContrast:
211  cp.setHsv(0, 0, 0); //values of h, s and v are irrelevant
212  cb.setHsv(180, 0, int(255.0 * contrast));
213  (*it)->setPalette(cp, cb);
214  continue;
215 
216  default:
217  h = int((*it)->start() / 16);
218  s1 = 160;
219  v1 = (int)(255.0 / darkness); //****doing this more often than once seems daft!
220  }
221 
222  v2 = v1 - int(contrast * v1);
223  s2 = s1 + int(contrast * (255 - s1));
224 
225  if (s1 < 80) s1 = 80; //can fall too low and makes contrast between the files hard to discern
226 
227  if ((*it)->isFake()) //multi-file
228  {
229  cb.setHsv(h, s2, (v2 < 90) ? 90 : v2); //too dark if < 100
230  cp.setHsv(h, 17, v1);
231  }
232  else if (!(*it)->file()->isFolder()) //file
233  {
234  cb.setHsv(h, 17, v1);
235  cp.setHsv(h, 17, v2);
236  }
237  else //folder
238  {
239  cb.setHsv(h, s1, v1); //v was 225
240  cp.setHsv(h, s2, v2); //v was 225 - delta
241  }
242 
243  (*it)->setPalette(cp, cb);
244 
245  //TODO:
246  //**** may be better to store KDE colours as H and S and vary V as others
247  //**** perhaps make saturation difference for s2 dependent on contrast too
248  //**** fake segments don't work with highContrast
249  //**** may work better with cp = cb rather than Qt::white
250  //**** you have to ensure the grey of files is sufficient, currently it works only with rainbow (perhaps use contrast there too)
251  //**** change v1,v2 to vp, vb etc.
252  //**** using percentages is not strictly correct as the eye doesn't work like that
253  //**** darkness factor is not done for kde_colour scheme, and also value for files is incorrect really for files in this scheme as it is not set like rainbow one is
254  }
255  }
256  }
257 }
258 
259 void RadialMap::Map::paint(bool antialias)
260 {
261  KColorScheme scheme(QPalette::Active, KColorScheme::View);
262 
263  QPainter paint;
264  QRect rect = m_rect;
265 
266  rect.adjust(5, 5, -5, -5);
267  m_pixmap.fill(scheme.background().color());
268 
269  //m_rect.moveRight(1); // Uncommenting this breaks repainting when recreating map from cache
270 
271 
272  //**** best option you can think of is to make the circles slightly less perfect,
273  // ** i.e. slightly eliptic when resizing inbetween
274 
275  if (m_pixmap.isNull())
276  return;
277 
278  if (!paint.begin(&m_pixmap)) {
279  kWarning() << "Failed to initialize painting, returning...";
280  return;
281  }
282 
283  if (antialias && Config::antialias) {
284  paint.translate(0.7, 0.7);
285  paint.setRenderHint(QPainter::Antialiasing);
286  }
287 
288  int step = m_ringBreadth;
289  int excess = -1;
290 
291  //do intelligent distribution of excess to prevent nasty resizing
292  if (m_ringBreadth != MAX_RING_BREADTH && m_ringBreadth != MIN_RING_BREADTH) {
293  excess = rect.width() % m_ringBreadth;
294  ++step;
295  }
296 
297 
298  for (int x = m_visibleDepth; x >= 0; --x)
299  {
300  int width = rect.width() / 2;
301  //clever geometric trick to find largest angle that will give biggest arrow head
302  uint a_max = int(acos((double)width / double((width + 5))) * (180*16 / M_PI));
303 
304  for (ConstIterator<Segment> it = m_signature[x].constIterator(); it != m_signature[x].end(); ++it)
305  {
306  //draw the pie segments, most of this code is concerned with drawing the little
307  //arrows on the ends of segments when they have hidden files
308 
309  paint.setPen((*it)->pen());
310 
311  if ((*it)->hasHiddenChildren())
312  {
313  //draw arrow head to indicate undisplayed files/directories
314  QPolygon pts(3);
315  QPoint pos, cpos = rect.center();
316  uint a[3] = { (*it)->start(), (*it)->length(), 0 };
317 
318  a[2] = a[0] + (a[1] / 2); //assign to halfway between
319  if (a[1] > a_max)
320  {
321  a[1] = a_max;
322  a[0] = a[2] - a_max / 2;
323  }
324 
325  a[1] += a[0];
326 
327  for (int i = 0, radius = width; i < 3; ++i)
328  {
329  double ra = M_PI/(180*16) * a[i], sinra, cosra;
330 
331  if (i == 2)
332  radius += 5;
333  sincos(ra, &sinra, &cosra);
334  pos.rx() = cpos.x() + static_cast<int>(cosra * radius);
335  pos.ry() = cpos.y() - static_cast<int>(sinra * radius);
336  pts.setPoint(i, pos);
337  }
338 
339  paint.setBrush((*it)->pen());
340  paint.drawPolygon(pts);
341  }
342 
343  paint.setBrush((*it)->brush());
344  paint.drawPie(rect, (*it)->start(), (*it)->length());
345 
346  if ((*it)->hasHiddenChildren())
347  {
348  //**** code is bloated!
349  paint.save();
350  QPen pen = paint.pen();
351  int width = 2;
352  pen.setWidth(width);
353  paint.setPen(pen);
354  QRect rect2 = rect;
355  width /= 2;
356  rect2.adjust(width, width, -width, -width);
357  paint.drawArc(rect2, (*it)->start(), (*it)->length());
358  paint.restore();
359  }
360  }
361 
362  if (excess >= 0) { //excess allows us to resize more smoothly (still crud tho)
363  if (excess < 2) //only decrease rect by more if even number of excesses left
364  --step;
365  excess -= 2;
366  }
367 
368  rect.adjust(step, step, -step, -step);
369  }
370 
371  // if(excess > 0) rect.addCoords(excess, excess, 0, 0); //ugly
372 
373  paint.setPen(scheme.foreground().color());
374  paint.setBrush(scheme.background().color());
375  paint.drawEllipse(rect);
376  paint.drawText(rect, Qt::AlignCenter, m_centerText);
377 
378  m_innerRadius = rect.width() / 2; //rect.width should be multiple of 2
379 
380  paint.end();
381 }
RadialMap::Map::Map
Map(bool summary)
Definition: map.cpp:39
Filelight::KDE
Definition: Config.h:31
mw
#define mw
LABEL_MAP_SPACER
#define LABEL_MAP_SPACER
Definition: radialMap.h:102
MAX_RING_BREADTH
#define MAX_RING_BREADTH
Definition: radialMap.h:98
Config.h
RadialMap::Builder
Definition: builder.h:37
Filelight::HighContrast
Definition: Config.h:31
sincos.h
File::humanReadableSize
QString humanReadableSize() const
Definition: fileTree.h:254
Folder
Definition: fileTree.h:271
fileTree.h
RadialMap::Map::resize
bool resize(const QRect &)
Definition: map.cpp:101
Filelight::m_summary
http QObject const QList< QVariant > m_summary(0)
widget.h
builder.h
Iterator
Definition: fileTree.h:38
MIN_RING_BREADTH
#define MIN_RING_BREADTH
Definition: radialMap.h:97
ch
#define ch
RadialMap::Map::make
void make(const Folder *, bool=false)
Definition: map.cpp:66
M_PI
#define M_PI
Definition: radialMap.h:94
DEFAULT_RING_DEPTH
#define DEFAULT_RING_DEPTH
Definition: radialMap.h:99
sincos
void sincos(double angleRadians, double *Sin, double *Cos)
ConstIterator
Definition: fileTree.h:39
mh
#define mh
cw
#define cw
RadialMap::Map::~Map
~Map()
Definition: map.cpp:53
RadialMap::Map::invalidate
void invalidate()
Definition: map.cpp:58
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:08:07 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

filelight

Skip menu "filelight"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeutils API Reference

Skip menu "kdeutils API Reference"
  • ark
  • filelight
  • kcalc
  • kcharselect
  • kdf
  • kfloppy
  • kgpg
  • kremotecontrol
  • ktimer
  • kwallet
  • superkaramba
  • sweeper

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal