1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2018
3 //              David Freese, W1HKJ
4 //
5 // This file is part of flrig.
6 //
7 // flrig is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // flrig is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20 
21 #include <FL/Fl.H>
22 #include <FL/Fl_Single_Window.H>
23 #include <FL/fl_draw.H>
24 #include "pl_tones.h"
25 
26 #define BOXWIDTH 50
27 #define BOXHEIGHT 20
28 #define BORDER 2
29 
30 /**
31  This widget creates a modal window for selecting a tone from a CTCSS map.
32 */
33 static const char *szTONES[] = {
34  "67.0",  "69.3",  "71.9",  "74.4",  "77.0",
35  "79.7",  "82.5",  "85.4",  "88.5",  "91.5",
36  "94.8",  "97.4", "100.0", "103.5", "107.2",
37 "110.9", "114.8", "118.8", "123.0", "127.3",
38 "131.8", "136.5", "141.3", "146.2", "151.4",
39 "156.7", "159.8", "162.2", "165.5", "167.9",
40 "171.3", "173.8", "177.3", "179.9", "183.5",
41 "186.2", "189.9", "192.8", "196.6", "199.5",
42 "203.5", "206.5", "210.7", "218.1", "225.7",
43 "229.1", "233.6", "241.8", "250.3", "254.1" };
44 
TonePicker(int oldtone,Fl_Color clr1,Fl_Color clr2)45 TonePicker::TonePicker(int oldtone, Fl_Color clr1, Fl_Color clr2) :
46 	Fl_Window(BOXWIDTH*5 + 1 + 2*BORDER, BOXHEIGHT*10 + 1 + 2*BORDER),
47 	clr_bkgnd(clr1),
48 	clr_select(clr2)
49 {
50 	clear_border();
51 	set_modal();
52 	initial = which = oldtone;
53 }
54 
drawbox(int c)55 void TonePicker::drawbox(int c) {
56 	int X = (c % 5) * BOXWIDTH + BORDER;
57 	int Y = (c / 5) * BOXHEIGHT + BORDER;
58 	fl_draw_box(c == which ? FL_DOWN_BOX : FL_BORDER_BOX,
59 		X, Y, BOXWIDTH + 1, BOXHEIGHT + 1,
60 		c == which ? clr_select : clr_bkgnd);
61 	fl_color(c == which ? FL_WHITE : FL_FOREGROUND_COLOR);
62 	fl_draw(szTONES[c],
63 			X, Y, BOXWIDTH + 1, BOXHEIGHT + 1,
64 			(Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE) );
65 }
66 
draw()67 void TonePicker::draw() {
68 	if (damage() != FL_DAMAGE_CHILD) {
69 		fl_draw_box(FL_UP_BOX,0,0,w(),h(),color());
70 		for (int c = 0; c < 50; c++) drawbox(c);
71 	} else {
72 		drawbox(previous);
73 		drawbox(which);
74 	}
75 	previous = which;
76 }
77 
handle(int e)78 int TonePicker::handle(int e) {
79 	int c = which;
80 	switch (e) {
81 	case FL_PUSH:
82 	case FL_DRAG: {
83 		int X = (Fl::event_x_root() - x() - BORDER);
84 		if (X >= 0) X = X / BOXWIDTH;
85 		int Y = (Fl::event_y_root() - y() - BORDER);
86 		if (Y >= 0) Y = Y / BOXHEIGHT;
87 		if (X >= 0 && X < 5 && Y >= 0 && Y < 10)
88 			c = 5*Y + X;
89 		else
90 			c = initial;
91 		} break;
92 	case FL_RELEASE:
93 		done = 1;
94 		return 1;
95 	case FL_KEYBOARD:
96 		switch (Fl::event_key()) {
97 		case FL_Up: if (c > 5) c -= 5; break;
98 		case FL_Down: if (c < 45) c += 5; break;
99 		case FL_Left: if (c > 0) c--; break;
100 		case FL_Right: if (c < 50) c++; break;
101 		case FL_Escape: which = initial; done = 1; return 1;
102 		case FL_KP_Enter:
103 		case FL_Enter: done = 1; return 1;
104 		default: return 0;
105 		}
106 		break;
107 	default:
108 		return 0;
109 	}
110 	if (c != which) {
111 		which = c; damage(FL_DAMAGE_CHILD);
112 		int bx = (c % 5) * BOXWIDTH + BORDER;
113 		int by = (c / 5) * BOXHEIGHT + BORDER;
114 		int px = x();
115 		int py = y();
116 		int scr_x, scr_y, scr_w, scr_h;
117 		Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h);
118 		if (px < scr_x) px = scr_x;
119 		if (px + bx + BOXWIDTH + BORDER >= scr_x+scr_w)
120 			px = scr_x + scr_w - bx - BOXWIDTH-BORDER;
121 		if (py < scr_y) py = scr_y;
122 		if (py + by + BOXHEIGHT + BORDER >= scr_y+scr_h)
123 			py = scr_y + scr_h - by - BOXHEIGHT - BORDER;
124 		if (px + bx < BORDER) px = BORDER - bx;
125 		if (py + by < BORDER) py = BORDER - by;
126 		position(px,py);
127 	}
128 	return 1;
129 }
130 
run()131 int  TonePicker::run() {
132 	if (which > 50) {
133 		position(
134 			Fl::event_x_root() - w()/2, Fl::event_y_root() - y()/2);
135 	} else {
136 		position(
137 			Fl::event_x_root() - (initial % 5)*BOXWIDTH - BOXWIDTH/2 - BORDER,
138 			Fl::event_y_root() - (initial / 10)*BOXHEIGHT - BOXHEIGHT/2 - BORDER);
139 	}
140 	show();
141 	Fl::grab(*this);
142 	done = 0;
143 	while (!done) Fl::wait();
144 	Fl::grab(0);
145 	return which;
146 }
147 
btn_cb(Fl_Button * v,void * d)148 void btn_cb (Fl_Button *v, void *d)
149 {
150 	Fl_PL_tone *p = (Fl_PL_tone *)(v->parent());
151 	TonePicker m(p->val, p->clr_bkgnd, p->clr_select);
152 	int val = m.run();
153 	p->val = val;
154 	p->valbox->label(szTONES[val]);
155 	p->valbox->redraw();
156 }
157 
Fl_PL_tone(int X,int Y,int W,int H,const char * label)158 Fl_PL_tone::Fl_PL_tone(int X, int Y, int W, int H, const char *label)
159 		: Fl_Group (X, Y, W, H, label)
160 {
161 	valbox = new Fl_Box (FL_DOWN_BOX, X, Y, W-H, H, "");
162 	valbox->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
163 	valbox->color(FL_BACKGROUND2_COLOR);
164 
165 	btn = new Fl_Button (X + W - H + 1, Y, H - 1, H, "@2>");
166 	btn->callback ((Fl_Callback *)btn_cb, 0);
167 
168 	clr_bkgnd = FL_BACKGROUND_COLOR;
169 	clr_select = FL_SELECTION_COLOR;
170 
171 	val = 0;
172 }
173 
~Fl_PL_tone()174 Fl_PL_tone::~Fl_PL_tone()
175 {
176 	delete valbox;
177 	delete btn;
178 }
179 
value()180 int Fl_PL_tone::value()
181 {
182 	return val;
183 }
184 
value(int val_)185 void Fl_PL_tone::value(int val_)
186 {
187 	val = val_;
188 	valbox->label(szTONES[val]);
189 }
190 
background(Fl_Color clr)191 void Fl_PL_tone::background(Fl_Color clr)
192 {
193 	clr_bkgnd = clr;
194 }
195 
color_select(Fl_Color clr)196 void Fl_PL_tone::color_select(Fl_Color clr)
197 {
198 	clr_select = clr;
199 }
200