1 // ----------------------------------------------------------------------------
2 //
3 // Viewer.cxx -- PSK browser
4 //
5 // Copyright (C) 2008-2009
6 // David Freese, W1HKJ
7 // Copyright (C) 2008-2010
8 // Stelios Bounanos, M0GLD
9 //
10 // This file is part of fldigi.
11 //
12 // Fldigi is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Fldigi is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
24 // ----------------------------------------------------------------------------
25
26 #include <FL/Enumerations.H>
27
28 #include "config.h"
29
30 #include "Viewer.h"
31 #include "trx.h"
32 #include "main.h"
33 #include "configuration.h"
34 #include "confdialog.h"
35 #include "status.h"
36 #include "waterfall.h"
37 #include "fl_digi.h"
38 #include "re.h"
39 #include "gettext.h"
40 #include "flmisc.h"
41 #include "spot.h"
42 #include "icons.h"
43
44 #include "psk_browser.h"
45 #include "view_rtty.h"
46 #include "spectrum_viewer.h"
47
48 extern pskBrowser *mainViewer;
49
50 using namespace std;
51
52 //
53 // External viewer dialog
54 //
55
56 Fl_Double_Window *dlgViewer = 0;
57 static Fl_Button *btnCloseViewer;
58 static Fl_Button *btnClearViewer;
59 Fl_Input2 *viewer_inp_seek;
60
61 Fl_Value_Slider2 *sldrViewerSquelch;
62
63 pskBrowser *brwsViewer;
64
65 static long long rfc;
66 static bool usb;
67
initViewer()68 void initViewer()
69 {
70 usb = wf->USB();
71 rfc = wf->rfcarrier();
72 if (mainViewer) {
73 mainViewer->usb = usb;
74 mainViewer->rfc = rfc;
75 mainViewer->setfont(progdefaults.ViewerFontnbr, progdefaults.ViewerFontsize);
76 mainViewer->HighLight_1((Fl_Color)progdefaults.bwsrHiLight1);
77 mainViewer->HighLight_2((Fl_Color)progdefaults.bwsrHiLight2);
78 mainViewer->SelectColor((Fl_Color)progdefaults.bwsrSelect);
79 mainViewer->Background1((Fl_Color)progdefaults.bwsrBackgnd1);
80 mainViewer->Background2((Fl_Color)progdefaults.bwsrBackgnd2);
81 mainViewer->makecolors();
82 mainViewer->clear();
83 if (active_modem->get_mode() == MODE_RTTY) {
84 mvsquelch->range(-12.0, 6.0);
85 mvsquelch->value(progStatus.VIEWER_rttysquelch);
86 } else if (active_modem->get_mode() == MODE_CW) {
87 mvsquelch->range(0.0, 40.0);
88 mvsquelch->value(progStatus.VIEWER_cwsquelch);
89 } else {
90 mvsquelch->range(-3.0, 6.0);
91 mvsquelch->value(progStatus.VIEWER_psksquelch);
92 }
93 mvsquelch->redraw();
94 }
95 if (brwsViewer) {
96 brwsViewer->usb = usb;
97 brwsViewer->rfc = rfc;
98 brwsViewer->setfont(progdefaults.ViewerFontnbr, progdefaults.ViewerFontsize);
99 brwsViewer->HighLight_1((Fl_Color)progdefaults.bwsrHiLight1);
100 brwsViewer->HighLight_2((Fl_Color)progdefaults.bwsrHiLight2);
101 brwsViewer->SelectColor((Fl_Color)progdefaults.bwsrSelect);
102 brwsViewer->Background1((Fl_Color)progdefaults.bwsrBackgnd1);
103 brwsViewer->Background2((Fl_Color)progdefaults.bwsrBackgnd2);
104 brwsViewer->makecolors();
105 brwsViewer->clear();
106 dlgViewer->size(dlgViewer->w(), dlgViewer->h() - brwsViewer->h() +
107 pskBrowser::cheight * progdefaults.VIEWERchannels + 4);
108 if (active_modem->get_mode() == MODE_RTTY) {
109 sldrViewerSquelch->range(-12.0, 6.0);
110 sldrViewerSquelch->value(progStatus.VIEWER_rttysquelch);
111 } else if (active_modem->get_mode() == MODE_CW) {
112 sldrViewerSquelch->range(0.0, 40.0);
113 sldrViewerSquelch->value(progStatus.VIEWER_cwsquelch);
114 } else {
115 sldrViewerSquelch->range(-3.0, 6.0);
116 sldrViewerSquelch->value(progStatus.VIEWER_psksquelch);
117 }
118 sldrViewerSquelch->redraw();
119 }
120 active_modem->clear_viewer();
121 }
122
viewaddchr(int ch,int freq,char c,int md)123 void viewaddchr(int ch, int freq, char c, int md)
124 {
125 if (mainViewer) {
126 if (mainViewer->rfc != wf->rfcarrier() || mainViewer->usb != wf->USB()) {
127 mainViewer->rfc = wf->rfcarrier();
128 mainViewer->usb = wf->USB();
129 mainViewer->redraw();
130 }
131 mainViewer->addchr(ch, freq, c, md, true);
132 }
133 if (dlgViewer) {
134 if (brwsViewer->rfc != wf->rfcarrier() || brwsViewer->usb != wf->USB()) {
135 brwsViewer->rfc = wf->rfcarrier();
136 brwsViewer->usb = wf->USB();
137 brwsViewer->redraw();
138 }
139 brwsViewer->addchr(ch, freq, c, md);
140 }
141
142 if (progStatus.spot_recv && freq != NULLFREQ)
143 spot_recv(c, ch, freq, md);
144 }
145
viewclearchannel(int ch)146 void viewclearchannel(int ch) // 0 < ch < channels - 1
147 {
148 if (mainViewer)
149 mainViewer->clearch(ch, NULLFREQ);
150 if (dlgViewer)
151 brwsViewer->clearch(ch, NULLFREQ);
152 }
153
viewerswap(int i,int j)154 void viewerswap(int i, int j)
155 {
156 if (mainViewer)
157 mainViewer->swap(i,j);
158 if (dlgViewer)
159 brwsViewer->swap(i,j);
160 }
161
viewer_redraw()162 void viewer_redraw()
163 {
164 usb = wf->USB();
165 rfc = wf->rfcarrier();
166 if (mainViewer) {
167 mainViewer->usb = usb;
168 mainViewer->rfc = rfc;
169 mainViewer->HighLight_1((Fl_Color)progdefaults.bwsrHiLight1);
170 mainViewer->HighLight_2((Fl_Color)progdefaults.bwsrHiLight2);
171 mainViewer->SelectColor((Fl_Color)progdefaults.bwsrSelect);
172 mainViewer->Background1((Fl_Color)progdefaults.bwsrBackgnd1);
173 mainViewer->Background2((Fl_Color)progdefaults.bwsrBackgnd2);
174 mainViewer->makecolors();
175 mainViewer->resize(mainViewer->x(), mainViewer->y(), mainViewer->w(), mainViewer->h());
176 }
177 if (dlgViewer) {
178 brwsViewer->usb = usb;
179 brwsViewer->rfc = rfc;
180 brwsViewer->resize(
181 brwsViewer->x(), brwsViewer->y(), brwsViewer->w(), brwsViewer->h());
182 brwsViewer->HighLight_1((Fl_Color)progdefaults.bwsrHiLight1);
183 brwsViewer->HighLight_2((Fl_Color)progdefaults.bwsrHiLight2);
184 brwsViewer->SelectColor((Fl_Color)progdefaults.bwsrSelect);
185 brwsViewer->Background1((Fl_Color)progdefaults.bwsrBackgnd1);
186 brwsViewer->Background2((Fl_Color)progdefaults.bwsrBackgnd2);
187 brwsViewer->makecolors();
188 dlgViewer->redraw();
189 }
190 }
191
cb_btnCloseViewer(Fl_Button *,void *)192 static void cb_btnCloseViewer(Fl_Button*, void*) {
193 progStatus.VIEWERxpos = dlgViewer->x();
194 progStatus.VIEWERypos = dlgViewer->y();
195 progStatus.VIEWERwidth = dlgViewer->w();
196 progStatus.VIEWERheight = dlgViewer->h();
197 dlgViewer->hide();
198 }
199
cb_btnClearViewer(Fl_Button *,void *)200 static void cb_btnClearViewer(Fl_Button*, void*) {
201 brwsViewer->clear();
202 if (mainViewer)
203 mainViewer->clear();
204 active_modem->clear_viewer();
205 }
206
cb_brwsViewer(Fl_Hold_Browser *,void *)207 static void cb_brwsViewer(Fl_Hold_Browser*, void*) {
208 int sel = brwsViewer->value();
209 if (sel == 0 || sel > progdefaults.VIEWERchannels)
210 return;
211
212 switch (Fl::event_button()) {
213 case FL_LEFT_MOUSE:
214 if (brwsViewer->freq(sel) != NULLFREQ) {
215 if (progdefaults.VIEWERhistory) {
216 ReceiveText->addchr('\n', FTextBase::RECV);
217 bHistory = true;
218 } else {
219 ReceiveText->addchr('\n', FTextBase::ALTR);
220 ReceiveText->addstr(brwsViewer->line(sel).c_str(), FTextBase::ALTR);
221 }
222 active_modem->set_freq(brwsViewer->freq(sel));
223 recenter_spectrum_viewer();
224 active_modem->set_sigsearch(SIGSEARCH);
225 if (mainViewer)
226 mainViewer->select(sel);
227 } else
228 brwsViewer->deselect();
229 break;
230 case FL_MIDDLE_MOUSE: // copy from modem
231 // set_freq(sel, active_modem->get_freq());
232 break;
233 case FL_RIGHT_MOUSE: // reset
234 {
235 int ch = progdefaults.VIEWERascend ? progdefaults.VIEWERchannels - sel : sel - 1;
236 active_modem->clear_ch(ch);
237 brwsViewer->deselect();
238 if (mainViewer) mainViewer->deselect();
239 }
240 default:
241 break;
242 }
243 }
244
cb_Squelch(Fl_Slider *,void *)245 static void cb_Squelch(Fl_Slider *, void *)
246 {
247 if (active_modem->get_mode() == MODE_RTTY)
248 progStatus.VIEWER_rttysquelch = sldrViewerSquelch->value();
249 else if (active_modem->get_mode() == MODE_CW)
250 progStatus.VIEWER_cwsquelch = sldrViewerSquelch->value();
251 else
252 progStatus.VIEWER_psksquelch = sldrViewerSquelch->value();
253
254 if (mainViewer)
255 mvsquelch->value(sldrViewerSquelch->value());
256 }
257
cb_Seek(Fl_Input *,void *)258 static void cb_Seek(Fl_Input *, void *)
259 {
260 static Fl_Color seek_color[2] = { FL_FOREGROUND_COLOR,
261 adjust_color(FL_RED, FL_BACKGROUND2_COLOR) }; // invalid RE
262 seek_re.recompile(*viewer_inp_seek->value() ? viewer_inp_seek->value() : "[invalid");
263 if (viewer_inp_seek->textcolor() != seek_color[!seek_re]) {
264 viewer_inp_seek->textcolor(seek_color[!seek_re]);
265 viewer_inp_seek->redraw();
266 }
267 progStatus.browser_search = viewer_inp_seek->value();
268 if (mainViewer) txtInpSeek->value(progStatus.browser_search.c_str());
269 }
270
createViewer(void)271 Fl_Double_Window* createViewer(void)
272 {
273 fl_font(progdefaults.ViewerFontnbr, progdefaults.ViewerFontsize);
274 pskBrowser::cwidth = (int)fl_width("W");
275 pskBrowser::cheight = fl_height();
276
277 progStatus.VIEWERnchars = progStatus.VIEWERnchars > 30 ? progStatus.VIEWERnchars : 30;
278
279 int pad = BWSR_BORDER / 2;
280
281 int viewerwidth = progStatus.VIEWERwidth - 2*BWSR_BORDER;
282 int viewerheight = progStatus.VIEWERheight - 2 * BWSR_BORDER - pad - 20;
283
284 Fl_Double_Window* w = new Fl_Double_Window(progStatus.VIEWERxpos, progStatus.VIEWERypos,
285 viewerwidth + 2 * BWSR_BORDER,
286 viewerheight + 2 * BWSR_BORDER + pad + 20 + 20,
287 _("Signal Browser"));
288
289 Fl_Group* gseek = new Fl_Group(BWSR_BORDER, BWSR_BORDER, viewerwidth, 20);
290 // search field
291 const char* label = _("Find: ");
292 fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
293 viewer_inp_seek = new Fl_Input2(static_cast<int>(BWSR_BORDER + fl_width(label) + fl_width("X")), BWSR_BORDER, 200, gseek->h(), label);
294 viewer_inp_seek->labelfont(FL_HELVETICA);
295 viewer_inp_seek->callback((Fl_Callback*)cb_Seek);
296 viewer_inp_seek->when(FL_WHEN_CHANGED);
297 viewer_inp_seek->textfont(FL_HELVETICA);
298 viewer_inp_seek->value(progStatus.browser_search.c_str());
299 viewer_inp_seek->do_callback();
300 gseek->resizable(0);
301 gseek->end();
302
303 brwsViewer = new pskBrowser(BWSR_BORDER, viewer_inp_seek->y() + viewer_inp_seek->h(), viewerwidth, viewerheight);
304
305 brwsViewer->callback((Fl_Callback*)cb_brwsViewer);
306 brwsViewer->setfont(progdefaults.ViewerFontnbr, progdefaults.ViewerFontsize);
307 brwsViewer->seek_re = &seek_re;
308
309 Fl_Group *g = new Fl_Group(BWSR_BORDER, brwsViewer->y() + brwsViewer->h() + pad, viewerwidth, 20);
310 // close button
311 btnCloseViewer = new Fl_Button(g->w() + BWSR_BORDER - 75, g->y(), 75, g->h(),
312 icons::make_icon_label(_("Close"), close_icon));
313 btnCloseViewer->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
314 icons::set_icon_label(btnCloseViewer);
315 btnCloseViewer->callback((Fl_Callback*)cb_btnCloseViewer);
316
317 // clear button
318 btnClearViewer = new Fl_Button(btnCloseViewer->x() - btnCloseViewer->w() - pad,
319 btnCloseViewer->y(), btnCloseViewer->w(), btnCloseViewer->h(),
320 icons::make_icon_label(_("Clear"), edit_clear_icon));
321 btnClearViewer->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
322 icons::set_icon_label(btnClearViewer);
323 btnClearViewer->callback((Fl_Callback*)cb_btnClearViewer);
324 btnClearViewer->tooltip(_("Left click to clear text\nRight click to reset frequencies"));
325
326 // squelch
327 sldrViewerSquelch = new Fl_Value_Slider2(BWSR_BORDER, g->y(),
328 btnClearViewer->x() - BWSR_BORDER - pad, g->h());
329 sldrViewerSquelch->align(FL_ALIGN_RIGHT);
330 sldrViewerSquelch->tooltip(_("Set Viewer Squelch"));
331 sldrViewerSquelch->type(FL_HOR_NICE_SLIDER);
332 sldrViewerSquelch->range(-12.0, 6.0);
333 sldrViewerSquelch->step(0.1);
334 sldrViewerSquelch->value(progStatus.VIEWER_psksquelch);
335 sldrViewerSquelch->callback((Fl_Callback*)cb_Squelch);
336 sldrViewerSquelch->color( fl_rgb_color(
337 progdefaults.bwsrSliderColor.R,
338 progdefaults.bwsrSliderColor.G,
339 progdefaults.bwsrSliderColor.B));
340 sldrViewerSquelch->selection_color( fl_rgb_color(
341 progdefaults.bwsrSldrSelColor.R,
342 progdefaults.bwsrSldrSelColor.G,
343 progdefaults.bwsrSldrSelColor.B));
344
345 g->resizable(sldrViewerSquelch);
346 g->end();
347
348 w->end();
349 w->callback((Fl_Callback*)cb_btnCloseViewer);
350 w->resizable(brwsViewer);
351 w->size_range(
352 (30 * pskBrowser::cwidth) + pskBrowser::sbarwidth + 2 * BWSR_BORDER,
353 5 * pskBrowser::cheight + 20 + 2 * BWSR_BORDER + pad);
354 w->xclass(PACKAGE_NAME);
355
356 w->hide();
357 return w;
358 }
359
openViewer()360 void openViewer()
361 {
362 if (!dlgViewer) {
363 dlgViewer = createViewer();
364 }
365 initViewer();
366 dlgViewer->show();
367 dlgViewer->redraw();
368 }
369
viewer_paste_freq(int freq)370 void viewer_paste_freq(int freq)
371 {
372 for (int i = 0; i < progdefaults.VIEWERchannels; i++) {
373 int ftest = active_modem->viewer_get_freq(i);
374 if (ftest == NULLFREQ) continue;
375 if (fabs(ftest - freq) <= 50) {
376 if (progdefaults.VIEWERascend)
377 i = (progdefaults.VIEWERchannels - i);
378 else i++;
379 if (mainViewer)
380 mainViewer->select(i);
381 if (brwsViewer)
382 brwsViewer->select(i);
383 return;
384 }
385 }
386 }
387
388
389