]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/xforms_resize.C
fix crash with "save as"
[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 #include "support/LAssert.h"
19 #include <algorithm> // std::max. Use FL_max in .c code...
20 #include FORMS_H_LOCATION
21
22 namespace {
23
24 /* This is hacked straight out of the xforms source.
25    It is fl_adjust_form_size without the last few lines that do the
26    adjusting.
27  */
28 double get_scaling_factor(FL_FORM * form)
29 {
30     FL_OBJECT *ob;
31     float xfactor, yfactor, max_factor, factor;
32     int sw, sh, osize;
33     float xm = 0.5f, ym = 0.5f;
34     int bw;
35
36 //      if (fl_no_connection)
37 //      return 1.0f;
38
39     max_factor = factor = 1.0f;
40     for (ob = form->first; ob; ob = ob->next)
41     {
42         if ((ob->align == FL_ALIGN_CENTER || (ob->align & FL_ALIGN_INSIDE) ||
43              ob->objclass == FL_INPUT) &&
44             !ob->is_child && *(ob->label) && ob->label[0] != '@' &&
45             ob->boxtype != FL_NO_BOX &&
46             (ob->boxtype != FL_FLAT_BOX || ob->objclass == FL_MENU))
47         {
48             fl_get_string_dimension(ob->lstyle, ob->lsize, ob->label,
49                        strlen(ob->label), &sw, &sh);
50
51             bw = (ob->boxtype == FL_UP_BOX || ob->boxtype == FL_DOWN_BOX) ?
52                 FL_abs(ob->bw) : 1;
53
54             if (ob->objclass == FL_BUTTON &&
55                 (ob->type == FL_RETURN_BUTTON || ob->type == FL_MENU_BUTTON))
56                 sw += FL_min(0.6f * ob->h, 0.6f * ob->w) - 1;
57
58             if (ob->objclass == FL_BUTTON && ob->type == FL_LIGHTBUTTON)
59                 sw += FL_LIGHTBUTTON_MINSIZE + 1;
60
61             if (sw <= (ob->w - 2 * (bw + xm)) && sh <= (ob->h - 2 * (bw + ym)))
62                 continue;
63
64             if ((osize = ob->w - 2 * (bw + xm)) <= 0)
65                 osize = 1;
66             xfactor = (float) sw / (float)osize;
67
68             if ((osize = ob->h - 2 * (bw + ym)) <= 0)
69                 osize = 1;
70             yfactor = (float) sh / osize;
71
72             if (ob->objclass == FL_INPUT)
73             {
74                 xfactor = 1.0f;
75                 yfactor = (sh + 1.6f) / osize;
76             }
77
78             if ((factor = FL_max(xfactor, yfactor)) > max_factor)
79             {
80                 max_factor = factor;
81             }
82         }
83     }
84
85     if (max_factor <= 1.0f)
86         return 1.0f;
87
88     max_factor = 0.01f * (int) (max_factor * 100.0f);
89
90     if (max_factor > 1.25f)
91         max_factor = 1.25f;
92
93     return max_factor;
94 }
95
96
97 // A nasty hack for older xforms versions
98 int get_tabfolder_numfolders(FL_OBJECT * folder)
99 {
100 #if FL_VERSION > 0 || FL_REVISION > 88
101         return fl_get_tabfolder_numfolders(folder);
102 #else
103         if (folder->objclass != FL_TABFOLDER)
104                 return 0;
105
106         fl_freeze_form(folder->form);
107         int const saved_folder_id = fl_get_folder_number(folder);
108
109         int num_folders = 0;
110         FL_FORM const * old_leaf = 0;
111         for (;;) {
112                 int const id = num_folders + 1;
113                 fl_set_folder_bynumber(folder, id);
114                 FL_FORM const * const leaf = fl_get_folder(folder);
115                 if (!leaf || leaf == old_leaf) {
116                         // unable to increment succesfully.
117                         break;
118                 }
119                 old_leaf = leaf;
120                 ++num_folders;
121         }
122
123         fl_set_folder_bynumber(folder, saved_folder_id);
124         fl_unfreeze_form(folder->form);
125
126         return num_folders;
127 #endif
128 }
129
130
131 double get_tabfolder_scale_to_fit(FL_OBJECT * folder)
132 {
133         lyx::Assert(folder && folder->objclass == FL_TABFOLDER);
134
135         fl_freeze_form(folder->form);
136         int const saved_folder_id = fl_get_folder_number(folder);
137
138         double factor = 1.0;
139         int const size = get_tabfolder_numfolders(folder);
140         for (int i = 0; i < size; ++i) {
141                 fl_set_folder_bynumber(folder, i+1);
142                 FL_FORM * leaf = fl_get_folder(folder);
143                 factor = std::max(factor, get_scale_to_fit(leaf));
144         }
145
146         fl_set_folder_bynumber(folder, saved_folder_id);
147         fl_unfreeze_form(folder->form);
148
149         return factor;
150 }
151
152
153 void scale_tabfolder_horizontally(FL_OBJECT * folder, double factor)
154 {
155         lyx::Assert(folder && folder->objclass == FL_TABFOLDER);
156
157         fl_freeze_form(folder->form);
158         int const saved_folder_id = fl_get_folder_number(folder);
159
160         int const size = get_tabfolder_numfolders(folder);
161         for (int i = 0; i < size; ++i) {
162                 fl_set_folder_bynumber(folder, i+1);
163                 FL_FORM * leaf = fl_get_folder(folder);
164                 scale_form_horizontally(leaf, factor);
165         }
166
167         fl_set_folder_bynumber(folder, saved_folder_id);
168         fl_unfreeze_form(folder->form);
169 }
170
171 } // namespace anon
172
173
174 double get_scale_to_fit(FL_FORM * form)
175 {
176         lyx::Assert(form);
177
178         double factor = get_scaling_factor(form);
179         for (FL_OBJECT * ob = form->first; ob; ob = ob->next) {
180                 if (ob->objclass == FL_TABFOLDER)
181                         factor = std::max(factor,
182                                           get_tabfolder_scale_to_fit(ob));
183         }
184         return factor;
185 }
186
187
188 void scale_form_horizontally(FL_FORM * form, double factor)
189 {
190         lyx::Assert(form);
191
192         if (factor <= 1.0)
193                 return;
194
195         fl_scale_form(form, factor, 1);
196
197         for (FL_OBJECT * ob = form->first; ob; ob = ob->next) {
198                 if (ob->objclass == FL_TABFOLDER)
199                         scale_tabfolder_horizontally(ob, factor);
200         }
201 }