kopia lustrzana https://github.com/jamescoxon/dl-fldigi
335 wiersze
8.2 KiB
C++
335 wiersze
8.2 KiB
C++
// ----------------------------------------------------------------------------
|
|
// flmisc.cxx
|
|
//
|
|
// Copyright (C) 2008-2010
|
|
// Stelios Bounanos, M0GLD
|
|
//
|
|
// This file is part of fldigi.
|
|
//
|
|
// Fldigi is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Fldigi is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include <config.h>
|
|
|
|
#include <string>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <cstdarg>
|
|
|
|
#include <FL/Fl.H>
|
|
#include <FL/Enumerations.H>
|
|
#include <FL/Fl_Menu_Item.H>
|
|
#include <FL/Fl_Tooltip.H>
|
|
|
|
#include <FL/Fl_Pixmap.H>
|
|
#include <FL/Fl_Window.H>
|
|
#include <FL/Fl_Group.H>
|
|
#include <FL/Fl_Box.H>
|
|
#include <FL/Fl_Dial.H>
|
|
#include <FL/Fl_Dial.H>
|
|
#include <FL/Fl_Return_Button.H>
|
|
#include <FL/fl_draw.H>
|
|
|
|
#include <FL/x.H>
|
|
|
|
#include "flmisc.h"
|
|
#include "pixmaps.h"
|
|
|
|
using namespace std;
|
|
|
|
unsigned quick_choice_menu(const char* title, unsigned sel, const Fl_Menu_Item* menu)
|
|
{
|
|
unsigned n = menu->size();
|
|
sel = CLAMP(sel - 1, 0, n - 1);
|
|
int t = Fl_Tooltip::enabled();
|
|
Fl_Tooltip::disable();
|
|
const Fl_Menu_Item* p = menu->popup(Fl::event_x(), Fl::event_y(), title, menu + sel);
|
|
Fl_Tooltip::enable(t);
|
|
return p ? p - menu + 1 : 0;
|
|
}
|
|
|
|
unsigned quick_choice(const char* title, unsigned sel, ...)
|
|
{
|
|
const char* item;
|
|
const Fl_Menu_Item* menu = NULL;
|
|
Fl_Menu_Item* p = NULL;
|
|
|
|
va_list ap;
|
|
va_start(ap, sel);
|
|
for (size_t n = 0; (item = va_arg(ap, const char*)); n++) {
|
|
if ((p = (Fl_Menu_Item*)realloc(p, (n+2) * sizeof(Fl_Menu_Item))) == NULL) {
|
|
free((Fl_Menu_Item*)menu);
|
|
va_end(ap);
|
|
return 0;
|
|
}
|
|
memset(p + n, 0, 2 * sizeof(Fl_Menu_Item));
|
|
p[n].label(item);
|
|
p[n+1].label(NULL);
|
|
menu = p;
|
|
}
|
|
va_end(ap);
|
|
|
|
sel = quick_choice_menu(title, sel, menu);
|
|
free(p);
|
|
return sel;
|
|
}
|
|
|
|
// Adjust and return fg color to ensure good contrast with bg
|
|
Fl_Color adjust_color(Fl_Color fg, Fl_Color bg)
|
|
{
|
|
Fl_Color adj;
|
|
unsigned max = 24;
|
|
while ((adj = fl_contrast(fg, bg)) != fg && max--)
|
|
fg = (adj == FL_WHITE) ? fl_color_average(fg, FL_WHITE, .9)
|
|
: fl_color_average(fg, FL_BLACK, .9);
|
|
return fg;
|
|
}
|
|
|
|
// invert colour (bg1r, bg1g, bg1b); return def if new colour does not make
|
|
// good contrast with bg2
|
|
void adjust_color_inv(unsigned char& bg1r, unsigned char& bg1g, unsigned char& bg1b,
|
|
Fl_Color bg2, Fl_Color def)
|
|
{
|
|
bg1r = 255 - bg1r; bg1g = 255 - bg1g; bg1b = 255 - bg1b;
|
|
Fl_Color adj = fl_rgb_color(bg1r, bg1g, bg1b);
|
|
if (fl_contrast(adj, bg2) != adj)
|
|
Fl::get_color((def >= 0 ? def : adj), bg1r, bg1g, bg1b);
|
|
}
|
|
|
|
#if !defined(__APPLE__) && !defined(__WOE32__) && USE_X
|
|
# include <FL/Fl_Window.H>
|
|
# include <FL/Fl_Pixmap.H>
|
|
# include <FL/fl_draw.H>
|
|
void make_pixmap(Pixmap *xpm, const char **data, int argc, char** argv)
|
|
{
|
|
// We need a displayed window to provide a GC for X_CreatePixmap
|
|
Fl_Window w(0, 0, PACKAGE_NAME);
|
|
w.xclass(PACKAGE_NAME);
|
|
w.border(0);
|
|
w.show(argc, argv);
|
|
|
|
Fl_Pixmap icon(data);
|
|
int maxd = MAX(icon.w(), icon.h());
|
|
w.make_current();
|
|
*xpm = fl_create_offscreen(maxd, maxd);
|
|
w.hide();
|
|
|
|
fl_begin_offscreen(*xpm);
|
|
// Fl_Color(FL_BACKGROUND_COLOR);
|
|
// fl_rectf(0, 0, maxd, maxd);
|
|
icon.draw(maxd - icon.w(), maxd - icon.h());
|
|
fl_end_offscreen();
|
|
}
|
|
#endif
|
|
|
|
|
|
notify_dialog::notify_dialog(int X, int Y, const char* l)
|
|
: Fl_Window(X, Y, l), icon(10, 10, 50, 50), message(70, 25, 330, 35),
|
|
dial(277, 70, 23, 23), button(309, 70, 90, 23, "Close"), resize_box(399, 26, 1, 1)
|
|
{
|
|
end();
|
|
|
|
icon.image(new Fl_Pixmap(dialog_information_48_icon));
|
|
|
|
message.type(FL_MULTILINE_OUTPUT);
|
|
message.box(FL_FLAT_BOX);
|
|
message.color(FL_BACKGROUND_COLOR);
|
|
|
|
button.callback(button_cb);
|
|
newx = button.x();
|
|
|
|
dial.box(FL_FLAT_BOX);
|
|
dial.type(FL_FILL_DIAL);
|
|
dial.selection_color(adjust_color(fl_lighter(FL_BACKGROUND_COLOR), FL_BACKGROUND_COLOR));
|
|
dial.angle1(180);
|
|
dial.angle2(-180);
|
|
dial.minimum(0.0);
|
|
|
|
xclass(PACKAGE_TARNAME);
|
|
resizable(resize_box);
|
|
}
|
|
notify_dialog::~notify_dialog()
|
|
{
|
|
delete icon.image();
|
|
Fl::remove_timeout(dial_timer, &dial);
|
|
}
|
|
int notify_dialog::handle(int event)
|
|
{
|
|
if (event == FL_HIDE && delete_on_hide) {
|
|
Fl::delete_widget(this);
|
|
return 1;
|
|
}
|
|
else if (event == FL_PUSH) {
|
|
dial.hide();
|
|
return Fl_Window::handle(event);
|
|
}
|
|
return Fl_Window::handle(event);
|
|
}
|
|
|
|
void notify_dialog::button_cb(Fl_Widget* w, void*)
|
|
{
|
|
w->window()->hide();
|
|
}
|
|
void notify_dialog::dial_timer(void* arg)
|
|
{
|
|
Fl_Dial* dial = reinterpret_cast<Fl_Dial*>(arg);
|
|
double v = dial->value();
|
|
if (!dial->visible())
|
|
return;
|
|
if (v == dial->minimum())
|
|
return dial->window()->hide();
|
|
dial->value(dial->clamp(v - 0.05));
|
|
return Fl::repeat_timeout(0.05, dial_timer, arg);
|
|
}
|
|
|
|
Fl_Button* notify_dialog::make_button(int W, int H)
|
|
{
|
|
Fl_Group* cur = Fl_Group::current();
|
|
Fl_Group::current(this);
|
|
Fl_Button* b = 0;
|
|
|
|
int pad = 10;
|
|
int X = newx - pad - W;
|
|
if (X - pad - dial.w() > 0) {
|
|
b = new Fl_Button(newx = X, button.y(), W, H);
|
|
dial.position(b->x() - dial.w() - pad, dial.y());
|
|
}
|
|
|
|
Fl_Group::current(cur);
|
|
return b;
|
|
}
|
|
|
|
void notify_dialog::notify(const char* msg, double timeout, bool delete_on_hide_)
|
|
{
|
|
delete_on_hide = delete_on_hide_;
|
|
message.value(msg);
|
|
const char* p;
|
|
if ((p = strchr(msg, '\n'))) { // use first line as label
|
|
string l(msg, p - msg);
|
|
copy_label(l.c_str());
|
|
}
|
|
else
|
|
label("Notification");
|
|
|
|
fl_font(message.textfont(), message.textsize());
|
|
int H = 0;
|
|
for (const char* p = msg; (p = strchr(p, '\n')); p++)
|
|
H++;
|
|
size(w(), h() + max(H - 1, 0) * fl_height());
|
|
|
|
if (timeout > 0.0) {
|
|
dial.maximum(timeout);
|
|
dial.value(timeout);
|
|
dial.show();
|
|
Fl::add_timeout(0.0, dial_timer, &dial);
|
|
}
|
|
else
|
|
dial.hide();
|
|
button.take_focus();
|
|
show();
|
|
}
|
|
|
|
// =============================================================================
|
|
|
|
#ifdef BUILD_FLDIGI
|
|
|
|
#include "icons.h"
|
|
#include "gettext.h"
|
|
|
|
Mode_Browser::Mode_Browser(void)
|
|
: Fl_Double_Window(170, 460), changed_cb(NULL), changed_args(NULL)
|
|
{
|
|
int bw = 80, bh = 20, pad = 2;
|
|
|
|
modes = new Fl_Check_Browser(pad, pad, w() - pad, h() - 2 * (bh + 2 * pad));
|
|
for (int i = 0; i < NUM_MODES; i++)
|
|
modes->add(mode_info[i].name);
|
|
modes->callback(modes_cb, this);
|
|
modes->when(FL_WHEN_CHANGED);
|
|
|
|
all_button = new Fl_Button(modes->x(), modes->y() + modes->h() + pad,
|
|
bw, bh, _("Select All"));
|
|
all_button->callback(button_cb, this);
|
|
|
|
none_button = new Fl_Button(all_button->x(), all_button->y() + all_button->h() + pad,
|
|
all_button->w(), all_button->h(), _("Clear All"));
|
|
none_button->callback(button_cb, this);
|
|
|
|
close_button = new Fl_Button(w() - none_button->w() - pad, none_button->y(),
|
|
none_button->w(), none_button->h(),
|
|
icons::make_icon_label(_("Close"), close_icon));
|
|
icons::set_icon_label(close_button);
|
|
close_button->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
|
|
close_button->callback(button_cb, this);
|
|
|
|
end();
|
|
resizable(modes);
|
|
xclass(PACKAGE_TARNAME);
|
|
}
|
|
|
|
Mode_Browser::~Mode_Browser(void)
|
|
{
|
|
icons::free_icon_label(close_button);
|
|
delete close_button;
|
|
delete all_button;
|
|
delete none_button;
|
|
delete modes;
|
|
}
|
|
|
|
void Mode_Browser::show(mode_set_t* b)
|
|
{
|
|
store = b;
|
|
modes->check_none();
|
|
for (size_t i = 0; i < b->size(); i++)
|
|
modes->checked(i + 1, store->test(i));
|
|
modes->position(0);
|
|
Fl_Double_Window::show();
|
|
}
|
|
|
|
void Mode_Browser::callback(Fl_Callback* cb, void* args)
|
|
{
|
|
changed_cb = cb;
|
|
changed_args = args;
|
|
}
|
|
|
|
void Mode_Browser::modes_cb(Fl_Widget* w, void* arg)
|
|
{
|
|
Mode_Browser* m = static_cast<Mode_Browser*>(arg);
|
|
int sel = m->modes->value();
|
|
m->store->set(sel - 1, m->modes->checked(sel));
|
|
if (m->changed_cb)
|
|
m->changed_cb(m, m->changed_args);
|
|
}
|
|
|
|
void Mode_Browser::button_cb(Fl_Widget* w, void* arg)
|
|
{
|
|
Mode_Browser* m = static_cast<Mode_Browser*>(arg);
|
|
if (w == m->close_button)
|
|
m->hide();
|
|
else {
|
|
if (w == m->all_button) {
|
|
m->store->set();
|
|
m->modes->check_all();
|
|
}
|
|
else {
|
|
m->store->reset();
|
|
m->modes->check_none();
|
|
}
|
|
if (m->changed_cb)
|
|
m->changed_cb(m, m->changed_args);
|
|
}
|
|
}
|
|
|
|
#endif // BUILD_FLDIGI
|