From d5b8fecd6eab730d0670285f5e82a7a083029528 Mon Sep 17 00:00:00 2001 From: Stelios Bounanos Date: Wed, 16 Apr 2008 12:02:33 +0100 Subject: [PATCH] Upstream version 2.11M --- ChangeLog | 4 ++ configure.ac | 2 +- src/cw_rtty/cw.cxx | 2 +- src/dialogs/fl_digi.cxx | 129 +++++++++++++++++++++++------------- src/dominoex/dominoex.cxx | 3 +- src/feld/feld.cxx | 2 +- src/include/digiscope.h | 1 + src/include/fl_digi.h | 4 ++ src/include/fldigi-config.h | 56 ++++++++-------- src/include/picture.h | 3 +- src/include/status.h | 5 ++ src/main.cxx | 10 +++ src/mfsk/mfsk.cxx | 43 +++++++----- src/misc/status.cxx | 32 +++++++++ src/mt63/mt63.cxx | 2 +- src/olivia/olivia.cxx | 2 +- src/psk/psk.cxx | 2 +- src/throb/throb.cxx | 2 +- src/waterfall/digiscope.cxx | 11 +++ src/waterfall/waterfall.cxx | 2 + src/widgets/picture.cxx | 121 ++++++++++++++++++++++++++------- src/widgets/progress.cxx | 2 + src/wwv/analysis.cxx | 2 +- src/wwv/wwv.cxx | 2 +- 24 files changed, 316 insertions(+), 128 deletions(-) diff --git a/ChangeLog b/ChangeLog index 511d0f34..59543136 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ Change Log: 2) Added mousewheel over Macro buttons to move between macro button sets. 3) Fixed bug in Olivia signal level display. 4) Ported to Windows (win32) + 5) Added floating digiscope and / or fixed scope abutting waterfall + specified with command line switch --twoscopes + Default is floating digiscope without the fixed scope + 6) Added save as png to mfsk-pic reception 2.10.3) 1) Corrected memory leak bug. diff --git a/configure.ac b/configure.ac index cf8e3115..895e84f0 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ dnl major and minor must be integers; patch may dnl contain other characters or be empty m4_define(FLDIGI_MAJOR, [2]) m4_define(FLDIGI_MINOR, [11]) -m4_define(FLDIGI_PATCH, [L]) +m4_define(FLDIGI_PATCH, [M]) AC_INIT([fldigi], FLDIGI_MAJOR.FLDIGI_MINOR[FLDIGI_PATCH], [w1hkj AT w1hkj DOT com]) diff --git a/src/cw_rtty/cw.cxx b/src/cw_rtty/cw.cxx index a4ba9d5a..2606ab3e 100644 --- a/src/cw_rtty/cw.cxx +++ b/src/cw_rtty/cw.cxx @@ -55,7 +55,7 @@ void cw::rx_init() smpl_ctr = 0; cw_rr_current = 0; agc_peak = 0; - digiscope->mode(Digiscope::SCOPE); + set_scope_mode(Digiscope::SCOPE); put_MODEstatus(mode); usedefaultWPM = false; } diff --git a/src/dialogs/fl_digi.cxx b/src/dialogs/fl_digi.cxx index b7b20d07..e68acda1 100644 --- a/src/dialogs/fl_digi.cxx +++ b/src/dialogs/fl_digi.cxx @@ -104,7 +104,8 @@ Fl_Double_Window *scopeview = (Fl_Double_Window *)0; MixerBase* mixer = 0; -bool useCheckButtons = false; +bool useCheckButtons = false; +bool twoscopes = false; Fl_Button *btnTune = (Fl_Button *)0; Fl_Tile_check *TiledGroup = 0; @@ -152,6 +153,8 @@ string strMacroName[NUMMACKEYS]; waterfall *wf = (waterfall *)0; Digiscope *digiscope = (Digiscope *)0; +Digiscope *wfscope = (Digiscope *)0; + Fl_Slider *sldrSquelch = (Fl_Slider *)0; Progress *pgrsSquelch = (Progress *)0; @@ -1231,6 +1234,9 @@ int below(Fl_Widget* w) void create_fl_digi_main() { int pad = wSpace, Y = 0; + + if (twoscopes) WNOM -= 2*DEFAULT_SW; + fl_digi_main = new Fl_Double_Window(WNOM, HNOM, "fldigi"); mnu = new Fl_Menu_Bar(0, 0, WNOM - 142, Hmenu); // FL_NORMAL_SIZE may have changed; update the menu items @@ -1394,54 +1400,64 @@ void create_fl_digi_main() { Y += Hmacros; - Fl_Pack *wfpack = new Fl_Pack(0, Y, WNOM, Hwfall); - wfpack->type(1); - pgrsSquelch = new Progress( - 0, Y+2, - DEFAULT_SW, Hwfall-4, ""); - pgrsSquelch->color(FL_BACKGROUND2_COLOR, FL_DARK_GREEN); - pgrsSquelch->type(Progress::VERTICAL); - sldrSquelch = new Fl_Slider( - FL_VERT_NICE_SLIDER, - DEFAULT_SW, Y+2, - DEFAULT_SW, Hwfall-4, ""); + if (twoscopes) { + Fl_Pack *wfpack = new Fl_Pack(0, Y, WNOM, Hwfall); + wfpack->type(1); + wf = new waterfall(0, Y, Wwfall - Hwfall + 24, Hwfall); + wf->end(); + Fl_Pack *ypack = new Fl_Pack(Wwfall - Hwfall + 24, Y, Hwfall - 24, Hwfall); + ypack->type(0); + + wfscope = new Digiscope (Wwfall - Hwfall, Y, Hwfall - 24, Hwfall - 24); + + pgrsSquelch = new Progress( + Wwfall - Hwfall + 24, Y + Hwfall - 24, + Hwfall - 24, 12, ""); + pgrsSquelch->color(FL_BACKGROUND2_COLOR, FL_DARK_GREEN); + sldrSquelch = new Fl_Slider( + FL_HOR_NICE_SLIDER, + Wwfall - Hwfall + 24, Y + Hwfall - 12, + Hwfall - 24, 12, ""); - sldrSquelch->minimum(100); - sldrSquelch->maximum(0); - sldrSquelch->step(1); - sldrSquelch->value(progStatus.sldrSquelchValue); - sldrSquelch->callback((Fl_Callback*)cb_sldrSquelch); - sldrSquelch->color(FL_INACTIVE_COLOR); - -// wf = new waterfall(0, Y, Wwfall, Hwfall); - wf = new waterfall(2*DEFAULT_SW, Y, Wwfall, Hwfall);//Wwfall, Hwfall); - wf->end(); + sldrSquelch->minimum(0); + sldrSquelch->maximum(100); + sldrSquelch->step(1); + sldrSquelch->value(progStatus.sldrSquelchValue); + sldrSquelch->callback((Fl_Callback*)cb_sldrSquelch); + sldrSquelch->color(FL_INACTIVE_COLOR); -// Fl_Pack *ypack = new Fl_Pack(WNOM-(Hwfall-24 - 2*sw), Y, Hwfall-26, Hwfall); -// ypack->type(0); + ypack->end(); + Fl_Group::current()->resizable(wf); + wfpack->end(); + } else { + Fl_Pack *wfpack = new Fl_Pack(0, Y, WNOM, Hwfall); + wfpack->type(1); -// digiscope = new Digiscope (2*DEFAULT_SW + Wwfall - (Hwfall - 24), Y, Hwfall-24, Hwfall-24); -// digiscope->hide(); - -// pgrsSquelch = new Progress( -// WNOM-(Hwfall-24), Y + Hwfall - 24, -// Hwfall - 24, 12, ""); -// pgrsSquelch->color(FL_BACKGROUND2_COLOR, FL_DARK_GREEN); -// sldrSquelch = new Fl_Slider( -// FL_HOR_NICE_SLIDER, -// WNOM-(Hwfall-24), Y + Hwfall - 12, -// Hwfall - 24, 12, ""); - -// sldrSquelch->minimum(0); -// sldrSquelch->maximum(100); -// sldrSquelch->step(1); -// sldrSquelch->value(progStatus.sldrSquelchValue); -// sldrSquelch->callback((Fl_Callback*)cb_sldrSquelch); -// sldrSquelch->color(FL_INACTIVE_COLOR); + wf = new waterfall(0, Y, Wwfall, Hwfall); + wf->end(); -// ypack->end(); - Fl_Group::current()->resizable(wf); - wfpack->end(); + pgrsSquelch = new Progress( + WNOM - 2*DEFAULT_SW, Y + 4, + DEFAULT_SW, Hwfall - 8, ""); + pgrsSquelch->color(FL_BACKGROUND2_COLOR, FL_DARK_GREEN); + pgrsSquelch->type(Progress::VERTICAL); + pgrsSquelch->tooltip("Detected signal level"); + + sldrSquelch = new Fl_Slider( + FL_VERT_NICE_SLIDER, + WNOM - DEFAULT_SW, Y + 4, + DEFAULT_SW, Hwfall - 8, ""); + sldrSquelch->minimum(100); + sldrSquelch->maximum(0); + sldrSquelch->step(1); + sldrSquelch->value(progStatus.sldrSquelchValue); + sldrSquelch->callback((Fl_Callback*)cb_sldrSquelch); + sldrSquelch->color(FL_INACTIVE_COLOR); + sldrSquelch->tooltip("Squelch level"); + + Fl_Group::current()->resizable(wf); + wfpack->end(); + } Y += (Hwfall + 2); Fl_Pack *hpack = new Fl_Pack(0, Y, WNOM, Hstatus); @@ -1526,7 +1542,10 @@ void create_fl_digi_main() { fl_digi_main->xclass(PACKAGE_NAME); scopeview = new Fl_Double_Window(0,0,140,140, "Scope"); + scopeview->xclass(PACKAGE_NAME); digiscope = new Digiscope (0, 0, 140, 140); + scopeview->resizable(digiscope); + scopeview->size_range(50, 50, 0, 0, 0, 0, 1); scopeview->end(); scopeview->hide(); } @@ -1562,28 +1581,44 @@ void put_cwRcvWPM(double wpm) FL_AWAKE_D(); } +void set_scope_mode(Digiscope::scope_mode md) +{ + if (digiscope) + digiscope->mode(md); + if (wfscope) + wfscope->mode(md); +} + void set_scope(double *data, int len, bool autoscale) { if (digiscope) digiscope->data(data, len, autoscale); + if (wfscope) + wfscope->data(data, len, autoscale); } void set_phase(double phase, bool highlight) { if (digiscope) digiscope->phase(phase, highlight); + if (wfscope) + wfscope->phase(phase, highlight); } void set_rtty(double flo, double fhi, double amp) { if (digiscope) digiscope->rtty(flo, fhi, amp); + if (wfscope) + wfscope->rtty(flo, fhi, amp); } void set_video(double *data, int len) { if (digiscope) digiscope->video(data, len); + if (wfscope) + wfscope->video(data, len); } Fl_Menu_Item *mnuLogging = (Fl_Menu_Item *)0; @@ -2028,8 +2063,10 @@ void change_modem_param(int state) return; } } - else if (state & FL_SHIFT) + else if (state & FL_SHIFT) { val = sldrSquelch; + d = -d; + } val->value(val->clamp(val->increment(val->value(), -d))); bool changed_save = progdefaults.changed; diff --git a/src/dominoex/dominoex.cxx b/src/dominoex/dominoex.cxx index d2c95450..6a4c1525 100644 --- a/src/dominoex/dominoex.cxx +++ b/src/dominoex/dominoex.cxx @@ -93,8 +93,7 @@ void dominoex::init() modem::init(); restart(); rx_init(); -// digiscope->mode(Digiscope::SCOPE); - digiscope->mode(Digiscope::DOMDATA); + set_scope_mode(Digiscope::DOMDATA); } dominoex::~dominoex() diff --git a/src/feld/feld.cxx b/src/feld/feld.cxx index 5b2aa087..1e54a311 100644 --- a/src/feld/feld.cxx +++ b/src/feld/feld.cxx @@ -73,7 +73,7 @@ void feld::init() { modem::init(); initKeyWaveform(); - digiscope->mode(Digiscope::BLANK); + set_scope_mode(Digiscope::BLANK); put_MODEstatus(mode); } diff --git a/src/include/digiscope.h b/src/include/digiscope.h index e37fe504..44550e30 100644 --- a/src/include/digiscope.h +++ b/src/include/digiscope.h @@ -69,6 +69,7 @@ public: Digiscope(int, int, int, int); ~Digiscope(); int handle(int); + void resize(int x, int y, int w, int h); void draw(); void draw_scope(); void draw_phase(); diff --git a/src/include/fl_digi.h b/src/include/fl_digi.h index 5edcb5fa..a4edf275 100644 --- a/src/include/fl_digi.h +++ b/src/include/fl_digi.h @@ -49,6 +49,7 @@ #include "progress.h" extern Fl_Double_Window *fl_digi_main; +extern Fl_Double_Window *scopeview; extern ReceiveWidget *ReceiveText; extern TransmitWidget *TransmitText; @@ -89,6 +90,7 @@ extern Fl_Button *btnAltMacros; extern bool useCheckButtons; +extern bool twoscopes; extern int altMacros; extern waterfall *wf; @@ -107,6 +109,8 @@ extern void put_freq(double frequency); extern void put_Bandwidth(int bandwidth); extern void display_metric(double metric); extern void put_cwRcvWPM(double wpm); + +extern void set_scope_mode(Digiscope::scope_mode md); extern void set_scope(double *data, int len, bool autoscale = true); extern void set_phase(double phase, bool highlight); extern void set_rtty(double, double, double); diff --git a/src/include/fldigi-config.h b/src/include/fldigi-config.h index 116e54b5..4cfc2ff4 100644 --- a/src/include/fldigi-config.h +++ b/src/include/fldigi-config.h @@ -29,27 +29,25 @@ #define IDI_ICON 101 #endif +//============================================================================= // You can change the x1 width of the waterfall / spectrum display by modifying this // constant. // Suggest that you make the value a multiple of 100. // DO NOT EXCEED 4000 // The larger the number the greater the cpu load will be for creating the // waterfall display -#define DEFAULT_SW 15 +// +// Setting the DEFAULT_IMAGE_WIDTH to 3200 will size the x1 waterfall to be +// 800 pixels wide. The x1 waterfall size is always DEFAULT_IMAGE_WIDTH / 4 +// and the minimum width of main display would then be +// +// DEFAULT_IMAGE_WIDTH / 4 + 2 * BEZEL + 2 * DEFAULT_SW +// +// where BEZEL is set to 2 (border around the waterfall), and +// DEFAULT_SW is the width of the signal level and squelch controls + #define DEFAULT_IMAGE_WIDTH 3200 -#define DEFAULT_HWFALL 144 -#define DEFAULT_HNOM 570 -#define DEFAULT_WNOM (DEFAULT_IMAGE_WIDTH / 4 + 2 * DEFAULT_SW) -//#define DEFAULT_WNOM (DEFAULT_IMAGE_WIDTH / 4 + DEFAULT_HWFALL - BTN_HEIGHT) - -#define EMC_HWFALL 144 -#define EMC_HNOM 500 -#define EMC_WNOM (EMC_HWFALL - BTN_HEIGHT + 500) - -extern int IMAGE_WIDTH; -extern int Hwfall; -extern int HNOM; -extern int WNOM; +//============================================================================= // widget sizes internal to the waterfall widget #define BEZEL 2 @@ -73,6 +71,21 @@ extern int WNOM; #define bwXmtRcv 45 #define wSpace 2 +#define DEFAULT_SW 15 +#define DEFAULT_HWFALL 144 +#define DEFAULT_HNOM 570 +#define Wwfall (DEFAULT_IMAGE_WIDTH / 4 + 2 * BEZEL) +#define DEFAULT_WNOM (Wwfall + 2* DEFAULT_SW) + +#define EMC_HWFALL 144 +#define EMC_HNOM 500 +#define EMC_WNOM (EMC_HWFALL - BTN_HEIGHT + 500) + +extern int IMAGE_WIDTH; +extern int Hwfall; +extern int HNOM; +extern int WNOM; + #define Hmenu 22 #define Hqsoframe 48 #define Hnotes 22 @@ -80,11 +93,9 @@ extern int WNOM; #define Hmacros 22 #define Htext (HNOM - 4 - Hwfall - Hmenu - Hstatus - Hmacros - Hqsoframe - Hnotes) -// Htext = HNOM - 140 - Hwfall #define Hrcvtxt (Htext) / 2 #define Hxmttxt (Htext - (Hrcvtxt)) -#define Wwfall (WNOM - Hwfall + BTN_HEIGHT + 2 * BEZEL) #define Wmode 80 #define Ws2n 100 #define Wimd 100 @@ -94,17 +105,4 @@ extern int WNOM; #define Wstatus (WNOM - Wmode - Ws2n - Wimd - bwAfcOnOff - bwSqlOnOff - Wwarn) -//remove the comment delimiter to enable experimental psk250 and qpsk250 modes - -#define USE250 - -//remove the comment delimiter to enable both old and new text widget class -//switching from one to the other requires a restart of the program before -//the newly selected widget becomes effective. -// -//default is to use the new text widget class that is a fully enabled editor -//widget -//#define USE_BOTH_TEXT_WIDGETS - - #endif // FLDIGI_CONFIG_H diff --git a/src/include/picture.h b/src/include/picture.h index 342babf4..bf0112ec 100644 --- a/src/include/picture.h +++ b/src/include/picture.h @@ -61,7 +61,8 @@ public: void clear(); void image(Fl_Image *img) {Fl_Widget::image(img);} void resize(int, int, int, int); - int save_jpeg(const char *); + int save_jpeg(const char *); + int save_png(const char *); }; #endif diff --git a/src/include/status.h b/src/include/status.h index f2db3fab..a8502cce 100644 --- a/src/include/status.h +++ b/src/include/status.h @@ -34,6 +34,11 @@ struct status { bool sqlonoff; double RcvMixer; double XmtMixer; + int scopeX; + int scopeY; + bool scopeVisible; + int scopeW; + int scopeH; bool bLastStateRead; diff --git a/src/main.cxx b/src/main.cxx index fbe38683..6cebde24 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -352,6 +352,10 @@ void generate_option_help(void) { << " If PROFILE is ``emc'', ``emcomm'', or ``minimal'',\n" << " widget sizes will be adjusted for a minimal screen footprint\n\n" + << " --twoscopes\n" + << " digiscope adjacent to waterfall and,\n" + << " digiscope in separate resizeable window\n\n" + << " --usechkbtns\n" << " Use check buttons for AFC / SQL.\n"; @@ -378,6 +382,7 @@ int parse_args(int argc, char **argv, int& idx) #if USE_PORTAUDIO OPT_FRAMES_PER_BUFFER, #endif + OPT_TWO_SCOPES, OPT_EXIT_AFTER, OPT_HELP, OPT_VERSION }; @@ -395,6 +400,7 @@ int parse_args(int argc, char **argv, int& idx) { "window-width", 1, 0, OPT_WINDOW_WIDTH }, { "window-height", 1, 0, OPT_WINDOW_HEIGHT }, { "profile", 1, 0, OPT_PROFILE }, + { "twoscopes", 0, 0, OPT_TWO_SCOPES }, { "usechkbtns", 0, 0, OPT_USE_CHECK }, { "resample", 1, 0, OPT_RESAMPLE }, @@ -479,6 +485,10 @@ int parse_args(int argc, char **argv, int& idx) } break; + case OPT_TWO_SCOPES: + twoscopes = true; + break; + case OPT_USE_CHECK: useCheckButtons = true; break; diff --git a/src/mfsk/mfsk.cxx b/src/mfsk/mfsk.cxx index 03de5797..19da41e7 100644 --- a/src/mfsk/mfsk.cxx +++ b/src/mfsk/mfsk.cxx @@ -82,7 +82,7 @@ void mfsk::init() { modem::init(); rx_init(); - digiscope->mode(Digiscope::SCOPE); + set_scope_mode(Digiscope::SCOPE); } mfsk::~mfsk() @@ -253,8 +253,8 @@ void mfsk::recvpic(complex z) if (color) { pixelnbr = rgb + row + 3*col; - updateRxPic(byte, pixelnbr); -// REQ(&mfsk::updateRxPic, this, byte, pixelnbr); +//! updateRxPic(byte, pixelnbr); + REQ(updateRxPic, byte, pixelnbr); if (++col == picW) { col = 0; if (++rgb == 3) { @@ -264,8 +264,8 @@ void mfsk::recvpic(complex z) } } else { for (int i = 0; i < 3; i++) - updateRxPic(byte, pixelnbr); -// REQ(&mfsk::updateRxPic, this, byte, pixelnbr++); +//! updateRxPic(byte, pixelnbr++); + REQ(updateRxPic, byte, pixelnbr++); } picf = 0.0; @@ -563,13 +563,19 @@ int mfsk::rx_process(const double *buf, int len) if (rxstate == RX_STATE_PICTURE) { if (counter++ == picturesize) { counter = 0; + if (btnpicRxAbort) { + FL_LOCK_E(); + btnpicRxAbort->hide(); + btnpicRxSave->show(); + FL_UNLOCK_E(); + } rxstate = RX_STATE_DATA; // REQ_FLUSH(); put_status(""); -#ifndef __CYGWIN__ +//#ifndef __CYGWIN__ string autosave_dir = HomeDir + "mfsk_pics/"; - picRx->save_jpeg(autosave_dir.c_str()); -#endif + picRx->save_png(autosave_dir.c_str()); +//#endif } else recvpic(z); continue; @@ -696,8 +702,8 @@ void mfsk::sendpic(unsigned char *data, int len) for (i = 0; i < len; i++) { if (txstate == TX_STATE_PICTURE) - updateTxPic(data[i], this); -// REQ(&mfsk::updateTxPic, this, data[i]); +//! updateTxPic(data[i], this); + REQ(updateTxPic, data[i], this); if (reverse) f = get_txfreq_woffset() - bandwidth * (data[i] - 128) / 256.0; else @@ -877,32 +883,31 @@ void cb_picRxSave( Fl_Widget *w, void *who) { // mfsk *me = (mfsk *)who; const char *fn = - file_saveas( "Save image as:", "Independent JPEG Group\t*.{jpg,jpeg}", NULL ); + file_saveas( "Save image as:", "Portable Network Graphics\t*.png", "." ); if (!fn) return; - picRx->save_jpeg(fn); + picRx->save_png(fn); } void createRxViewer(mfsk *who) { - FL_LOCK_E(); + FL_LOCK_D(); picRxWin = new Fl_Double_Window(200, 140); picRxWin->xclass(PACKAGE_NAME); picRx = new picture(2, 2, 136, 104); btnpicRxSave = new Fl_Button(5, 140 - 30, 60, 24,"Save"); btnpicRxSave->callback(cb_picRxSave, who); -#ifdef __CYGWIN__ btnpicRxSave->hide(); -#endif btnpicRxAbort = new Fl_Button(70, 140 - 30, 60, 24, "Abort"); btnpicRxAbort->callback(cb_picRxAbort, who); btnpicRxClose = new Fl_Button(135, 140 - 30, 60, 24, "Hide"); btnpicRxClose->callback(cb_picRxClose, who); activate_mfsk_image_item(true); - FL_UNLOCK_E(); + FL_UNLOCK_D(); } void showRxViewer(int W, int H, mfsk *who) { + FL_LOCK_E(); if (!picRxWin) createRxViewer(who); int winW, winH; int picX, picY; @@ -910,16 +915,18 @@ void showRxViewer(int W, int H, mfsk *who) winH = H + 34; picX = (winW - W) / 2; picY = 2; - FL_LOCK_D(); picRxWin->size(winW, winH); picRx->resize(picX, picY, W, H); btnpicRxSave->resize(winW/2 - 65, H + 6, 60, 24); + btnpicRxSave->hide(); + btnpicRxAbort->resize(winW/2 - 65, H + 6, 60, 24); + btnpicRxAbort->show(); btnpicRxClose->resize(winW/2 + 5, H + 6, 60, 24); picRx->clear(); #ifndef __CYGWIN__ picRxWin->show(); #endif - FL_UNLOCK_D(); + FL_UNLOCK_E(); } void load_file(const char *n) { diff --git a/src/misc/status.cxx b/src/misc/status.cxx index 323cd44a..ed15818e 100644 --- a/src/misc/status.cxx +++ b/src/misc/status.cxx @@ -52,7 +52,14 @@ status progStatus = { true, // bool sqlonoff 1.0, // double RcvMixer; 1.0, // double XmtMixer; + 0, // int scopeX; + 0, // int scopeY; + false, // bool scopeVisible; + 50, // int scopeW; + 50, // int scopeH; + false // bool bLastStateRead; + }; @@ -98,6 +105,17 @@ void status::saveLastState() rigX = rigcontrol->x(); rigY = rigcontrol->y(); } + if (scopeview) { + if (scopeview->visible()) + scopeVisible = true; + else + scopeVisible = false; + scopeX = scopeview->x(); + scopeY = scopeview->y(); + scopeW = scopeview->w(); + scopeH = scopeview->h(); + } + string deffname = HomeDir; deffname.append("fldigi.status"); ofstream deffile(deffname.c_str(), ios::out); @@ -125,6 +143,11 @@ void status::saveLastState() deffile << sqlonoff << endl; deffile << RcvMixer << endl; deffile << XmtMixer << endl; + deffile << scopeX << endl; + deffile << scopeY << endl; + deffile << scopeVisible << endl; + deffile << scopeW << endl; + deffile << scopeH << endl; deffile.close(); } @@ -159,6 +182,11 @@ void status::loadLastState() deffile >> sqlonoff; deffile >> RcvMixer; deffile >> XmtMixer; + deffile >> scopeX; + deffile >> scopeY; + deffile >> scopeVisible; + deffile >> scopeW; + deffile >> scopeH; deffile.close(); progdefaults.wfRefLevel = reflevel; progdefaults.wfAmpSpan = ampspan; @@ -223,6 +251,10 @@ void status::initLastState() if (VIEWERvisible == true) openViewer(); + scopeview->resize(scopeX, scopeY, scopeW, scopeH); + if (scopeVisible == true) + scopeview->show(); + if (LOGenabled) { Fl_Menu_Item *mnulogging = getMenuItem("Log File"); if (!mnulogging) diff --git a/src/mt63/mt63.cxx b/src/mt63/mt63.cxx index 433464f2..ed62fc97 100644 --- a/src/mt63/mt63.cxx +++ b/src/mt63/mt63.cxx @@ -159,7 +159,7 @@ void mt63::restart() int err; put_MODEstatus(mode); - digiscope->mode(Digiscope::BLANK); + set_scope_mode(Digiscope::BLANK); set_freq(500.0 + bandwidth / 2.0); err = Tx->Preset((int)bandwidth, Interleave == 64 ? 1 : 0); diff --git a/src/olivia/olivia.cxx b/src/olivia/olivia.cxx index 97c94b25..2c4462d7 100644 --- a/src/olivia/olivia.cxx +++ b/src/olivia/olivia.cxx @@ -336,7 +336,7 @@ void olivia::init() { modem::init(); restart(); - digiscope->mode(Digiscope::BLANK); + set_scope_mode(Digiscope::BLANK); } olivia::olivia() diff --git a/src/psk/psk.cxx b/src/psk/psk.cxx index e8b869e3..d2c63cc6 100644 --- a/src/psk/psk.cxx +++ b/src/psk/psk.cxx @@ -83,7 +83,7 @@ void psk::rx_init() bitclk = 0; freqerr = 0.0; if (mailserver && progdefaults.PSKmailSweetSpot) sigsearch = SIGSEARCH; - digiscope->mode(Digiscope::PHASE); + set_scope_mode(Digiscope::PHASE); put_MODEstatus(mode); } diff --git a/src/throb/throb.cxx b/src/throb/throb.cxx index a7269c97..8efe35e8 100644 --- a/src/throb/throb.cxx +++ b/src/throb/throb.cxx @@ -63,7 +63,7 @@ void throb::init() { modem::init(); rx_init(); - digiscope->mode(Digiscope::SCOPE); + set_scope_mode(Digiscope::SCOPE); } throb::~throb() diff --git a/src/waterfall/digiscope.cxx b/src/waterfall/digiscope.cxx index 55649e40..c5f6c54f 100644 --- a/src/waterfall/digiscope.cxx +++ b/src/waterfall/digiscope.cxx @@ -345,3 +345,14 @@ int Digiscope::handle(int event) return 1; } + +void Digiscope::resize(int x, int y, int w, int h) +{ + delete [] vidbuf; + delete [] vidline; + vidbuf = new unsigned char[ 3 * (w-4) * (h-4)]; + vidline = new unsigned char[ 3 * (w-4)]; + + Fl_Widget::resize(x, y, w, h); + mode(_mode); +} diff --git a/src/waterfall/waterfall.cxx b/src/waterfall/waterfall.cxx index 034a5398..2030a9db 100644 --- a/src/waterfall/waterfall.cxx +++ b/src/waterfall/waterfall.cxx @@ -1372,6 +1372,8 @@ int waterfall::handle(int event) Fl_Valuator* v[] = { sldrSquelch, wfcarrier, wfRefLevel, wfAmpSpan }; for (size_t i = 0; i < sizeof(v)/sizeof(v[0]); i++) { if (Fl::event_inside(v[i])) { + if (v[i] == sldrSquelch) + d = -d; v[i]->value(v[i]->clamp(v[i]->increment(v[i]->value(), -d))); v[i]->do_callback(); return 1; diff --git a/src/widgets/picture.cxx b/src/widgets/picture.cxx index dc34ce20..de52e9f5 100644 --- a/src/widgets/picture.cxx +++ b/src/widgets/picture.cxx @@ -57,6 +57,7 @@ extern "C" { //# include "transupp.h" }; +#include #include "picture.h" @@ -237,6 +238,43 @@ int picture::handle(int event) return 0; } +static FILE* open_file(const char* name, const char* suffix) +{ + FILE* fp; + + size_t flen = strlen(name); + if (name[flen - 1] == '/') { + // if the name ends in a slash we will generate + // a timestamped name in the following format: + const char t[] = "pic_YYYY-MM-DD_HHMMSSz"; + + size_t newlen = flen + sizeof(t); + if (suffix) + newlen += 5; + char* newfn = new char[newlen]; + memcpy(newfn, name, flen); + + time_t time_sec = time(0); + struct tm ztime; + (void)gmtime_r(&time_sec, &ztime); + + size_t sz; + if ((sz = strftime(newfn + flen, newlen - flen, "pic_%F_%H%M%Sz", &ztime)) > 0) { + strncpy(newfn + flen + sz, suffix, newlen - flen - sz); + newfn[newlen - 1] = '\0'; + mkdir(name, 0777); + fp = fopen(newfn, "wb"); + } + else + fp = NULL; + delete [] newfn; + } + else + fp = fopen(name, "wb"); + + return fp; +} + // // save_jpeg - Write a captured picture to a JPEG format file. // @@ -248,29 +286,8 @@ int picture::save_jpeg(const char *filename) struct jpeg_compress_struct info; // Compressor info struct jpeg_error_mgr err; // Error handler info - size_t flen = strlen(filename); - if (filename[flen - 1] == '/') { - // if the filename ends in a slash we will generate - // a timestamped filename in the following format: - const char t[] = "pic_YYYY-MM-DD_HH:MM:SSz.jpg"; - - size_t newlen = flen + sizeof(t); - char newfn[newlen]; - memcpy(newfn, filename, flen); - - time_t time_sec = time(0); - struct tm ztime; - (void)gmtime_r(&time_sec, &ztime); - - if (strftime(newfn + flen, newlen - flen, "pic_%F_%Tz.jpg", &ztime) > 0) { - mkdir(filename, 0777); - if ((fp = fopen(newfn, "wb")) == NULL) - return -1; - } - } - else - if ((fp = fopen(filename, "wb")) == NULL) - return -1; + if ((fp = open_file(filename, ".jpg")) == NULL) + return -1; // Setup the JPEG compression stuff... info.err = jpeg_std_error(&err); @@ -302,3 +319,61 @@ int picture::save_jpeg(const char *filename) return 0; } +int picture::save_png(const char* filename) +{ + FILE* fp; + if ((fp = open_file(filename, ".png")) == NULL) + return -1; + + // set up the png structures + png_structp png; + png_infop info; + if ((png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) { + fclose(fp); + return -1; + } + if ((info = png_create_info_struct(png)) == NULL) { + png_destroy_write_struct(&png, png_infopp_NULL); + fclose(fp); + return -1; + } + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(&png, &info); + fclose(fp); + return -1; + } + + // use an stdio stream + png_init_io(png, fp); + + // set png header + png_set_IHDR(png, info, width, height, 1 << depth, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // TODO: write more useful image comments + png_text text; + text.key = strdup("Comment"); + text.text = strdup("MFSK-16 image decoded by " PACKAGE_STRING); + text.compression = PNG_TEXT_COMPRESSION_NONE; + png_set_text(png, info, &text, 1); + + // write header + png_write_info(png, info); + + // write image + png_bytep row; + for (int i = 0; i < height; i++) { + row = &vidbuf[i * width * depth]; + png_write_rows(png, &row, 1); + } + png_write_end(png, info); + + // clean up + free(text.key); + free(text.text); + png_destroy_write_struct(&png, &info); + fclose(fp); + + return 0; +} diff --git a/src/widgets/progress.cxx b/src/widgets/progress.cxx index ebe435b7..402d3fbf 100644 --- a/src/widgets/progress.cxx +++ b/src/widgets/progress.cxx @@ -24,6 +24,8 @@ // Include necessary header files... // +#include + #include #include diff --git a/src/wwv/analysis.cxx b/src/wwv/analysis.cxx index c705c1f5..20116959 100644 --- a/src/wwv/analysis.cxx +++ b/src/wwv/analysis.cxx @@ -46,7 +46,7 @@ void anal::init() { modem::init(); rx_init(); - digiscope->mode(Digiscope::RTTY); + set_scope_mode(Digiscope::RTTY); } anal::~anal() diff --git a/src/wwv/wwv.cxx b/src/wwv/wwv.cxx index 6a84d7c4..872cb171 100644 --- a/src/wwv/wwv.cxx +++ b/src/wwv/wwv.cxx @@ -52,7 +52,7 @@ void wwv::rx_init() ticks = 0; calc = false; zoom = false; - digiscope->mode(Digiscope::WWV); + set_scope_mode(Digiscope::WWV); put_MODEstatus(mode); }