1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#include "functiontooltipwidget.h"
18
19#include <QHBoxLayout>
20#include <QPushButton>
21
22FunctionTooltipWidget::FunctionTooltipWidget(QWidget *parent) :
23 QFrame(parent, Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus)
24{
25 setFocusPolicy(Qt::NoFocus);
26 mInfoLabel = new QLabel(this);
27 mInfoLabel->setWordWrap(true);
28 mInfoLabel->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
29 mTotalLabel = new QLabel(this);
30 mTotalLabel->setWordWrap(false);
31 mTotalLabel->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
32 mUpButton = new QToolButton(this);
33 mUpButton->setArrowType(Qt::UpArrow);
34 mUpButton->setFixedSize(16, 16);
35 mUpButton->setAutoRaise(true);
36 mDownButton = new QToolButton(this);
37 mDownButton->setArrowType(Qt::DownArrow);
38 mDownButton->setFixedSize(16, 16);
39 mDownButton->setAutoRaise(true);
40
41 this->setLayout(new QHBoxLayout());
42 layout()->setContentsMargins(0,0,0,0);
43 layout()->setSpacing(0);
44 layout()->addWidget(mUpButton);
45 layout()->addWidget(mTotalLabel);
46 layout()->addWidget(mDownButton);
47 layout()->addWidget(mInfoLabel);
48 connect(mUpButton,&QPushButton::clicked,
49 this,&FunctionTooltipWidget::previousTip);
50 connect(mDownButton,&QPushButton::clicked,
51 this,&FunctionTooltipWidget::nextTip);
52}
53
54void FunctionTooltipWidget::addTip(const QString &name, const QString& fullname,
55 const QString &returnType, const QString &args, const QString &noNameArgs)
56{
57 PFunctionInfo info = std::make_shared<FunctionInfo>();
58 info->name = name;
59 info->fullname = fullname;
60 info->returnType = returnType;
61 info->params = splitArgs(args);
62 info->nonameParams = splitArgs(noNameArgs);
63 mInfos.append(info);
64}
65
66void FunctionTooltipWidget::clearTips()
67{
68 mInfos.clear();
69 hide();
70}
71
72int FunctionTooltipWidget::tipCount()
73{
74 return mInfos.count();
75}
76
77int FunctionTooltipWidget::paramPos() const
78{
79 return mParamPos;
80}
81
82void FunctionTooltipWidget::setParamPos(int newParamPos)
83{
84 mParamPos = newParamPos;
85}
86
87void FunctionTooltipWidget::nextTip()
88{
89 if (mInfoIndex>=mInfos.length()-1) {
90 hide();
91 return;
92 }
93 if (mInfos.length()>0)
94 mInfoIndex = std::min(mInfoIndex+1,mInfos.length()-1);
95 updateTip();
96}
97
98void FunctionTooltipWidget::previousTip()
99{
100 if (mInfoIndex==0) {
101 hide();
102 return ;
103 }
104 if (mInfos.length()>0)
105 mInfoIndex = std::max(mInfoIndex-1,0);
106 updateTip();
107}
108
109void FunctionTooltipWidget::updateTip()
110{
111
112 mTotalLabel->setVisible(mInfos.length()>1);
113 mUpButton->setVisible(mInfos.length()>1);
114 mDownButton->setVisible(mInfos.length()>1);
115 mUpButton->setEnabled(mInfoIndex!=0);
116 mDownButton->setEnabled(mInfoIndex!=mInfos.length()-1);
117 if (mInfos.length()<=0)
118 return;
119 PFunctionInfo info = mInfos[mInfoIndex];
120 QString text = info->returnType+ " " + info->name;
121 if (info->params.length()==0) {
122 text += "()";
123 } else {
124 QStringList displayList;
125 for (int i=0;i<info->params.length();i++){
126 const QString& param = info->params[i];
127 if (mParamIndex == i) {
128 displayList.append(QString("<b>%1</b>").arg(param));
129 } else {
130 displayList.append(param);
131 }
132 }
133 text += "( "+displayList.join(", ") + ") ";
134 }
135 if (mInfos.length()>1) {
136 mTotalLabel->setText(QString("%1/%2").arg(mInfoIndex+1).arg(mInfos.length()));
137 }
138 int width = mInfoLabel->fontMetrics().horizontalAdvance(text);
139 if (width > 400) {
140 mInfoLabel->setMinimumWidth(410);
141 } else {
142 mInfoLabel->setMinimumWidth(width);
143 }
144 mInfoLabel->setText(text);
145}
146
147void FunctionTooltipWidget::guessFunction(int commas)
148{
149 if (mInfoIndex>=0 && mInfoIndex<mInfos.count()
150 && mInfos[mInfoIndex]->params.count()>commas)
151 return;
152 for (int i=0;i<mInfos.size();i++) {
153 if (mInfos[i]->params.count()>commas) {
154 mInfoIndex = i;
155 return;
156 }
157 }
158 mInfoIndex = 0;
159 return;
160}
161
162QStringList FunctionTooltipWidget::splitArgs(QString argStr)
163{
164 int i = 0;
165 // Split up argument string by ,
166 if (argStr.startsWith('(')) {
167 i = 1; // assume it starts with ( and ends with )
168 } else {
169 i = 0;
170 }
171 int paramStart = i;
172
173 QStringList result;
174 while (i < argStr.length()) {
175 if ((argStr[i] == ',')) {
176 // We've found "int* a" for example
177 QString s = argStr.mid(paramStart,i-paramStart);
178 result.append(s);
179 paramStart = i + 1; // step over ,
180 }
181 i++;
182 }
183 QString s = argStr.mid(paramStart,i-paramStart);
184 s=s.trimmed();
185 if (!s.isEmpty()) {
186 if (s.endsWith(')'))
187 s.truncate(s.length()-1);
188 result.append(s);
189 }
190 return result;
191}
192
193const QString &FunctionTooltipWidget::functionFullName() const
194{
195 return mFunctioFullName;
196}
197
198void FunctionTooltipWidget::setFunctioFullName(const QString &newFunctioFullName)
199{
200 mFunctioFullName = newFunctioFullName;
201}
202
203int FunctionTooltipWidget::paramIndex() const
204{
205 return mParamIndex;
206}
207
208void FunctionTooltipWidget::setParamIndex(int newParamIndex)
209{
210 mParamIndex = newParamIndex;
211 updateTip();
212}
213
214void FunctionTooltipWidget::closeEvent(QCloseEvent *)
215{
216
217}
218
219void FunctionTooltipWidget::showEvent(QShowEvent *)
220{
221 if (mInfoIndex<0 || mInfoIndex>= mInfos.count()) {
222 mInfoIndex = 0;
223 }
224 updateTip();
225}
226
227void FunctionTooltipWidget::hideEvent(QHideEvent *)
228{
229 mInfos.clear();
230 mFunctioFullName = "";
231}
232