]> git.lyx.org Git - lyx.git/commitdiff
Prevent crashes experienced by speakers of "long" languages like Norwegian
authorAngus Leeming <leeming@lyx.org>
Wed, 8 May 2002 17:52:02 +0000 (17:52 +0000)
committerAngus Leeming <leeming@lyx.org>
Wed, 8 May 2002 17:52:02 +0000 (17:52 +0000)
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
src/frontends/xforms/FormBase.C
src/frontends/xforms/FormBaseDeprecated.C
src/frontends/xforms/Makefile.am
src/frontends/xforms/xforms_resize.C [new file with mode: 0644]
src/frontends/xforms/xforms_resize.h [new file with mode: 0644]

index ed2d6dcca023933d89cf3d2cf346d72069eb0a0c..73cd458f116475357a011c3bddf410eda16916f0 100644 (file)
@@ -1,3 +1,15 @@
+2002-05-06  Angus Leeming  <a.leeming@ic.ac.uk>
+
+       * 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  <reese@isn.net>
 
        * FormMathsDeco.C: fix offset to normal size decos.
index 52a9572b01e05666a941fe0a33c8b232e34bd4a3..b9c70fa0aec4091239d7e6388642d7ef52919248 100644 (file)
@@ -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
index f04ee4b686ea20018a83cc17ea11452ffe183559..41c808f0c425c54fb96a84464d599ccd7cc71c55 100644 (file)
@@ -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
index 276d2ecc77f8190a138da8c7b726602ef4ec6a43..09ed9db497838abeaaced9d880eff3e2385ef279 100644 (file)
@@ -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 (file)
index 0000000..e5816b8
--- /dev/null
@@ -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 <config.h>
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
+#include "xforms_resize.h"
+
+#include "LString.h"
+#include <algorithm>
+#include <vector>
+
+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<FL_FORM *> const leaves_in_tabfolder(FL_OBJECT * folder);
+
+// The labels of each tab in the folder.
+vector<string> 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<FL_FORM *> const leaves = leaves_in_tabfolder(folder);
+       vector<FL_FORM *>::const_iterator it  = leaves.begin();
+       vector<FL_FORM *>::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<FL_FORM *> const leaves = leaves_in_tabfolder(folder);
+       vector<FL_FORM *>::const_iterator it  = leaves.begin();
+       vector<FL_FORM *>::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<string> 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<string>::const_iterator it  = names.begin();
+               vector<string>::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<string>::const_iterator it  = names.begin();
+       vector<string>::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<FL_FORM *> const leaves_in_tabfolder(FL_OBJECT * folder)
+{
+       if (folder->objclass != FL_TABFOLDER)
+               return vector<FL_FORM *>();
+
+       fl_freeze_form(folder->form);
+       int const folder_id = fl_get_folder_number(folder);
+
+       int const size = fl_get_tabfolder_numfolders(folder);
+       vector<FL_FORM *> 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<string> const tab_names(FL_OBJECT * folder)
+{
+       if (folder->objclass != FL_TABFOLDER)
+               return vector<string>();
+
+       fl_freeze_form(folder->form);
+       int const folder_id = fl_get_folder_number(folder);
+
+       int const size = fl_get_tabfolder_numfolders(folder);
+       vector<string> 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 (file)
index 0000000..6174a61
--- /dev/null
@@ -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