summaryrefslogtreecommitdiff
path: root/test/radialmap/radialMap/widgetEvents.cpp
blob: 0dd980d41ec3d709e7923d8374c2c572c80661f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/***********************************************************************
* Copyright 2003-2004  Max Howell <max.howell@methylblue.com>
* Copyright 2008-2009  Martin Sandsmark <martin.sandsmark@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
***********************************************************************/

#include "fileTree.h"
#include "Config.h"
#include "radialMap.h"   //class Segment
#include "widget.h"

#include <QMenu>  //::mousePressEvent()
#include <QUrl>

#include <QApplication> //QApplication::setOverrideCursor()
#include <QClipboard>
#include <QPainter>
#include <QTimer>      //::resizeEvent()
#include <QDropEvent>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMouseEvent>
#include <QDragEnterEvent>
#include <QToolTip>
#include <QMimeData>

#include <cmath>         //::segmentAt()

void RadialMap::Widget::resizeEvent(QResizeEvent*)
{
    if (m_map.resize(rect()))
        m_timer.setSingleShot(true);
    m_timer.start(500); //will cause signature to rebuild for new size

    //always do these as they need to be initialised on creation
    m_offset.rx() = (width() - m_map.width()) / 2;
    m_offset.ry() = (height() - m_map.height()) / 2;
}

void RadialMap::Widget::paintEvent(QPaintEvent*)
{
    QPainter paint;
    paint.begin(this);

    if (!m_map.isNull())
        paint.drawPixmap(m_offset, m_map.pixmap());
    else
    {
        paint.drawText(rect(), 0, tr("We messed up, the user needs to initiate a rescan."));
        return;
    }

    //exploded labels
    if (!m_map.isNull() && !m_timer.isActive())
    {
        if (Config::antialias) {
            paint.setRenderHint(QPainter::Antialiasing);
            //make lines appear on pixel boundaries
            paint.translate(0.5, 0.5);
        }
        paintExplodedLabels(paint);
    }
}

const RadialMap::Segment* RadialMap::Widget::segmentAt(QPoint &e) const
{
    //determine which segment QPoint e is above

    e -= m_offset;

    if (!m_map.m_signature)
        return nullptr;

    if (e.x() <= m_map.width() && e.y() <= m_map.height())
    {
        //transform to cartesian coords
        e.rx() -= m_map.width() / 2; //should be an int
        e.ry()  = m_map.height() / 2 - e.y();

        double length = hypot(e.x(), e.y());

        if (length >= m_map.m_innerRadius) //not hovering over inner circle
        {
            uint depth  = ((int)length - m_map.m_innerRadius) / m_map.m_ringBreadth;

            if (depth <= m_map.m_visibleDepth) //**** do earlier since you can //** check not outside of range
            {
                //vector calculation, reduces to simple trigonometry
                //cos angle = (aibi + ajbj) / albl
                //ai = x, bi=1, aj=y, bj=0
                //cos angle = x / (length)

                uint a  = (uint)(acos((double)e.x() / length) * 916.736);  //916.7324722 = #radians in circle * 16

                //acos only understands 0-180 degrees
                if (e.y() < 0) a = 5760 - a;

                for (Segment *segment : m_map.m_signature[depth]) {
                    if (segment->intersects(a))
                        return segment;
                }
            }
        }
        else return m_rootSegment; //hovering over inner circle
    }

    return nullptr;
}

void RadialMap::Widget::mouseMoveEvent(QMouseEvent *e)
{
    //set m_focus to what we hover over, update UI if it's a new segment

    Segment const * const oldFocus = m_focus;
    QPoint p = e->pos();

    m_focus = segmentAt(p); //NOTE p is passed by non-const reference

    if (m_focus)
    {
        m_tooltip.move(e->globalX() + 20, e->globalY() + 20);
        if (m_focus != oldFocus) //if not same as last time
        {
            setCursor(Qt::PointingHandCursor);

            QString string;


                string = QObject::tr("Tooltip of file/folder, %1 is path, %2 is size")
                               .arg(m_focus->file()->displayPath())
                               .arg(m_focus->file()->humanReadableSize());

                if (m_focus->file()->isFolder()) {
                    int files = static_cast<const Folder*>(m_focus->file())->children();
                    const uint percent = uint((100 * files) / (double)m_tree->children());

                    string += QLatin1Char('\n');
                    if (percent > 0) {
                        string += QObject::tr("Tooltip of folder, %1 File (%2%)")
                                         .arg(files).arg(percent);
                    } else {
                        string += QObject::tr("Tooltip of folder, %1 File")
                                         .arg(files);
                    }
                }


            // Calculate a semi-sane size for the tooltip
            QFontMetrics fontMetrics(font());
            int tooltipWidth = 0;
            int tooltipHeight = 0;
            for (const QString &part : string.split(QLatin1Char('\n'))) {
                tooltipHeight += fontMetrics.height();
                tooltipWidth = qMax(tooltipWidth, fontMetrics.width(part));
            }
            // Limit it to the window size, probably should find something better
            tooltipWidth = qMin(tooltipWidth, window()->width());
            tooltipWidth += 10;
            tooltipHeight += 10;
            m_tooltip.resize(tooltipWidth, tooltipHeight);
            m_tooltip.setText(string);
            m_tooltip.show();

            emit mouseHover(m_focus->file()->displayPath());
            update();
        }
    }
    else if (oldFocus && oldFocus->file() != m_tree)
    {
        m_tooltip.hide();
        unsetCursor();
        update();

        emit mouseHover(QString());
    }
}

void RadialMap::Widget::enterEvent(QEvent *)
{
    if (!m_focus) return;

    setCursor(Qt::PointingHandCursor);
    emit mouseHover(m_focus->file()->displayPath());
    update();
}

void RadialMap::Widget::leaveEvent(QEvent *)
{
    m_tooltip.hide();
}

void RadialMap::Widget::changeEvent(QEvent *e)
{
    if (e->type() == QEvent::ApplicationPaletteChange ||
        e->type() == QEvent::PaletteChange)
        m_map.paint();
}