1 /*
2  * Frequency controller widget (originally from CuteSDR)
3  *
4  * This file is part of gqrx sdr.
5  *
6  * Copyright 2010 Moe Wheatley AE4JY
7  * Copyright 2012-2017 Alexandru Csete OZ9AEC
8  * All rights reserved.
9  *
10  * This software is released under the "Simplified BSD License".
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include <QDebug>
35 #include "freqctrl.h"
36 
37 // Manual adjustment of Font size as percent of control height
38 #define DIGIT_SIZE_PERCENT 90
39 #define UNITS_SIZE_PERCENT 60
40 
41 // adjustment for separation between digits
42 #define SEPRATIO_N 100         // separation rectangle size ratio numerator times 100
43 #define SEPRATIO_D 3           // separation rectangle size ratio denominator
44 
45 #define STATUS_TIP \
46     "Scroll or left-click to increase/decrease digit. " \
47     "Right-click to clear digits."
48 
CFreqCtrl(QWidget * parent)49 CFreqCtrl::CFreqCtrl(QWidget *parent) :
50     QFrame(parent)
51 {
52     setAutoFillBackground(false);
53     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
54     setFocusPolicy(Qt::StrongFocus);
55     setMouseTracking(true);
56     m_BkColor = QColor(0x1F, 0x1D, 0x1D, 0xFF);
57     m_InactiveColor = QColor(0x43, 0x43, 0x43, 0xFF);
58     m_DigitColor = QColor(0xFF, 0xFF, 0xFF, 0xFF);
59     m_HighlightColor = QColor(0x5A, 0x5A, 0x5A, 0xFF);
60     m_UnitsColor = Qt::gray;
61     m_freq = 146123456;
62     setup(0, 1, 4000000000U, 1, FCTL_UNIT_NONE);
63     m_Oldfreq = 0;
64     m_LastLeadZeroPos = 0;
65     m_LRMouseFreqSel = false;
66     m_ActiveEditDigit = -1;
67     m_ResetLowerDigits = true;
68     m_InvertScrolling = false;
69     m_UnitsFont = QFont("Arial", 12, QFont::Normal);
70     m_DigitFont = QFont("Arial", 12, QFont::Normal);
71 
72     setStatusTip(tr(STATUS_TIP));
73 }
74 
~CFreqCtrl()75 CFreqCtrl::~CFreqCtrl()
76 {
77 }
78 
minimumSizeHint() const79 QSize CFreqCtrl::minimumSizeHint() const
80 {
81     return QSize(100, 20);
82 }
83 
sizeHint() const84 QSize CFreqCtrl::sizeHint() const
85 {
86     return QSize(100, 20);
87 }
88 
inRect(QRect & rect,QPoint & point)89 bool CFreqCtrl::inRect(QRect &rect, QPoint &point)
90 {
91     if ((point.x() < rect.right()) && (point.x() > rect.x()) &&
92         (point.y() < rect.bottom()) && (point.y() > rect.y()))
93         return true;
94     else
95         return false;
96 }
97 
fmax_to_numdigits(qint64 fmax)98 static int fmax_to_numdigits(qint64 fmax)
99 {
100     if (fmax < 10e6)
101         return 7;
102     else if (fmax < 100e6)
103         return 8;
104     else if (fmax < 1e9)
105         return 9;
106     else if (fmax < 10e9)
107         return 10;
108     else if (fmax < 100e9)
109         return 11;
110 
111     return 12;
112 }
113 
setup(int NumDigits,qint64 Minf,qint64 Maxf,int MinStep,FctlUnit unit)114 void CFreqCtrl::setup(int NumDigits, qint64 Minf, qint64 Maxf, int MinStep,
115                      FctlUnit unit)
116 {
117     int       i;
118     qint64    pwr = 1;
119     m_LastEditDigit = 0;
120     m_Oldfreq = -1;
121 
122     m_NumDigits = NumDigits ? NumDigits : fmax_to_numdigits(Maxf);
123 
124     if (m_NumDigits > FCTL_MAX_DIGITS)
125         m_NumDigits = FCTL_MAX_DIGITS;
126 
127     if (m_NumDigits < FCTL_MIN_DIGITS)
128         m_NumDigits = FCTL_MIN_DIGITS;
129 
130     m_UnitString = "";
131     m_MinStep = MinStep;
132 
133     if (m_MinStep == 0)
134         m_MinStep = 1;
135 
136     m_MinFreq = Minf;
137     m_MaxFreq = Maxf;
138 
139     if (m_freq < m_MinFreq)
140         m_freq = m_MinFreq;
141 
142     if (m_freq > m_MaxFreq)
143         m_freq = m_MaxFreq;
144 
145     for (i = 0; i < m_NumDigits; i++)
146     {
147         m_DigitInfo[i].weight = pwr;
148         m_DigitInfo[i].incval = pwr;
149         m_DigitInfo[i].modified = true;
150         m_DigitInfo[i].editmode = false;
151         m_DigitInfo[i].val = 0;
152         pwr *= 10;
153     }
154 
155     if (m_MaxFreq > pwr)
156         m_MaxFreq = pwr - 1;
157 
158     m_MaxFreq = m_MaxFreq - m_MaxFreq % m_MinStep;
159 
160     if (m_MinFreq > pwr)
161         m_MinFreq = 1;
162 
163     m_MinFreq = m_MinFreq - m_MinFreq % m_MinStep;
164     m_DigStart = 0;
165 
166     setUnit(unit);
167 
168     for (i = m_NumDigits - 1; i >= 0; i--)
169     {
170         if (m_DigitInfo[i].weight <= m_MinStep)
171         {
172             if (m_DigStart == 0)
173             {
174                 m_DigitInfo[i].incval = m_MinStep;
175                 m_DigStart = i;
176             }
177             else
178             {
179                 if ((m_MinStep % m_DigitInfo[i + 1].weight) != 0)
180                     m_DigStart = i;
181                 m_DigitInfo[i].incval = 0;
182             }
183         }
184     }
185 
186     m_NumSeps = (m_NumDigits - 1) / 3 - m_DigStart / 3;
187 }
188 
setFrequency(qint64 freq)189 void CFreqCtrl::setFrequency(qint64 freq)
190 {
191     int       i;
192     qint64    acc = 0;
193     qint64    rem;
194     int       val;
195 
196     if (freq == m_Oldfreq)
197         return;
198 
199     if (freq < m_MinFreq)
200         freq = m_MinFreq;
201 
202     if (freq > m_MaxFreq)
203         freq = m_MaxFreq;
204 
205     m_freq = freq - freq % m_MinStep;
206     rem = m_freq;
207     m_LeadZeroPos = m_NumDigits;
208 
209     for (i = m_NumDigits - 1; i >= m_DigStart; i--)
210     {
211         val = (int)(rem / m_DigitInfo[i].weight);
212         if (m_DigitInfo[i].val != val)
213         {
214             m_DigitInfo[i].val = val;
215             m_DigitInfo[i].modified = true;
216         }
217         rem = rem - val * m_DigitInfo[i].weight;
218         acc += val;
219         if ((acc == 0) && (i > m_DecPos))
220         {
221             m_LeadZeroPos = i;
222         }
223     }
224 
225     // If the sign changed and the frequency is less than 1 unit,
226     // redraw the leading zero to get the correct sign.
227     if ((m_Oldfreq ^ m_freq) < 0 && m_DigitInfo[m_LeadZeroPos - 1].val == 0)
228         m_DigitInfo[m_LeadZeroPos - 1].modified = true;
229 
230     // When frequency is negative all non-zero digits that
231     // have changed will have a negative sign. This loop will
232     // change all digits back to positive, except the one at
233     // position m_leadZeroPos-1. If that position is zero,
234     // it will be checked in the drawing method, drawDigits().
235     /** TBC if this works for all configurations */
236     if (m_freq < 0)
237     {
238         if (m_DigitInfo[m_LeadZeroPos - 1].val > 0)
239             m_DigitInfo[m_LeadZeroPos -
240                         1].val = -m_DigitInfo[m_LeadZeroPos - 1].val;
241 
242         for (i = 0; i < (m_LeadZeroPos - 1); i++)
243         {
244             if (m_DigitInfo[i].val < 0)
245                 m_DigitInfo[i].val = -m_DigitInfo[i].val;
246         }
247     }
248 
249     // signal the new frequency to world
250     m_Oldfreq = m_freq;
251     emit    newFrequency(m_freq);
252     updateCtrl(m_LastLeadZeroPos != m_LeadZeroPos);
253     m_LastLeadZeroPos = m_LeadZeroPos;
254 }
255 
setDigitColor(QColor col)256 void CFreqCtrl::setDigitColor(QColor col)
257 {
258     m_UpdateAll = true;
259     m_DigitColor = col;
260     for (int i = m_DigStart; i < m_NumDigits; i++)
261         m_DigitInfo[i].modified = true;
262     updateCtrl(true);
263 }
264 
setUnit(FctlUnit unit)265 void CFreqCtrl::setUnit(FctlUnit unit)
266 {
267     m_NumDigitsForUnit = 2;
268     switch (unit)
269     {
270     case FCTL_UNIT_NONE:
271         m_NumDigitsForUnit = 0;
272         m_DecPos = 0;
273         m_UnitString = QString();
274         break;
275     case FCTL_UNIT_HZ:
276         m_DecPos = 0;
277         m_UnitString = "Hz ";
278         break;
279     case FCTL_UNIT_KHZ:
280         m_DecPos = 3;
281         m_UnitString = "kHz";
282         break;
283     case FCTL_UNIT_MHZ:
284         m_DecPos = 6;
285         m_UnitString = "MHz";
286         break;
287     case FCTL_UNIT_GHZ:
288         m_DecPos = 9;
289         m_UnitString = "GHz";
290         break;
291     case FCTL_UNIT_SEC:
292         m_DecPos = 6;
293         m_UnitString = "Sec";
294         break;
295     case FCTL_UNIT_MSEC:
296         m_DecPos = 3;
297         m_UnitString = "mS ";
298         break;
299     case FCTL_UNIT_USEC:
300         m_DecPos = 0;
301         m_UnitString = "uS ";
302         break;
303     case FCTL_UNIT_NSEC:
304         m_DecPos = 0;
305         m_UnitString = "nS ";
306         break;
307     }
308     m_Unit = unit;
309     m_UpdateAll = true;
310     updateCtrl(true);
311 }
312 
setBgColor(QColor col)313 void CFreqCtrl::setBgColor(QColor col)
314 {
315     m_UpdateAll = true;
316     m_BkColor = col;
317 
318     for (int i = m_DigStart; i < m_NumDigits; i++)
319         m_DigitInfo[i].modified = true;
320 
321     updateCtrl(true);
322 }
323 
setUnitsColor(QColor col)324 void CFreqCtrl::setUnitsColor(QColor col)
325 {
326     m_UpdateAll = true;
327     m_UnitsColor = col;
328     updateCtrl(true);
329 }
330 
setHighlightColor(QColor col)331 void CFreqCtrl::setHighlightColor(QColor col)
332 {
333     m_UpdateAll = true;
334     m_HighlightColor = col;
335     updateCtrl(true);
336 }
337 
updateCtrl(bool all)338 void CFreqCtrl::updateCtrl(bool all)
339 {
340     if (all)
341     {
342         m_UpdateAll = true;
343         for (int i = m_DigStart; i < m_NumDigits; i++)
344             m_DigitInfo[i].modified = true;
345     }
346     update();
347 }
348 
resizeEvent(QResizeEvent *)349 void CFreqCtrl::resizeEvent(QResizeEvent *)
350 {
351 // qDebug() <<rect.width() << rect.height();
352     int dpr = devicePixelRatio();
353     m_Pixmap = QPixmap(width() * dpr, height() * dpr); // resize pixmap to current control size
354     m_Pixmap.setDevicePixelRatio(dpr);
355     m_Pixmap.fill(m_BkColor);
356     m_UpdateAll = true;
357     updateCtrl(true);
358 }
359 
leaveEvent(QEvent *)360 void CFreqCtrl::leaveEvent(QEvent *)
361 {
362     // called when mouse cursor leaves this control so deactivate any highlights
363     if (m_ActiveEditDigit >= 0)
364     {
365         if (m_DigitInfo[m_ActiveEditDigit].editmode)
366         {
367             m_DigitInfo[m_ActiveEditDigit].editmode = false;
368             m_DigitInfo[m_ActiveEditDigit].modified = true;
369             m_ActiveEditDigit = -1;
370             updateCtrl(false);
371         }
372     }
373 }
374 
paintEvent(QPaintEvent *)375 void CFreqCtrl::paintEvent(QPaintEvent *)
376 {
377     QPainter    painter(&m_Pixmap);
378 
379     if (m_UpdateAll)           // if need to redraw everything
380     {
381         drawBkGround(painter);
382         m_UpdateAll = false;
383     }
384     // draw any modified digits to the m_MemDC
385     drawDigits(painter);
386     // now draw pixmap onto screen
387     QPainter    scrnpainter(this);
388     scrnpainter.drawPixmap(0, 0, m_Pixmap); // blt to the screen(flickers like a candle, why?)
389 }
390 
mouseMoveEvent(QMouseEvent * event)391 void CFreqCtrl::mouseMoveEvent(QMouseEvent *event)
392 {
393     QPoint    pt = event->pos();
394     // find which digit is to be edited
395     if (isActiveWindow())
396     {
397         if (!hasFocus())
398             setFocus(Qt::MouseFocusReason);
399 
400         for (int i = m_DigStart; i < m_NumDigits; i++)
401         {
402             if (inRect(m_DigitInfo[i].dQRect, pt))
403             {
404                 if (!m_DigitInfo[i].editmode)
405                 {
406                     m_DigitInfo[i].editmode = true;
407                     m_ActiveEditDigit = i;
408                 }
409             }
410             else
411             {
412                 // un-highlight the previous digit if moved off it
413                 if (m_DigitInfo[i].editmode)
414                 {
415                     m_DigitInfo[i].editmode = false;
416                     m_DigitInfo[i].modified = true;
417                 }
418             }
419         }
420 
421         updateCtrl(false);
422     }
423 }
424 
mousePressEvent(QMouseEvent * event)425 void CFreqCtrl::mousePressEvent(QMouseEvent *event)
426 {
427     QPoint    pt = event->pos();
428     if (event->button() == Qt::LeftButton)
429     {
430         for (int i = m_DigStart; i < m_NumDigits; i++)
431         {
432             if (inRect(m_DigitInfo[i].dQRect, pt)) // if in i'th digit
433             {
434                 if (m_LRMouseFreqSel)
435                 {
436                     incFreq();
437                 }
438                 else
439                 {
440                     if (pt.y() < m_DigitInfo[i].dQRect.bottom() / 2) // top half?
441                         incFreq();
442                     else
443                         decFreq();                                   // bottom half
444                 }
445             }
446         }
447     }
448     else if (event->button() == Qt::RightButton)
449     {
450         for (int i = m_DigStart; i < m_NumDigits; i++)
451         {
452             if (inRect(m_DigitInfo[i].dQRect, pt)) // if in i'th digit
453             {
454                 if (m_LRMouseFreqSel)
455                 {
456                     decFreq();
457                 }
458                 else
459                 {
460                     clearFreq();
461                 }
462             }
463         }
464     }
465 }
466 
wheelEvent(QWheelEvent * event)467 void CFreqCtrl::wheelEvent(QWheelEvent *event)
468 {
469     QPoint    pt = event->pos();
470     int       delta = m_InvertScrolling ? -event->angleDelta().y() : event->angleDelta().y();
471     int       numDegrees = delta / 8;
472     int       numSteps = numDegrees / 15;
473 
474     for (int i = m_DigStart; i < m_NumDigits; i++)
475     {
476         if (inRect(m_DigitInfo[i].dQRect, pt)) // if in i'th digit
477         {
478             if (numSteps > 0)
479                 incFreq();
480             else if (numSteps < 0)
481                 decFreq();
482         }
483     }
484 }
485 
keyPressEvent(QKeyEvent * event)486 void CFreqCtrl::keyPressEvent(QKeyEvent *event)
487 {
488     // call base class if dont over ride key
489     bool      fSkipMsg = false;
490     qint64    tmp;
491 
492     // qDebug() <<event->key();
493 
494     switch (event->key())
495     {
496     case Qt::Key_0:
497     case Qt::Key_1:
498     case Qt::Key_2:
499     case Qt::Key_3:
500     case Qt::Key_4:
501     case Qt::Key_5:
502     case Qt::Key_6:
503     case Qt::Key_7:
504     case Qt::Key_8:
505     case Qt::Key_9:
506         if (m_ActiveEditDigit >= 0)
507         {
508             if (m_DigitInfo[m_ActiveEditDigit].editmode)
509             {
510                 tmp = (m_freq / m_DigitInfo[m_ActiveEditDigit].weight) % 10;
511                 m_freq -= tmp * m_DigitInfo[m_ActiveEditDigit].weight;
512                 m_freq = m_freq + (event->key() - '0') *
513                          m_DigitInfo[m_ActiveEditDigit].weight;
514                 setFrequency(m_freq);
515             }
516         }
517         moveCursorRight();
518         fSkipMsg = true;
519         break;
520     case Qt::Key_Backspace:
521     case Qt::Key_Left:
522         if (m_ActiveEditDigit != -1)
523         {
524             moveCursorLeft();
525             fSkipMsg = true;
526         }
527         break;
528     case Qt::Key_Up:
529         if (m_ActiveEditDigit != -1)
530         {
531             incFreq();
532             fSkipMsg = true;
533         }
534         break;
535     case Qt::Key_Down:
536         if (m_ActiveEditDigit != -1)
537         {
538             decFreq();
539             fSkipMsg = true;
540         }
541         break;
542     case Qt::Key_Right:
543         if (m_ActiveEditDigit != -1)
544         {
545             moveCursorRight();
546             fSkipMsg = true;
547         }
548         break;
549     case Qt::Key_Home:
550         cursorHome();
551         fSkipMsg = true;
552         break;
553     case Qt::Key_End:
554         cursorEnd();
555         fSkipMsg = true;
556         break;
557     default:
558         break;
559     }
560     if (!fSkipMsg)
561         QFrame::keyPressEvent(event);
562 }
563 
drawBkGround(QPainter & Painter)564 void CFreqCtrl::drawBkGround(QPainter &Painter)
565 {
566     QRect    rect(0, 0, width(), height());
567 
568     // qDebug() <<rect;
569     int    cellwidth = 100 * rect.width() /
570                        (100 * (m_NumDigits + m_NumDigitsForUnit) +
571                         (m_NumSeps * SEPRATIO_N) / SEPRATIO_D);
572     int    sepwidth = (SEPRATIO_N * cellwidth) / (100 * SEPRATIO_D);
573     // qDebug() <<cellwidth <<sepwidth;
574 
575     // draw unit text
576     if (m_Unit != FCTL_UNIT_NONE)
577     {
578         m_UnitsRect.setRect(rect.right() - 2 * cellwidth, rect.top(),
579                             2 * cellwidth, rect.height());
580         Painter.fillRect(m_UnitsRect, m_BkColor); // FIXME: not necessary?
581         m_UnitsFont.setPixelSize((UNITS_SIZE_PERCENT * rect.height()) / 100);
582         m_UnitsFont.setFamily("Arial");
583         Painter.setFont(m_UnitsFont);
584         Painter.setPen(m_UnitsColor);
585         Painter.drawText(m_UnitsRect, Qt::AlignHCenter | Qt::AlignVCenter,
586                          m_UnitString);
587     }
588 
589     // draw digits
590     m_DigitFont.setPixelSize((DIGIT_SIZE_PERCENT * rect.height()) / 100);
591     m_DigitFont.setFamily("Arial");
592     Painter.setFont(m_DigitFont);
593     Painter.setPen(m_DigitColor);
594 
595     char    dgsep = ' ';       // digit group separator
596     int     digpos = rect.right() - m_NumDigitsForUnit * cellwidth - 1; // starting digit x position
597     for (int i = m_DigStart; i < m_NumDigits; i++)
598     {
599         if ((i > m_DigStart) && ((i % 3) == 0))
600         {
601             m_SepRect[i].setCoords(digpos - sepwidth,
602                                    rect.top(),
603                                    digpos,
604                                    rect.bottom());
605             Painter.fillRect(m_SepRect[i], m_BkColor);
606             digpos -= sepwidth;
607             if (m_Unit == FCTL_UNIT_NONE)
608             {
609                 if (m_LeadZeroPos > i)
610                     dgsep = '.';
611                 else
612                     dgsep = ' ';
613             }
614             else
615             {
616                 if (i == m_DecPos)
617                     dgsep = '.';
618                 else
619                     dgsep = ' ';
620             }
621             Painter.drawText(m_SepRect[i], Qt::AlignHCenter | Qt::AlignVCenter,
622                              QChar(dgsep));
623         }
624         else
625         {
626             m_SepRect[i].setCoords(0, 0, 0, 0);
627         }
628         m_DigitInfo[i].dQRect.setCoords(digpos - cellwidth, rect.top(),
629                                         digpos, rect.bottom());
630         digpos -= cellwidth;
631     }
632 }
633 
634 //  Draws just the Digits that have been modified
drawDigits(QPainter & Painter)635 void CFreqCtrl::drawDigits(QPainter &Painter)
636 {
637     Painter.setFont(m_DigitFont);
638     m_FirstEditableDigit = m_DigStart;
639 
640     for (int i = m_DigStart; i < m_NumDigits; i++)
641     {
642         if (m_DigitInfo[i].incval == 0)
643             m_FirstEditableDigit++;
644 
645         if (m_DigitInfo[i].modified || m_DigitInfo[i].editmode)
646         {
647             if (m_DigitInfo[i].editmode && m_DigitInfo[i].incval != 0)
648                 Painter.fillRect(m_DigitInfo[i].dQRect, m_HighlightColor);
649             else
650                 Painter.fillRect(m_DigitInfo[i].dQRect, m_BkColor);
651 
652             if (i >= m_LeadZeroPos)
653                 Painter.setPen(m_InactiveColor);
654             else
655                 Painter.setPen(m_DigitColor);
656 
657             if (m_freq < 0 && i == m_LeadZeroPos - 1 && m_DigitInfo[i].val == 0)
658                 Painter.drawText(m_DigitInfo[i].dQRect,
659                                  Qt::AlignHCenter | Qt::AlignVCenter,
660                                  QString("-0"));
661             else
662                 Painter.drawText(m_DigitInfo[i].dQRect,
663                                  Qt::AlignHCenter | Qt::AlignVCenter,
664                                  QString().number(m_DigitInfo[i].val));
665             m_DigitInfo[i].modified = false;
666         }
667     }
668 }
669 
670 // Increment just the digit active in edit mode
incDigit()671 void CFreqCtrl::incDigit()
672 {
673     /** FIXME: no longer used? */
674     int       tmp;
675     qint64    tmpl;
676 
677     if (m_ActiveEditDigit >= 0)
678     {
679         if (m_DigitInfo[m_ActiveEditDigit].editmode)
680         {
681             if (m_DigitInfo[m_ActiveEditDigit].weight ==
682                 m_DigitInfo[m_ActiveEditDigit].incval)
683             {
684                 // get the current digit value
685                 tmp =
686                     (int)((m_freq / m_DigitInfo[m_ActiveEditDigit].weight) %
687                           10);
688                 // set the current digit value to zero
689                 m_freq -= tmp * m_DigitInfo[m_ActiveEditDigit].weight;
690                 tmp++;
691                 if (tmp > 9)
692                     tmp = 0;
693                 m_freq = m_freq + (qint64)tmp *
694                          m_DigitInfo[m_ActiveEditDigit].weight;
695             }
696             else
697             {
698                 tmp =
699                     (int)((m_freq / m_DigitInfo[m_ActiveEditDigit + 1].weight) %
700                           10);
701                 tmpl = m_freq + m_DigitInfo[m_ActiveEditDigit].incval;
702                 if (tmp !=
703                     (int)((tmpl / m_DigitInfo[m_ActiveEditDigit + 1].weight) %
704                           10))
705                 {
706                     tmpl -= m_DigitInfo[m_ActiveEditDigit + 1].weight;
707                 }
708                 m_freq = tmpl;
709             }
710             setFrequency(m_freq);
711         }
712     }
713 }
714 
715 // Increment the frequency by this digit active in edit mode
incFreq()716 void CFreqCtrl::incFreq()
717 {
718     if (m_ActiveEditDigit >= 0)
719     {
720         if (m_DigitInfo[m_ActiveEditDigit].editmode)
721         {
722             m_freq += m_DigitInfo[m_ActiveEditDigit].incval;
723             if (m_ResetLowerDigits)
724             {
725                 /* Set digits below the active one to 0 */
726                 m_freq = m_freq - m_freq %
727                          m_DigitInfo[m_ActiveEditDigit].weight;
728             }
729             setFrequency(m_freq);
730             m_LastEditDigit = m_ActiveEditDigit;
731         }
732     }
733 }
734 
735 // Decrement the digit active in edit mode
decDigit()736 void CFreqCtrl::decDigit()
737 {
738     /** FIXME: no longer used? */
739     int       tmp;
740     qint64    tmpl;
741 
742     if (m_ActiveEditDigit >= 0)
743     {
744         if (m_DigitInfo[m_ActiveEditDigit].editmode)
745         {
746             if (m_DigitInfo[m_ActiveEditDigit].weight ==
747                 m_DigitInfo[m_ActiveEditDigit].incval)
748             {
749                 // get the current digit value
750                 tmp =
751                     (int)((m_freq / m_DigitInfo[m_ActiveEditDigit].weight) %
752                           10);
753                 // set the current digit value to zero
754                 m_freq -= tmp * m_DigitInfo[m_ActiveEditDigit].weight;
755                 tmp--;
756                 if (tmp < 0)
757                     tmp = 9;
758                 m_freq = m_freq + (qint64)tmp *
759                          m_DigitInfo[m_ActiveEditDigit].weight;
760             }
761             else
762             {
763                 tmp =
764                     (int)((m_freq / m_DigitInfo[m_ActiveEditDigit + 1].weight) %
765                           10);
766                 tmpl = m_freq - m_DigitInfo[m_ActiveEditDigit].incval;
767                 if (tmp !=
768                     (int)((tmpl / m_DigitInfo[m_ActiveEditDigit + 1].weight) %
769                           10))
770                 {
771                     tmpl += m_DigitInfo[m_ActiveEditDigit + 1].weight;
772                 }
773                 m_freq = tmpl;
774             }
775             setFrequency(m_freq);
776         }
777     }
778 }
779 
780 // Decrement the frequency by this digit active in edit mode
decFreq()781 void CFreqCtrl::decFreq()
782 {
783     if (m_ActiveEditDigit >= 0)
784     {
785         if (m_DigitInfo[m_ActiveEditDigit].editmode)
786         {
787             m_freq -= m_DigitInfo[m_ActiveEditDigit].incval;
788             if (m_ResetLowerDigits)
789             {
790                 /* digits below the active one are reset to 0 */
791                 m_freq = m_freq - m_freq %
792                          m_DigitInfo[m_ActiveEditDigit].weight;
793             }
794 
795             setFrequency(m_freq);
796             m_LastEditDigit = m_ActiveEditDigit;
797         }
798     }
799 }
800 
801 // Clear the selected digit and the digits below (i.e. set them to 0)
clearFreq()802 void CFreqCtrl::clearFreq()
803 {
804     if (m_ActiveEditDigit >= 0)
805     {
806         if (m_DigitInfo[m_ActiveEditDigit].editmode)
807         {
808             m_freq -= m_DigitInfo[m_ActiveEditDigit].val *
809                       m_DigitInfo[m_ActiveEditDigit].incval;
810 
811             /* digits below the active one are reset to 0 */
812             m_freq -= m_freq % m_DigitInfo[m_ActiveEditDigit].weight;
813 
814             setFrequency(m_freq);
815             m_LastEditDigit = m_ActiveEditDigit;
816         }
817     }
818 }
819 
820 //  Cursor move routines for arrow key editing
moveCursorLeft()821 void CFreqCtrl::moveCursorLeft()
822 {
823     if ((m_ActiveEditDigit >= 0) && (m_ActiveEditDigit < m_NumDigits - 1))
824     {
825         cursor().setPos(mapToGlobal(m_DigitInfo[++m_ActiveEditDigit].dQRect.
826                                     center()));
827     }
828 }
829 
moveCursorRight()830 void CFreqCtrl::moveCursorRight()
831 {
832     if (m_ActiveEditDigit > m_FirstEditableDigit)
833     {
834         cursor().setPos(mapToGlobal(m_DigitInfo[--m_ActiveEditDigit].dQRect.
835                                     center()));
836     }
837 }
838 
cursorHome()839 void CFreqCtrl::cursorHome()
840 {
841     if (m_ActiveEditDigit >= 0)
842     {
843         cursor().setPos(mapToGlobal(
844                             m_DigitInfo[m_NumDigits - 1].dQRect.center()));
845     }
846 }
847 
cursorEnd()848 void CFreqCtrl::cursorEnd()
849 {
850     if (m_ActiveEditDigit > 0)
851     {
852         cursor().setPos(mapToGlobal(m_DigitInfo[m_FirstEditableDigit].dQRect.
853                                     center()));
854     }
855 }
856 
setFrequencyFocus()857 void CFreqCtrl::setFrequencyFocus()
858 {
859     uint8_t position = floor(log10(m_freq));
860     position = (uint8_t)fmax(position, 4);      // restrict min to 100s of kHz
861 
862     QMouseEvent mouseEvent(QEvent::MouseMove,
863                            m_DigitInfo[position].dQRect.center(),
864                            Qt::NoButton,
865                            Qt::NoButton,
866                            Qt::NoModifier);
867     mouseMoveEvent(&mouseEvent);
868 }
869