1%%
2%%  wings_menu_util.erl --
3%%
4%%     Menu utilities and helpers.
5%%
6%%  Copyright (c) 2002-2011 Bjorn Gustavsson
7%%
8%%  See the file "license.terms" for information on usage and redistribution
9%%  of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10%%
11%%     $Id$
12%%
13
14-module(wings_menu_util).
15-export([directions/1,directions/2,scale/1,rotate/1,flatten/0,all_xyz/0,
16	 crossmark/1]).
17
18-include("wings.hrl").
19
20directions(#st{selmode=Mode}) ->
21    fun(B, Ns) ->
22	    dirs(B, Mode, Ns)
23    end.
24
25dirs(1, Mode, Ns) -> dirs_1(Mode, Ns);
26dirs(2, body, [duplicate|_]) -> {body,duplicate};
27dirs(2, body, [move|_]) -> ignore;
28dirs(2, body, [move_light|_]) -> ignore;
29dirs(2, face, [extrude|_]) -> {face,{extrude,{faces,{'ASK',{[axis],[]}}}}};
30dirs(2, face, [extract|_]) -> {face,{extract,{faces,{'ASK',{[axis],[]}}}}};
31dirs(2, _Mode, Ns) ->
32    case magnet_props(normal, Ns) of
33	[] ->
34	    wings_menu:build_command(normal, Ns);
35	Flags ->
36	    wings_menu:build_command({'ASK',{[],[normal],Flags}}, Ns)
37    end;
38dirs(3, face, [extrude|_]) -> {face,{extrude,{region,{'ASK',{[axis],[]}}}}};
39dirs(3, face, [extract|_]) -> {face,{extract,{region,{'ASK',{[axis],[]}}}}};
40dirs(3, _Mode, Ns) ->
41    Flags = magnet_props(some_axis, Ns),
42    wings_menu:build_command({'ASK',{[axis],[],Flags}}, Ns);
43dirs(help, body, [move|_]) ->
44    {?STR(dirs,1,"Move along std. axis"),[],?STR(dirs,2,"Pick axis to move along")};
45dirs(help, _Mode, Ns) -> dirs_help(Ns).
46
47dirs_help([move|_]) ->
48    {?STR(dirs,3,"Move along std. axis"),
49     ?STR(dirs,4,"Move along selection's normal"),
50     ?STR(dirs,5,"Pick axis to move along")};
51dirs_help([extrude,face]) ->
52    {?STR(dirs,6,"Extrude along std. axis"),
53     ?__(18,"Pick axis to extrude each face along"),
54     ?__(19,"Pick axis to extrude each region of faces along")};
55dirs_help([extrude|_]) ->
56    {?STR(dirs,6,"Extrude along std. axis"),
57     ?STR(dirs,7,"Extrude along selection's normal"),
58     ?STR(dirs,8,"Pick axis to extrude along")};
59dirs_help([extract|_]) ->
60    {?STR(dirs,12,"Extract along std. axis"),
61     ?__(20,"Pick axis to extract each face along"),
62     ?__(21,"Pick axis to extract each region of faces along")};
63dirs_help([duplicate|_]) ->
64    {?STR(dirs,15,"Duplicate; move along std. axis"),
65     ?STR(dirs,16,"Duplicate; don't move"),
66     ?STR(dirs,17,"Duplicate; pick axis to move along")};
67dirs_help([shell_extrude|_]) ->
68    {?STR(dirs,22,"Extract Shell and Extrude along std. axis"),
69     ?STR(dirs,23,"Extract Shell and Extrude along selection's normal"),
70     ?STR(dirs,24,"Pick axis to Extract Shell and Extrude along")};
71dirs_help(_) -> "".
72
73dirs_1(body, Ns) -> directions([free,x,y,z], Ns);
74dirs_1(_, Ns) ->
75    directions([normal,free,x,y,z], Ns).
76
77all_xyz() ->
78    [{wings_s:dir(all),all},
79     {wings_s:dir(x),x},
80     {wings_s:dir(y),y},
81     {wings_s:dir(z),z}].
82
83%%%
84%%% Scale sub-menu.
85%%%
86
87scale(#st{selmode=body}) -> adv_scale_1([]);
88scale(_) -> adv_scale_1([magnet]).
89
90adv_scale_1(MagFlags) ->
91    [{?STR(adv_scale_1,1,"Scale Uniform"),{scale,fun(B, Ns) -> uniform_scale(B, Ns, MagFlags) end},
92      [],MagFlags},
93     {?STR(adv_scale_1,2,"Scale Axis"),{scale,fun(B, Ns) -> scale(B, Ns, [], MagFlags) end},
94      [],MagFlags},
95     {?STR(adv_scale_1,3,"Scale Radial"),{scale,fun(B, Ns) -> scale(B, Ns, [radial], MagFlags) end},
96      [],MagFlags}].
97
98uniform_scale(help, _, _) ->
99    ChoosePoint = ?STR(uniform_scale,1,"Choose point to scale from"),
100    {?STR(uniform_scale,2,"Scale uniformly from midpoint of selection"),ChoosePoint,ChoosePoint};
101uniform_scale(1, Ns, Flags) ->
102    wings_menu:build_command({'ASK',{[],[center,uniform],Flags}}, Ns);
103uniform_scale(_, Ns, Flags) ->
104    wings_menu:build_command({'ASK',{[point],[],Flags}}, Ns).
105
106scale(help, _, [radial],_) ->
107    {?STR(scale,1,"Scale outward from std. axis"),
108     ?STR(scale,2,"Pick axis and point to scale from"),
109     ?STR(scale,3,"Pick axis to scale out from")};
110scale(help, _, [], _) ->
111    {?STR(scale,4,"Scale along std. axis"),
112     ?STR(scale,5,"Pick axis and point to scale from"),
113     ?STR(scale,6,"Pick axis to scale along")};
114scale(1, Ns, Flags, _MagFlags) ->
115    [scale_fun(x, Ns, Flags),
116     scale_fun(y, Ns, Flags),
117     scale_fun(z, Ns, Flags),
118     separator,
119     scale_fun(last_axis, Ns, Flags),
120     scale_fun(default_axis, Ns, Flags)];
121scale(2, Ns, Flags, MagFlags) ->
122    wings_menu:build_command({'ASK',{[axis,point],Flags,MagFlags}}, Ns);
123scale(3, Ns, Flags, MagFlags) ->
124    wings_menu:build_command({'ASK',{[axis_point],Flags,MagFlags}}, Ns).
125
126scale_fun(Dir, Names, [radial]) ->
127    scale_fun({radial,Dir}, Names, []);
128scale_fun(Dir, Names, _Flags) ->
129    DirString = wings_s:dir(Dir),
130    F = magnet_scale_rot_fun(Dir, center),
131    Help0 = dir_help(Dir, Names),
132    Help = {Help0,[],?STR(scale_fun,1,"Pick point to scale from")},
133    {DirString,F,Help,magnet_props(Dir, Names)}.
134
135
136
137%%%
138%%% Rotate sub-menu.
139%%%
140
141rotate(#st{selmode=body}) -> rotate_1([]);
142rotate(_) -> rotate_1([magnet]).
143
144rotate_1(Flags) ->
145    {?STR(rotate_1,1,"Rotate"),{rotate,fun rotate/2},[],Flags}.
146
147rotate(help, _) ->
148    {?STR(rotate,1,"Rotate around std. axis"),
149     ?STR(rotate,2,"Pick axis and ref point"),
150     ?STR(rotate,3,"Pick axis to rotate around")};
151rotate(1, [rotate,Mode]=Ns) when Mode == vertex; Mode == body ->
152    rotate_common(Ns);
153rotate(1, Ns) ->
154    [rotate_fun(normal, Ns)|rotate_common(Ns)];
155rotate(2, Ns) ->
156    MagFlags = magnet_props(any, Ns),
157    wings_menu:build_command({'ASK',{[axis,point],[],MagFlags}}, Ns);
158rotate(3, Ns) ->
159    MagFlags = magnet_props(any, Ns),
160    wings_menu:build_command({'ASK',{[axis_point],[],MagFlags}}, Ns).
161
162rotate_common(Ns) ->
163
164    [
165        rotate_fun(free,Ns),
166        rotate_fun(x, Ns),
167        rotate_fun(y, Ns),
168        rotate_fun(z, Ns),
169     separator,
170     rotate_fun(last_axis, Ns),
171     rotate_fun(default_axis, Ns)
172     ].
173
174rotate_fun(Dir, Names) ->
175    DirString = wings_util:cap(wings_s:dir(Dir)),
176    F = magnet_scale_rot_fun(Dir, center),
177    Help0 = dir_help(Dir, Names),
178    Help = {Help0, ?STR(rotate_fun,2,"Through Origin"), ?STR(rotate_fun,1,"Pick point for axis to pass through")},
179    Ps = magnet_props(Dir, Names),
180    {DirString,F,Help,Ps}.
181
182magnet_scale_rot_fun(Vec, Point) ->
183    fun(1, Ns) ->
184            MagFlags = magnet_props(Vec, Ns),
185            wings_menu:build_command({'ASK',{[],[Point,Vec],MagFlags}}, Ns);
186       (2, Ns) ->
187            {Vec1,Point1} =
188            case Vec of
189                x ->  {{1.0,0.0,0.0},{0.0,0.0,0.0}};
190                y ->  {{0.0,1.0,0.0},{0.0,0.0,0.0}};
191                z ->  {{0.0,0.0,1.0},{0.0,0.0,0.0}};
192                _Other -> {_Other,{0.0,0.0,0.0}}
193            end,
194            MagFlags = magnet_props(Vec1, Ns),
195            wings_menu:build_command({'ASK',{[],[Point1,Vec1],MagFlags}}, Ns);
196       (3, Ns) ->
197            MagFlags = magnet_props(Vec, Ns),
198            wings_menu:build_command({'ASK',{[point],[Vec],MagFlags}}, Ns)
199    end.
200
201%%%
202%%% Flatten submenu.
203%%%
204
205flatten() ->
206    {?STR(flatten,1,"Flatten"),{flatten,fun flatten/2}}.
207
208flatten(help, _) ->
209    {?STR(flatten,2,"Flatten to std. planes"),
210     ?STR(flatten,3,"Pick plane and ref point on plane"),
211     ?STR(flatten,4,"Pick plane")};
212flatten(1, [flatten,vertex]) ->
213    %% Vertex mode flatten.
214    flatten_common();
215flatten(1, [flatten,edge]) ->
216    %% Edge mode flatten.
217    [flatten_common()|flatten_edge_loops()];
218flatten(1, _) ->
219    %% Face mode flatten.
220    [flatten_fun(normal)|flatten_common()];
221flatten(2, Ns) ->
222    wings_menu:build_command({'ASK',{[axis,point],[],[]}}, Ns);
223flatten(3, Ns) ->
224    wings_menu:build_command({'ASK',{[axis],[],[]}}, Ns).
225
226flatten_common() ->
227    [flatten_fun(x),
228     flatten_fun(y),
229     flatten_fun(z),
230     separator,
231     flatten_fun(last_axis),
232     flatten_fun(default_axis)].
233
234flatten_fun(Vec) ->
235    flatten_fun_1(Vec, Vec, wings_util:cap(wings_s:dir(Vec))).
236
237flatten_fun_1(Vec, Axis, String) ->
238    F = fun(1, Ns) ->
239		wings_menu:build_command(Vec, Ns);
240	   (2, _Ns) ->
241		ignore;
242	   (3, Ns) ->
243		wings_menu:build_command({'ASK',{[point],[Vec]}}, Ns)
244	end,
245    Help0 = dir_help(Axis, [flatten]),
246    Help = {Help0,[],?STR(flatten_fun_1,1,"Pick point on plane")},
247    {String,F,Help,[]}.
248
249flatten_edge_loops() ->
250    [separator,
251     {?__(1,"Edge Loops"),edge_loop,
252      ?__(2,"Flatten each closed edge loop to its normal")}].
253
254%%%
255%%% General directions.
256%%%
257
258directions([D|Dirs], Ns) ->
259    [direction(D, Ns)|directions(Dirs, Ns)];
260directions([], Ns) ->
261    [separator,
262     direction(last_axis, Ns),
263     direction(default_axis, Ns)].
264
265direction(Dir, [extrude,face]) ->
266    Str  = wings_util:cap(wings_s:dir(Dir)),
267    Help = {dir_help(Dir, [extrude_region]),[],dir_help(Dir, [extrude])},
268    F = fun
269      (1,_Ns) -> {face,{extrude,{region,Dir}}};
270      (3,_Ns) -> {face,{extrude,{faces,Dir}}};
271      (_, _) -> ignore
272    end,
273    {Str,F,Help,[]};
274direction(Dir, [extract,face]) ->
275    Str  = wings_util:cap(wings_s:dir(Dir)),
276    Help = {dir_help(Dir, [extract_region]),[],dir_help(Dir, [extract])},
277    F = fun
278      (1,_Ns) -> {face,{extract,{region,Dir}}};
279      (3,_Ns) -> {face,{extract,{faces,Dir}}};
280      (_, _) -> ignore
281    end,
282    {Str,F,Help,[]};
283direction(Dir, Ns) ->
284    Str  = wings_util:cap(wings_s:dir(Dir)),
285    Help = dir_help(Dir, Ns),
286    Ps = magnet_props(Dir, Ns),
287    {Str,Dir,Help,Ps}.
288
289magnet_props(normal, [rotate|_]) -> [];
290magnet_props(_, [_,body]) -> [];
291magnet_props(_, [move|_]) -> [magnet];
292magnet_props(_, [scale|_]) -> [magnet];
293magnet_props(_, [rotate|_]) -> [magnet];
294magnet_props(_, _) -> [].
295
296dir_help(Axis, Ns) when Axis == x; Axis == y; Axis == z ->
297    dir_help_1(Ns, wings_s:dir_axis(Axis));
298dir_help(last_axis, Ns) ->
299    dir_help_1(Ns, ?STR(dir_help,3,"the last axis"));
300dir_help(default_axis, Ns) ->
301    dir_help_1(Ns, ?STR(dir_help,4,"the default axis"));
302dir_help({radial,Axis}, Ns) ->
303    dir_help_1(Ns, [around|wings_s:dir_axis(Axis)]);
304dir_help(radial_x, Ns) ->
305    dir_help_1(Ns, [around|?STR(dir_help,7,"around") ++ " " ++ wings_s:dir_axis(x)]);
306dir_help(radial_y, Ns) ->
307    dir_help_1(Ns, [around|?STR(dir_help,7,"around") ++ " " ++ wings_s:dir_axis(y)]);
308dir_help(radial_z, Ns) ->
309    dir_help_1(Ns, [around|?STR(dir_help,7,"around") ++ " " ++ wings_s:dir_axis(z)]);
310dir_help(normal, Ns) ->
311    dir_help_1(Ns, [normal|?STR(dir_help,10,"along its normal")]);
312dir_help(free, Ns) ->
313    dir_help_1(Ns, [free|?STR(dir_help,11,"freely in all directions")]);
314dir_help(uniform, [scale|_]) ->
315    ?STR(dir_help,12,"Scale equally in all directions").
316
317%% Normal/Free.
318dir_help_1([move|_], [NF|Text]) when NF == normal; NF == free ->
319    ?STR(dir_help_1,1,"Move each element ") ++ Text;
320dir_help_1([rotate|_], [free|_Text]) ->
321    ?STR(dir_help_1,2,"Rotate freely");
322dir_help_1([rotate|_], [normal|_Text]) ->
323    ?STR(dir_help_1,3,"Rotate around each element's normal");
324dir_help_1([extrude|_], [NF|Text]) when NF == normal; NF == free ->
325    ?STR(dir_help_1,4,"Extrude each element, then move it ")++ Text;
326dir_help_1([extract|_], [NF|Text]) when NF == normal; NF == free ->
327    ?__(24,"Extract each element, then move it ")++ Text;
328dir_help_1([extrude_region|_], [normal|_]) ->
329    ?STR(dir_help_1,5,"Extrude faces as region, then move faces along the region's normal");
330dir_help_1([extrude_region|_], [free|Text]) ->
331    ?STR(dir_help_1,6,"Extrude faces as region, then move faces ") ++ Text;
332dir_help_1([extract_region|_], [normal|_]) ->
333    ?STR(dir_help_1,7,"Extract faces, then move faces along the region's normal");
334dir_help_1([extract_region|_], [free|Text]) ->
335    ?STR(dir_help_1,8,"Extract faces, then move faces ") ++ Text;
336dir_help_1([flatten|_], [normal|_Text]) ->
337    ?STR(dir_help_1,9,"Flatten elements to normal plane");
338dir_help_1([lift|_], [normal|_]) ->
339    ?STR(dir_help_1,10,"Lift face along its normal");
340dir_help_1([lift|_], [free|Text]) ->
341    ?STR(dir_help_1,11,"Lift face and move it ") ++ Text;
342dir_help_1([duplicate|_], [free|Text]) ->
343    ?STR(dir_help_1,12,"Duplicate and move freely ")++ Text;
344dir_help_1([shell_extrude|_], [normal|_]) ->
345    ?STR(dir_help_1,27,"Extract and Extrude faces as region, then move faces along the region's normal");
346dir_help_1([shell_extrude|_], [free|Text]) ->
347    ?STR(dir_help_1,28,"Extract and Extrude faces as region, then move faces ") ++ Text;
348
349%% Axis
350dir_help_1([move|_], Text) ->
351    ?STR(dir_help_1,13,"Move each element along ") ++ Text;
352dir_help_1([extrude|_], Text) ->
353    ?STR(dir_help_1,14,"Extrude elements, then move along ") ++ Text;
354dir_help_1([extract|_], Text) ->
355    ?__(25,"Extract elements, then move along ") ++ Text;
356dir_help_1([extrude_region|_], Text) ->
357    ?STR(dir_help_1,15,"Extrude faces as region, then move along ") ++ Text;
358dir_help_1([extract_region|_], Text) ->
359    ?STR(dir_help_1,16,"Extract faces, then move along ") ++ Text;
360dir_help_1([rotate|_], Text) ->
361    ?STR(dir_help_1,17,"Rotate around ") ++ Text;
362dir_help_1([scale|_], [around|Text]) ->
363    ?STR(dir_help_1,18,"Scale ") ++ Text;
364dir_help_1([scale|_], Text) ->
365    ?STR(dir_help_1,19,"Scale along ")++ Text;
366dir_help_1([flatten|_], Text) ->
367    ?STR(dir_help_1,20,"Flatten to ")++ Text;
368dir_help_1([flatten_move|_], Text) ->
369    ?STR(dir_help_1,21,"Flatten and move to ") ++ Text;
370dir_help_1([lift|_], Text) ->
371    ?STR(dir_help_1,22,"Lift face along ")++ Text;
372dir_help_1([duplicate|_], Text) ->
373    ?STR(dir_help_1,23,"Duplicate, then move along ")++ Text;
374dir_help_1([shell_extrude|_], Text) ->
375    ?STR(dir_help_1,26,"Extract and Extrude faces as region, then move along ") ++ Text;
376dir_help_1(_, _) -> "".
377
378%% Menu checkmark
379crossmark(Key) ->
380    Val = case wings_pref:get_value(Key) of
381	      undefined ->
382		  case wings_wm:this() of
383		      Client = {autouv, _} ->
384			  wings_wm:get_prop(Client, Key);
385		      {_,Client} ->
386			  wings_wm:get_prop(Client, Key);
387		      Client when is_atom(Client) ->    % Client is     'geom' when updating from wings_pref_dlg
388			  wings_wm:get_prop(Client, Key)
389		  end;
390	      Other -> Other
391	  end,
392    [{crossmark, Val}].
393