]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/xforms_resize.C
Angus fix for resizing tabfolders on xforms 0.88.
[lyx.git] / src / frontends / xforms / xforms_resize.C
1 /**
2  * \file xforms_resize.C
3  * Copyright 2000-2002 the LyX Team
4  * Read the file COPYING
5  *
6  * \author Angus Leeming, a.leeming@ic.ac.uk
7  */
8
9 #include <config.h>
10
11 #ifdef __GNUG__
12 #pragma implementation
13 #endif
14
15 #include "xforms_resize.h"
16
17 #include "LString.h"
18 #include <algorithm>
19 #include <vector>
20
21 using std::vector;
22
23 namespace {
24
25 // Returns the FL_OBJECT * of class FL_TABFOLDER if present in the form.
26 // Else 0.
27 FL_OBJECT * find_tabfolder(FL_FORM * form);
28
29 // Takes an FL_OBJECT * folder of class FL_TABFOLDER and calculates how much it
30 // should be scaled to display all the tabs.
31 // Returns 1 if the tabs are alll fully visible.
32 // Nested tabfolders are not considered.
33 double scale_to_fit_tabs(FL_OBJECT * folder);
34
35 // Returns the leaves making up a tabfolder.
36 vector<FL_FORM *> const leaves_in_tabfolder(FL_OBJECT * folder);
37
38 // The labels of each tab in the folder.
39 vector<string> const tab_names(FL_OBJECT * folder);
40
41 } // namespace anon
42
43
44 double scale_to_fit_tabs(FL_FORM * form)
45 {
46         if (!form)
47                 return 1;
48
49         FL_OBJECT * folder = find_tabfolder(form);
50         if (!folder)
51                 return 1;
52
53         double scale = scale_to_fit_tabs(folder);
54
55         vector<FL_FORM *> const leaves = leaves_in_tabfolder(folder);
56         vector<FL_FORM *>::const_iterator it  = leaves.begin();
57         vector<FL_FORM *>::const_iterator end = leaves.end();
58
59         for (; it != end; ++it) {
60                 folder = find_tabfolder(*it);
61                 if (folder)
62                         scale = std::max(scale, scale_to_fit_tabs(folder));
63         }
64
65         return scale;
66 }
67
68
69 void scale_form(FL_FORM * form, double scale_factor)
70 {
71         if (!form)
72                 return;
73
74         fl_scale_form(form, scale_factor, 1);
75
76         FL_OBJECT * folder = find_tabfolder(form);
77         if (!folder)
78                 return;
79
80         vector<FL_FORM *> const leaves = leaves_in_tabfolder(folder);
81         vector<FL_FORM *>::const_iterator it  = leaves.begin();
82         vector<FL_FORM *>::const_iterator end = leaves.end();
83
84         for (; it != end; ++it) {
85                 fl_scale_form(*it, scale_factor, 1);
86         }
87 }
88
89
90 namespace {
91
92 FL_OBJECT * find_tabfolder(FL_FORM * form)
93 {
94         for (FL_OBJECT * ob = form->first; ob; ob = ob->next) {
95                 if (ob->objclass == FL_TABFOLDER)
96                         return ob;
97         }
98
99         return 0;
100 }
101
102
103 // Return the scaling factor needed to render all the tab labels.
104 double scale_to_fit_tabs(FL_OBJECT * folder)
105 {
106         if (folder->objclass != FL_TABFOLDER)
107                 return 1;
108
109         // The problem here is that we can access the names of a tabfolder's
110         // tabs directly (through fl_get_folder_name(folder)), but we
111         // can't access directly the tabs themselves. Nonetheless, they are
112         // made visible as buttons on the parent form, so we can obtain
113         // the style info by a judicious camparison of names. This style info
114         // (label font size, style) is needed to ascertain how much space
115         // the label takes up.
116
117         // The tabfolder makes the tabs (buttons) visible to the parent form,
118         // so to identify them, we need their names.
119         vector<string> const names = tab_names(folder);
120         if (names.empty())
121                 return 1;
122
123         FL_FORM * parent = folder->form;
124         if (!parent)
125                 return 1;
126
127         // Ascertain the style parameters of the tabs.
128         int label_style = FL_BOLD_STYLE;
129         int label_size  = FL_NORMAL_SIZE;
130         int box_width   = 1;
131         // Hard-coded within xforms' fl_create_tabfolder in tabfolder.c.
132         int const tab_padding = 12;
133
134         for (FL_OBJECT * ob = parent->first; ob; ob = ob->next) {
135                 if (!ob->label)
136                         continue;
137
138                 vector<string>::const_iterator it  = names.begin();
139                 vector<string>::const_iterator end = names.end();
140                 it = std::find(it, end, ob->label);
141
142                 if (it == end)
143                         continue;
144
145                 label_style = ob->lstyle;
146                 label_size  = ob->lsize;
147
148                 if (ob->boxtype == FL_UP_BOX || ob->boxtype == FL_DOWN_BOX)
149                         box_width = FL_abs(ob->bw);
150
151                 // achieved all we set out to achieve, so break.
152                 break;
153         }
154         // Hard coded in xforms' get_tabsize in tabfolder.c as
155         // (2 + fudge) * box_width, where fudge is always 1.
156         int const box_width_factor = 3 * box_width;
157
158         // Loop over the names and calculate how much space is needed to display
159         // them.
160         int length = 0;
161
162         vector<string>::const_iterator it  = names.begin();
163         vector<string>::const_iterator end = names.end();
164
165         for (; it != end; ++it) {
166                 int sw, sh;
167
168                 fl_get_string_dimension(label_style, label_size,
169                                         it->c_str(), int(it->size()),
170                                         &sw, &sh);
171
172                 // This is the minimum width the object must be to contain
173                 // the label
174                 length += sw + tab_padding + box_width_factor;
175         }
176
177         // Compare this length to the width of the tabfolder
178         double const scale = double(length) / double(folder->w);
179         return std::max(double(1), scale);
180 }
181
182
183 // A nasty hack for older xforms versions
184 int get_tabfolder_numfolders(FL_OBJECT * folder)
185 {
186 #if FL_REVISION > 88
187         return fl_get_tabfolder_numfolders(folder);
188 #else
189         if (folder->objclass != FL_TABFOLDER)
190                 return 0;
191
192         fl_freeze_form(folder->form);
193         int const saved_folder_id = fl_get_folder_number(folder);
194
195         int num_folders = 0;
196         FL_FORM const * old_leaf = 0;
197         for (;;) {
198                 int const id = num_folders + 1;
199                 fl_set_folder_bynumber(folder, id);
200                 FL_FORM const * const leaf = fl_get_folder(folder);
201                 if (!leaf || leaf == old_leaf) {
202                         // unable to increment succesfully.
203                         break;
204                 }
205                 old_leaf = leaf;
206                 ++num_folders;
207         }
208
209         fl_set_folder_bynumber(folder, saved_folder_id);
210         fl_unfreeze_form(folder->form);
211
212         return num_folders;
213 #endif
214 }
215
216
217 // Returns the leaves making up a tabfolder.
218 vector<FL_FORM *> const leaves_in_tabfolder(FL_OBJECT * folder)
219 {
220         if (folder->objclass != FL_TABFOLDER)
221                 return vector<FL_FORM *>();
222
223         fl_freeze_form(folder->form);
224         int const saved_folder_id = fl_get_folder_number(folder);
225
226         int const size = get_tabfolder_numfolders(folder);
227         vector<FL_FORM *> leaves(size);
228
229         for (int i = 0; i < size; ++i) {
230                 fl_set_folder_bynumber(folder, i+1);
231                 leaves[i] = fl_get_folder(folder);
232         }
233
234         fl_set_folder_bynumber(folder, saved_folder_id);
235         fl_unfreeze_form(folder->form);
236
237         return leaves;
238 }
239
240
241 // The labels of each tab in the folder.
242 vector<string> const tab_names(FL_OBJECT * folder)
243 {
244         if (folder->objclass != FL_TABFOLDER)
245                 return vector<string>();
246
247         fl_freeze_form(folder->form);
248         int const saved_folder_id = fl_get_folder_number(folder);
249
250         int const size = get_tabfolder_numfolders(folder);
251         vector<string> names(size);
252
253         for (int i = 0; i < size; ++i) {
254                 fl_set_folder_bynumber(folder, i+1);
255
256                 char const * const name = fl_get_folder_name(folder);
257                 if (name)
258                         names[i] = name;
259         }
260
261         fl_set_folder_bynumber(folder, saved_folder_id);
262         fl_unfreeze_form(folder->form);
263
264         return names;
265 }
266
267 } // namespace anon