From 38b1890429d90c7bd08f2ba6b3ec2a844e7da01e Mon Sep 17 00:00:00 2001 From: Angus Leeming Date: Wed, 8 May 2002 17:52:02 +0000 Subject: [PATCH] Prevent crashes experienced by speakers of "long" languages like Norwegian and German when they select a tab of some tabbed-folder that is only partly displayed. Of course, the crash no longer happens with xforms 0.9999, but this is still the elegant thing to do. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4141 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/frontends/xforms/ChangeLog | 12 ++ src/frontends/xforms/FormBase.C | 5 + src/frontends/xforms/FormBaseDeprecated.C | 5 + src/frontends/xforms/Makefile.am | 2 + src/frontends/xforms/xforms_resize.C | 235 ++++++++++++++++++++++ src/frontends/xforms/xforms_resize.h | 33 +++ 6 files changed, 292 insertions(+) create mode 100644 src/frontends/xforms/xforms_resize.C create mode 100644 src/frontends/xforms/xforms_resize.h diff --git a/src/frontends/xforms/ChangeLog b/src/frontends/xforms/ChangeLog index ed2d6dcca0..73cd458f11 100644 --- a/src/frontends/xforms/ChangeLog +++ b/src/frontends/xforms/ChangeLog @@ -1,3 +1,15 @@ +2002-05-06 Angus Leeming + + * FormBase.C (show): + * FormBaseDeprecated.C (show): having built the dialog, ensure that the + tabs of any tabbed-folders are sufficiently lengthened to be displayed + whole. This is more than just cosmetic as it will prevent crashes + when a partly displayed tab is selected (xforms < 0.9999). + + * xforms_resize.[Ch]: new files doing the grunt work of ascertaining + by how much a dialog should be scaled to show its tabs fully (should + it have a tabfolder). + 2002-05-08 Garst Reese * FormMathsDeco.C: fix offset to normal size decos. diff --git a/src/frontends/xforms/FormBase.C b/src/frontends/xforms/FormBase.C index 52a9572b01..b9c70fa0ae 100644 --- a/src/frontends/xforms/FormBase.C +++ b/src/frontends/xforms/FormBase.C @@ -15,6 +15,7 @@ #include "Dialogs.h" #include "FormBase.h" #include "xformsBC.h" +#include "xforms_resize.h" #include "GUIRunTime.h" #include "Tooltips.h" #include "support/LAssert.h" @@ -65,6 +66,10 @@ void FormBase::show() // use minw_ to flag whether the dialog has ever been shown // (Needed now that build() is/should be called from the controller) if (minw_ == 0) { + double const scale = scale_to_fit_tabs(form()); + if (scale > 1.001) + scale_form(form(), scale); + bc().refresh(); // work around dumb xforms sizing bug diff --git a/src/frontends/xforms/FormBaseDeprecated.C b/src/frontends/xforms/FormBaseDeprecated.C index f04ee4b686..41c808f0c4 100644 --- a/src/frontends/xforms/FormBaseDeprecated.C +++ b/src/frontends/xforms/FormBaseDeprecated.C @@ -15,6 +15,7 @@ #include "Dialogs.h" #include "FormBaseDeprecated.h" #include "xformsBC.h" +#include "xforms_resize.h" #include "GUIRunTime.h" #include "Tooltips.h" #include "LyXView.h" @@ -83,6 +84,10 @@ void FormBaseDeprecated::show() if (!form()) { build(); + double const scale = scale_to_fit_tabs(form()); + if (scale > 1.001) + scale_form(form(), scale); + bc().refresh(); // work around dumb xforms sizing bug diff --git a/src/frontends/xforms/Makefile.am b/src/frontends/xforms/Makefile.am index 276d2ecc77..09ed9db497 100644 --- a/src/frontends/xforms/Makefile.am +++ b/src/frontends/xforms/Makefile.am @@ -210,6 +210,8 @@ libxforms_la_SOURCES = \ Tooltips.h \ xforms_helpers.C \ xforms_helpers.h \ + xforms_resize.C \ + xforms_resize.h \ $(XFORMSGIMAGE) xformsBC.C \ xformsBC.h diff --git a/src/frontends/xforms/xforms_resize.C b/src/frontends/xforms/xforms_resize.C new file mode 100644 index 0000000000..e5816b82f4 --- /dev/null +++ b/src/frontends/xforms/xforms_resize.C @@ -0,0 +1,235 @@ +/** + * \file xforms_resize.C + * Copyright 2000-2002 the LyX Team + * Read the file COPYING + * + * \author Angus Leeming, a.leeming@ic.ac.uk + */ + +#include + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include "xforms_resize.h" + +#include "LString.h" +#include +#include + +using std::vector; + +namespace { + +// Returns the FL_OBJECT * of class FL_TABFOLDER if present in the form. +// Else 0. +FL_OBJECT * find_tabfolder(FL_FORM * form); + +// Takes an FL_OBJECT * folder of class FL_TABFOLDER and calculates how much it +// should be scaled to display all the tabs. +// Returns 1 if the tabs are alll fully visible. +// Nested tabfolders are not considered. +double scale_to_fit_tabs(FL_OBJECT * folder); + +// Returns the leaves making up a tabfolder. +vector const leaves_in_tabfolder(FL_OBJECT * folder); + +// The labels of each tab in the folder. +vector const tab_names(FL_OBJECT * folder); + +} // namespace anon + + +double scale_to_fit_tabs(FL_FORM * form) +{ + if (!form) + return 1; + + FL_OBJECT * folder = find_tabfolder(form); + if (!folder) + return 1; + + double scale = scale_to_fit_tabs(folder); + + vector const leaves = leaves_in_tabfolder(folder); + vector::const_iterator it = leaves.begin(); + vector::const_iterator end = leaves.end(); + + for (; it != end; ++it) { + folder = find_tabfolder(*it); + if (!folder) + continue; + double folder_scale = scale_to_fit_tabs(folder); + scale = std::max(scale, folder_scale); + } + + return scale; +} + + +void scale_form(FL_FORM * form, double scale_factor) +{ + if (!form) + return; + + fl_scale_form(form, scale_factor, 1); + + FL_OBJECT * folder = find_tabfolder(form); + if (!folder) + return; + + vector const leaves = leaves_in_tabfolder(folder); + vector::const_iterator it = leaves.begin(); + vector::const_iterator end = leaves.end(); + + for (; it != end; ++it) { + fl_scale_form(*it, scale_factor, 1); + } +} + + +namespace { + +FL_OBJECT * find_tabfolder(FL_FORM * form) +{ + for (FL_OBJECT * ob = form->first; ob; ob = ob->next) { + if (ob->objclass == FL_TABFOLDER) + return ob; + } + + return 0; +} + + +// Return the scaling factor needed to render all the tab labels. +double scale_to_fit_tabs(FL_OBJECT * folder) +{ + if (folder->objclass != FL_TABFOLDER) + return 1; + + // The problem here is that we can access the names of a tabfolder's + // tabs directly (through fl_get_folder_name(folder)), but we + // can't access directly the tabs themselves. Nonetheless, they are + // made visible as buttons on the parent form, so we can obtain + // the style info by a judicious camparison of names. This style info + // (label font size, style) is needed to ascertain how much space + // the label takes up. + + // The tabfolder makes the tabs (buttons) visible to the parent form, + // so to identify them, we need their names. + vector const names = tab_names(folder); + if (names.empty()) + return 1; + + FL_FORM * parent = folder->form; + if (!parent) + return 1; + + // Ascertain the style parameters of the tabs. + int label_style = FL_BOLD_STYLE; + int label_size = FL_NORMAL_SIZE; + int box_width = 1; + // Hard-coded within xforms' fl_create_tabfolder in tabfolder.c. + int const tab_padding = 12; + + for (FL_OBJECT * ob = parent->first; ob; ob = ob->next) { + if (!ob->label) + continue; + + vector::const_iterator it = names.begin(); + vector::const_iterator end = names.end(); + it = std::find(it, end, ob->label); + + if (it == end) + continue; + + label_style = ob->lstyle; + label_size = ob->lsize; + + if (ob->boxtype == FL_UP_BOX || ob->boxtype == FL_DOWN_BOX) + box_width = FL_abs(ob->bw); + + // achieved all we set out to achieve, so break. + break; + } + // Hard coded in xforms' get_tabsize in tabfolder.c as + // (2 + fudge) * box_width, where fudge is always 1. + int const box_width_factor = 3 * box_width; + + // Loop over the names and calculate how much space is needed to display + // them. + int length = 0; + + vector::const_iterator it = names.begin(); + vector::const_iterator end = names.end(); + + for (; it != end; ++it) { + int sw, sh; + + fl_get_string_dimension(label_style, label_size, + it->c_str(), int(it->size()), + &sw, &sh); + + // This is the minimum width the object must be to contain + // the label + length += sw + tab_padding + box_width_factor; + } + + // Compare this length to the width of the tabfolder + double scale = double(length) / double(folder->w); + return std::max(double(1), scale); +} + + +// Returns the leaves making up a tabfolder. +vector const leaves_in_tabfolder(FL_OBJECT * folder) +{ + if (folder->objclass != FL_TABFOLDER) + return vector(); + + fl_freeze_form(folder->form); + int const folder_id = fl_get_folder_number(folder); + + int const size = fl_get_tabfolder_numfolders(folder); + vector leaves(size); + + for (int i = 0; i < size; ++i) { + fl_set_folder_bynumber(folder, i+1); + leaves[i] = fl_get_folder(folder); + } + + fl_set_folder_bynumber(folder, folder_id); + fl_unfreeze_form(folder->form); + + return leaves; +} + + +// The labels of each tab in the folder. +vector const tab_names(FL_OBJECT * folder) +{ + if (folder->objclass != FL_TABFOLDER) + return vector(); + + fl_freeze_form(folder->form); + int const folder_id = fl_get_folder_number(folder); + + int const size = fl_get_tabfolder_numfolders(folder); + vector names(size); + + for (int i = 0; i < size; ++i) { + fl_set_folder_bynumber(folder, i+1); + + const char * const name = fl_get_folder_name(folder); + if (name) + names[i] = name; + } + + fl_set_folder_bynumber(folder, folder_id); + fl_unfreeze_form(folder->form); + + return names; +} + +} // namespace anon diff --git a/src/frontends/xforms/xforms_resize.h b/src/frontends/xforms/xforms_resize.h new file mode 100644 index 0000000000..6174a61837 --- /dev/null +++ b/src/frontends/xforms/xforms_resize.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +/** + * \file xforms_resize.h + * Copyright 2000-2002 the LyX Team + * Read the file COPYING + * + * \author Angus Leeming, a.leeming@ic.ac.uk + */ + +#ifndef XFORMS_RESIZE_H +#define XFORMS_RESIZE_H + +#ifdef __GNUG__ +#pragma interface +#endif + +#include FORMS_H_LOCATION + +/** Returns 1 if the form does not contain a tabfolder. + If it does contain a tabfolder, then by how much should the form be + scaled to render the tabs (buttons) visible. + + This routine works for two levels of nested tabfolders. + */ +double scale_to_fit_tabs(FL_FORM * form); + +/** A wrapper for fl_scale_form(form, scale, 1) that scales the parent form + horizontally, but also scales the leaves (FL_FORMs) of the tabfolder, + should one exist. + */ +void scale_form(FL_FORM * form, double scale_factor); + +#endif // XFORMS_RESIZE_H -- 2.39.2