From 0a6bcade1c600604cf5ff43572fcdf00c1ac4058 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 14 Jan 2022 14:07:19 +0100 Subject: [PATCH] Change to modern layout in options dialog Classical tabs are very dated. They are also a practical problem as you get very limited in the numbers of tabs we can have, and how long the text can be on them. Switch to one popular modern model with a list on the left instead where pages can be selected. --- vncviewer/CMakeLists.txt | 1 + vncviewer/OptionsDialog.cxx | 24 ++-- vncviewer/fltk/Fl_Navigation.cxx | 198 +++++++++++++++++++++++++++++++ vncviewer/fltk/Fl_Navigation.h | 58 +++++++++ vncviewer/fltk/layout.h | 3 - 5 files changed, 273 insertions(+), 11 deletions(-) create mode 100644 vncviewer/fltk/Fl_Navigation.cxx create mode 100644 vncviewer/fltk/Fl_Navigation.h diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt index 0e1b27b8..1a4f9f13 100644 --- a/vncviewer/CMakeLists.txt +++ b/vncviewer/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories(${CMAKE_SOURCE_DIR}/common) add_executable(vncviewer fltk/Fl_Monitor_Arrangement.cxx + fltk/Fl_Navigation.cxx fltk/theme.cxx menukey.cxx BaseTouchHandler.cxx diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx index 22224a9b..dcb8ca09 100644 --- a/vncviewer/OptionsDialog.cxx +++ b/vncviewer/OptionsDialog.cxx @@ -43,6 +43,7 @@ #include "fltk/layout.h" #include "fltk/util.h" #include "fltk/Fl_Monitor_Arrangement.h" +#include "fltk/Fl_Navigation.h" #include #include @@ -62,19 +63,26 @@ std::map OptionsDialog::callbacks; static std::set instances; OptionsDialog::OptionsDialog() - : Fl_Window(450, 460, _("VNC Viewer: Connection Options")) + : Fl_Window(580, 420, _("TigerVNC Options")) { int x, y; + Fl_Navigation *navigation; Fl_Button *button; - Fl_Tabs *tabs = new Fl_Tabs(OUTER_MARGIN, OUTER_MARGIN, - w() - OUTER_MARGIN*2, - h() - OUTER_MARGIN*2 - INNER_MARGIN - BUTTON_HEIGHT); - + // Odd dimensions to get rid of extra borders + // FIXME: We need to retain the top border on Windows as they don't + // have any separator for the caption, which looks odd +#ifdef WIN32 + navigation = new Fl_Navigation(-1, 0, w()+2, + h() - INNER_MARGIN - BUTTON_HEIGHT - OUTER_MARGIN); +#else + navigation = new Fl_Navigation(-1, -1, w()+2, + h()+1 - INNER_MARGIN - BUTTON_HEIGHT - OUTER_MARGIN); +#endif { int tx, ty, tw, th; - tabs->client_area(tx, ty, tw, th, TABS_HEIGHT); + navigation->client_area(tx, ty, tw, th, 150); createCompressionPage(tx, ty, tw, th); createSecurityPage(tx, ty, tw, th); @@ -83,7 +91,7 @@ OptionsDialog::OptionsDialog() createMiscPage(tx, ty, tw, th); } - tabs->end(); + navigation->end(); x = w() - BUTTON_WIDTH * 2 - INNER_MARGIN - OUTER_MARGIN; y = h() - BUTTON_HEIGHT - OUTER_MARGIN; @@ -1006,7 +1014,7 @@ void OptionsDialog::createDisplayPage(int tx, int ty, int tw, int th) void OptionsDialog::createMiscPage(int tx, int ty, int tw, int th) { - Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Misc.")); + Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Miscellaneous")); tx += OUTER_MARGIN; ty += OUTER_MARGIN; diff --git a/vncviewer/fltk/Fl_Navigation.cxx b/vncviewer/fltk/Fl_Navigation.cxx new file mode 100644 index 00000000..603c69ce --- /dev/null +++ b/vncviewer/fltk/Fl_Navigation.cxx @@ -0,0 +1,198 @@ +/* Copyright 2022 Pierre Ossman for Cendio AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include "Fl_Navigation.h" + +Fl_Navigation::Fl_Navigation(int x, int y, int w, int h) + : Fl_Group(x, y, w, h) +{ + int dummy; + + scroll = new Fl_Scroll(x, y, 1, 1); + scroll->type(Fl_Scroll::VERTICAL); + scroll->color(FL_BACKGROUND2_COLOR); + + labels = new Fl_Group(x, y, 1, 1); + labels->end(); + + scroll->end(); + + pages = new Fl_Group(x, y, 1, 1); + pages->end(); + + Fl_Group::end(); + + // Just to resize things, and avoid code duplication + client_area(dummy, dummy, dummy, dummy, w/10); + + begin(); +} + +Fl_Navigation::~Fl_Navigation() +{ +} + +Fl_Widget *Fl_Navigation::value() +{ + int i; + + for (i = 0;i < pages->children();i++) { + if (pages->child(i)->visible()) + return pages->child(i); + } + + return NULL; +} + +int Fl_Navigation::value(Fl_Widget *newpage) +{ + int i; + int found; + + assert(labels->children() == pages->children()); + + found = 0; + for (i = 0;i < pages->children();i++) { + if (pages->child(i) == newpage) { + pages->child(i)->show(); + ((Fl_Button*)labels->child(i))->setonly(); + found = 1; + } else { + pages->child(i)->hide(); + } + } + + return found; +} + +void Fl_Navigation::client_area(int &rx, int &ry, + int &rw, int &rh, int lw) +{ + if (!pages->children()) { + int cx, cy, cw, ch; + + cx = x() + 1; + cy = y() + 1; + cw = w() - 2; + ch = h() - 2; + + scroll->resize(cx, cy, lw, ch); + labels->resize(cx, cy, lw, ch); + pages->resize(cx + lw + 1, cy, cw - lw - 1, ch); + } + + rx = pages->x(); + ry = pages->y(); + rw = pages->w(); + rh = pages->h(); +} + +void Fl_Navigation::draw() +{ + draw_box(FL_BORDER_FRAME, x(), y(), + labels->w()+2, h(), FL_DARK3); + draw_box(FL_BORDER_FRAME, x()+1+labels->w(), y(), + w() - (labels->w()+1), h(), FL_DARK3); + Fl_Group::draw(); +} + +void Fl_Navigation::begin() +{ + pages->begin(); +} + +void Fl_Navigation::end() +{ + pages->end(); + Fl_Group::end(); + + update_labels(); +} + +void Fl_Navigation::update_labels() +{ + int i, offset; + + labels->clear(); + labels->resizable(NULL); + + if (!pages->children()) + return; + + offset = 0; + for (i = 0;i < pages->children();i++) { + Fl_Widget *page; + Fl_Button *btn; + + page = pages->child(i); + + btn = new Fl_Button(labels->x(), labels->y() + offset, + labels->w(), page->labelsize() * 3, + page->label()); + btn->box(FL_FLAT_BOX); + btn->type(FL_RADIO_BUTTON); + btn->color(FL_BACKGROUND2_COLOR); + btn->selection_color(FL_SELECTION_COLOR); + btn->labelsize(page->labelsize()); + btn->labelfont(page->labelfont()); + btn->image(page->image()); + btn->deimage(page->deimage()); + btn->callback(label_pressed, this); + + labels->add(btn); + offset += page->labelsize() * 3; + } + labels->size(labels->w(), offset); + + // FIXME: Retain selection + value(pages->child(0)); +} + +void Fl_Navigation::label_pressed(Fl_Widget *widget, void *user_data) +{ + Fl_Navigation *self = (Fl_Navigation *) user_data; + + int i, idx; + + idx = -1; + for (i = 0;i < self->labels->children();i++) { + if (self->labels->child(i) == widget) + idx = i; + } + + assert(idx >= 0); + assert(idx < self->pages->children()); + + self->value(self->pages->child(idx)); +} diff --git a/vncviewer/fltk/Fl_Navigation.h b/vncviewer/fltk/Fl_Navigation.h new file mode 100644 index 00000000..7f5e44ac --- /dev/null +++ b/vncviewer/fltk/Fl_Navigation.h @@ -0,0 +1,58 @@ +/* Copyright 2022 Pierre Ossman for Cendio AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __FL_NAVIGATION_H__ +#define __FL_NAVIGATION_H__ + +#include + +class Fl_Scroll; + +class Fl_Navigation: private Fl_Group { +public: + Fl_Navigation(int x, int y, int w, int h); + ~Fl_Navigation(); + + Fl_Widget *value(); + int value(Fl_Widget*); + + void client_area(int &rx, int &ry, int &rw, int &rh, int lw); + + virtual void draw(); + + // Delegation to underlying widget + void begin(); + void end(); + +private: + void update_labels(); + + static void label_pressed(Fl_Widget *widget, void *user_data); + +private: + Fl_Scroll *scroll; + Fl_Group *labels; + Fl_Group *pages; +}; + +#endif diff --git a/vncviewer/fltk/layout.h b/vncviewer/fltk/layout.h index ae716e1a..31d6a650 100644 --- a/vncviewer/fltk/layout.h +++ b/vncviewer/fltk/layout.h @@ -51,9 +51,6 @@ static inline int gui_str_len(const char *str) /**** FLTK WIDGETS ****/ -/* Fl_Tabs */ -#define TABS_HEIGHT 30 - /* Fl_Input */ #define INPUT_LABEL_OFFSET FL_NORMAL_SIZE #define INPUT_HEIGHT 25 -- 2.39.5