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