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

filelight

  • sources
  • kde-4.14
  • kdeutils
  • filelight
  • src
  • part
  • radialMap
labels.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 <QFont>
23 #include <QFontMetrics>
24 #include <QPainter>
25 
26 #include "part/Config.h"
27 #include "part/fileTree.h"
28 #include "radialMap.h"
29 #include "sincos.h"
30 #include "widget.h"
31 
32 
33 
34 namespace RadialMap
35 {
36 class Label
37 {
38 public:
39  Label(const RadialMap::Segment *s, int l) : segment(s), lvl(l), angle(segment->start() + (segment->length() / 2)) { }
40 
41  bool tooClose(const int otherAngle) const {
42  return (angle > otherAngle - LABEL_ANGLE_MARGIN && angle < otherAngle + LABEL_ANGLE_MARGIN);
43  }
44 
45  const RadialMap::Segment *segment;
46  const unsigned int lvl;
47  const int angle;
48 
49  int x1, y1, x2, y2, x3;
50  int tx, ty, tw, th;
51 
52  QString qs;
53 };
54 
55 int compareAndSortLabels(Label *item1, Label *item2)
56 {
57  //you add 1440 to work round the fact that later you want the circle split vertically
58  //and as it is you start at 3 o' clock. It's to do with rightPrevY, stops annoying bug
59 
60  int angle1 = (item1)->angle + 1440;
61  int angle2 = (item2)->angle + 1440;
62 
63  // Also sort by level
64  if (angle1 == angle2)
65  return (item1->lvl > item2->lvl);
66 
67  if (angle1 > 5760) angle1 -= 5760;
68  if (angle2 > 5760) angle2 -= 5760;
69 
70  return (angle1 < angle2);
71 
72 }
73 
74 void
75 RadialMap::Widget::paintExplodedLabels(QPainter &paint) const
76 {
77  //we are a friend of RadialMap::Map
78 
79  QList<Label*> list;
80  unsigned int startLevel = 0;
81 
82 
83  //1. Create list of labels sorted in the order they will be rendered
84 
85  if (m_focus && m_focus->file() != m_tree) //separate behavior for selected vs unselected segments
86  {
87  //don't bother with files
88  if (m_focus && m_focus->file() && !m_focus->file()->isFolder())
89  return;
90 
91  //find the range of levels we will be potentially drawing labels for
92  //startLevel is the level above whatever m_focus is in
93  for (const Folder *p = (const Folder*)m_focus->file(); p != m_tree; ++startLevel)
94  p = p->parent();
95 
96  //range=2 means 2 levels to draw labels for
97 
98  unsigned int start, end, minAngle;
99 
100  start = m_focus->start();
101  end = m_focus->end(); //boundary angles
102  minAngle = int(m_focus->length() * LABEL_MIN_ANGLE_FACTOR);
103 
104 
105 #define segment (*it)
106 #define ring (m_map.m_signature + i)
107 
108  //**** Levels should be on a scale starting with 0
109  //**** range is a useless parameter
110  //**** keep a topblock var which is the lowestLevel OR startLevel for identation purposes
111  for (unsigned int i = startLevel; i <= m_map.m_visibleDepth; ++i)
112  for (Iterator<Segment> it = ring->iterator(); it != ring->end(); ++it)
113  if (segment->start() >= start && segment->end() <= end)
114  if (segment->length() > minAngle) {
115  list.append(new Label(segment, i));
116  }
117 
118 #undef ring
119 #undef segment
120 
121  } else {
122 
123 #define ring m_map.m_signature
124 
125  for (Iterator<Segment> it = ring->iterator(); it != ring->end(); ++it)
126  if ((*it)->length() > 288) {
127  list.append(new Label((*it), 0));
128 
129  }
130 
131 #undef ring
132 
133  }
134  qSort(list.begin(), list.end(), compareAndSortLabels);
135 
136  //2. Check to see if any adjacent labels are too close together
137  // if so, remove it (the least significant labels, since we sort by level too).
138 
139  int pos = 0;
140  while (pos < list.size() - 1)
141  {
142  if (list[pos]->tooClose(list[pos+1]->angle))
143  delete list.takeAt(pos+1);
144  else
145  ++pos;
146  }
147 
148  //used in next two steps
149  bool varySizes;
150  //**** should perhaps use doubles
151  int *sizes = new int [ m_map.m_visibleDepth + 1 ]; //**** make sizes an array of floats I think instead (or doubles)
152 
153  // If the minimum is larger than the default it fucks up further down
154  if (paint.font().pointSize() < Config::minFontPitch) {
155  QFont font = paint.font();
156  font.setPointSize(Config::minFontPitch);
157  paint.setFont(font);
158  }
159 
160  QList<Label*>::iterator it;
161 
162  do
163  {
164  //3. Calculate font sizes
165 
166  {
167  //determine current range of levels to draw for
168  uint range = 0;
169 
170  for (it = list.begin(); it != list.end(); ++it)
171  {
172  uint lvl = (*it)->lvl;
173  if (lvl > range)
174  range = lvl;
175 
176  //**** better way would just be to assign if nothing is range
177  }
178 
179  range -= startLevel; //range 0 means 1 level of labels
180 
181  varySizes = Config::varyLabelFontSizes && (range != 0);
182 
183  if (varySizes)
184  {
185  //create an array of font sizes for various levels
186  //will exceed normal font pitch automatically if necessary, but not minPitch
187  //**** this needs to be checked lots
188 
189  //**** what if this is negative (min size gtr than default size)
190  uint step = (paint.font().pointSize() - Config::minFontPitch) / range;
191  if (step == 0)
192  step = 1;
193 
194  for (uint x = range + startLevel, y = Config::minFontPitch; x >= startLevel; y += step, --x)
195  sizes[x] = y;
196  }
197  }
198 
199  //4. determine label co-ordinates
200 
201  int x1, y1, x2, y2, x3, tx, ty; //coords
202  double sinra, cosra, ra; //angles
203 
204  int cx = m_map.width() / 2 + m_offset.x(); //centre relative to canvas
205  int cy = m_map.height() / 2 + m_offset.y();
206 
207  int spacer, preSpacer = int(m_map.m_ringBreadth * 0.5) + m_map.m_innerRadius;
208  int fullStrutLength = (m_map.width() - m_map.MAP_2MARGIN) / 2 + LABEL_MAP_SPACER; //full length of a strut from map center
209 
210  int prevLeftY = 0;
211  int prevRightY = height();
212 
213  bool rightSide;
214 
215  QFont font;
216 
217  for (it = list.begin(); it != list.end(); ++it)
218  {
219  //** bear in mind that text is drawn with QPoint param as BOTTOM left corner of text box
220  QString string = (*it)->segment->file()->name();
221  if (varySizes)
222  font.setPointSize(sizes[(*it)->lvl]);
223  QFontMetrics fontMetrics(font);
224  int fontHeight = fontMetrics.height(); //used to ensure label texts don't overlap
225  int lineSpacing = fontHeight / 4;
226 
227  fontHeight += LABEL_TEXT_VMARGIN;
228 
229  rightSide = ((*it)->angle < 1440 || (*it)->angle > 4320);
230 
231  ra = M_PI/2880 * (*it)->angle; //convert to radians
232  sincos(ra, &sinra, &cosra);
233 
234 
235  spacer = preSpacer + m_map.m_ringBreadth * (*it)->lvl;
236 
237  x1 = cx + (int)(cosra * spacer);
238  y1 = cy - (int)(sinra * spacer);
239  y2 = y1 - (int)(sinra * (fullStrutLength - spacer));
240 
241  if (rightSide) { //righthand side, going upwards
242  if (y2 > prevRightY /*- fmh*/) //then it is too low, needs to be drawn higher
243  y2 = prevRightY /*- fmh*/;
244  }
245  else //lefthand side, going downwards
246  if (y2 < prevLeftY/* + fmh*/) //then we're too high, need to be drawn lower
247  y2 = prevLeftY /*+ fmh*/;
248 
249  x2 = x1 - int(double(y2 - y1) / tan(ra));
250  ty = y2 + lineSpacing;
251 
252 
253  if (rightSide) {
254  if (x2 > width() || ty < fontHeight || x2 < x1) {
255  //skip this strut
256  //**** don't duplicate this code
257  list.erase(it); //will delete the label and set it to list.current() which _should_ be the next ptr
258  break;
259  }
260 
261  prevRightY = ty - fontHeight - lineSpacing; //must be after above's "continue"
262 
263  string = fontMetrics.elidedText(string, Qt::ElideMiddle, width() - x2);
264 
265  x3 = width() - fontMetrics.width(string)
266  - LABEL_HMARGIN //outer margin
267  - LABEL_TEXT_HMARGIN //margin between strut and text
268  //- ((*it)->lvl - startLevel) * LABEL_HMARGIN; //indentation
269  ;
270  if (x3 < x2) x3 = x2;
271  tx = x3 + LABEL_TEXT_HMARGIN;
272 
273  } else {
274 
275  if (x2 < 0 || ty > height() || x2 > x1)
276  {
277  //skip this strut
278  list.erase(it); //will delete the label and set it to list.current() which _should_ be the next ptr
279  break;
280  }
281 
282  prevLeftY = ty + fontHeight - lineSpacing;
283 
284  string = fontMetrics.elidedText(string, Qt::ElideMiddle, x2);
285 
286  //**** needs a little tweaking:
287 
288  tx = fontMetrics.width(string) + LABEL_HMARGIN/* + ((*it)->lvl - startLevel) * LABEL_HMARGIN*/;
289  if (tx > x2) { //text is too long
290  tx = LABEL_HMARGIN + x2 - tx; //some text will be lost from sight
291  x3 = x2; //no text margin (right side of text here)
292  } else {
293  x3 = tx + LABEL_TEXT_HMARGIN;
294  tx = LABEL_HMARGIN /*+ ((*it)->lvl - startLevel) * LABEL_HMARGIN*/;
295  }
296  }
297 
298  (*it)->x1 = x1;
299  (*it)->y1 = y1;
300  (*it)->x2 = x2;
301  (*it)->y2 = y2;
302  (*it)->x3 = x3;
303  (*it)->tx = tx;
304  (*it)->ty = ty;
305  (*it)->qs = string;
306  }
307 
308  //if an element is deleted at this stage, we need to do this whole
309  //iteration again, thus the following loop
310  //**** in rare case that deleted label was last label in top level
311  // and last in labelList too, this will not work as expected (not critical)
312 
313  } while (it != list.end());
314 
315 
316  //5. Render labels
317 
318  foreach (Label *label, list) {
319  if (varySizes) {
320  //**** how much overhead in making new QFont each time?
321  // (implicate sharing remember)
322  QFont font = paint.font();
323  font.setPointSize(sizes[label->lvl]);
324  paint.setFont(font);
325  }
326 
327  paint.drawEllipse(label->x1 - 3, label->y1 - 3, 6, 6); //**** CPU intensive! better to use a pixmap
328  paint.drawLine(label->x1, label->y1, label->x2, label->y2);
329  paint.drawLine(label->x2, label->y2, label->x3, label->y2);
330 
331  paint.drawText(label->tx, label->ty, label->qs);
332  }
333 
334  foreach(Label *label, list) {
335  delete label;
336  }
337  delete [] sizes;
338 }
339 }
340 
QFont::setPointSize
void setPointSize(int pointSize)
LABEL_HMARGIN
#define LABEL_HMARGIN
Definition: radialMap.h:103
LABEL_ANGLE_MARGIN
#define LABEL_ANGLE_MARGIN
Definition: radialMap.h:106
QPainter::font
const QFont & font() const
QFont
LABEL_MAP_SPACER
#define LABEL_MAP_SPACER
Definition: radialMap.h:102
QList::erase
iterator erase(iterator pos)
QList::takeAt
T takeAt(int i)
QFontMetrics
QPainter::drawLine
void drawLine(const QLineF &line)
Config.h
QList::size
int size() const
sincos.h
LABEL_TEXT_VMARGIN
#define LABEL_TEXT_VMARGIN
Definition: radialMap.h:105
radialMap.h
QPainter::setFont
void setFont(const QFont &font)
QList::append
void append(const T &value)
RadialMap::compareAndSortLabels
int compareAndSortLabels(Label *item1, Label *item2)
Definition: labels.cpp:55
Folder
Definition: fileTree.h:271
QPainter::drawEllipse
void drawEllipse(const QRectF &rectangle)
fileTree.h
QPainter
QPainter::drawText
void drawText(const QPointF &position, const QString &text)
QString
QList
QList::iterator
QList::end
iterator end()
widget.h
Iterator
Definition: fileTree.h:38
LABEL_MIN_ANGLE_FACTOR
#define LABEL_MIN_ANGLE_FACTOR
Definition: radialMap.h:107
M_PI
#define M_PI
Definition: radialMap.h:94
sincos
void sincos(double angleRadians, double *Sin, double *Cos)
LABEL_TEXT_HMARGIN
#define LABEL_TEXT_HMARGIN
Definition: radialMap.h:104
RadialMap::Segment
Definition: radialMap.h:31
ring
#define ring
length
static const int length[]
Definition: progressBox.cpp:99
segment
#define segment
QList::begin
iterator begin()
QFont::pointSize
int pointSize() const
Filelight::m_map
http QObject const QList< QVariant > m_map(0)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:42:32 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
  • ktimer
  • kwallet
  • 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