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