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