1%% 2%% wings_util.erl -- 3%% 4%% Various utility functions that not obviously fit somewhere else. 5%% 6%% Copyright (c) 2001-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%% Note: To keep the call graph clean, wings_util MUST NOT call 14%% other wings_* modules (except wings_pref). 15 16-module(wings_util). 17-export([share/1,share/3,make_vector/1, 18 rel2fam/1, 19 format/2, 20 key_format/2, 21 cap/1,upper/1,stringify/1,quote/1, 22 add_vpos/2,update_vpos/2, 23 gb_trees_smallest_key/1,gb_trees_largest_key/1, 24 array_keys/1,array_smallest_key/1,array_greatest_key/1, 25 array_is_empty/1,array_entries/1, 26 mapsfind/3, 27 wxequal/2, wxset_pid/2, min_wx/1, 28 nice_float/1,nice_vector/1,nice_abs_vector/1, 29 string_to_float/1, 30 unique_name/2, 31 is_name_masked/2, 32 lib_dir/1, 33 tc/3, profile_start/1, profile_stop/1, 34 limit/2]). 35 36-define(NEED_OPENGL, 1). 37-define(NEED_ESDL, 1). 38-include("wings.hrl"). 39-include_lib("e3d/e3d.hrl"). 40 41-import(lists, [foldl/3,reverse/1,member/2,last/1]). 42 43share(X, X, X) -> {X,X,X}; 44share(X, X, Z) -> {X,X,Z}; 45share(X, Y, Y) -> {X,Y,Y}; 46share(X, Y, X) -> {X,Y,X}; 47share(X, Y, Z) -> {X,Y,Z}. 48 49share({X,X,X}) -> {X,X,X}; 50share({X,X,Z}) -> {X,X,Z}; 51share({X,Y,Y}) -> {X,Y,Y}; 52share({X,Y,X}) -> {X,Y,X}; 53%% 54share({X,X,X,X}) -> {X,X,X,X}; 55%% 56share({X,X,X,A}) -> {X,X,X,A}; 57share({X,X,Z,X}) -> {X,X,Z,X}; 58share({X,Y,X,X}) -> {X,Y,X,X}; 59share({X,Y,Y,Y}) -> {X,Y,Y,Y}; 60%% 61share({X,X,Y,Y}) -> {X,X,Y,Y}; 62share({X,Y,X,Y}) -> {X,Y,X,Y}; 63share({X,Y,Y,X}) -> {X,Y,Y,X}; 64%% 65share({X,X,Z,A}) -> {X,X,Z,A}; 66share({X,Y,X,A}) -> {X,Y,X,A}; 67share({X,Y,Z,X}) -> {X,Y,Z,X}; 68share({X,Y,Y,A}) -> {X,Y,Y,A}; 69share({X,Y,Z,Y}) -> {X,Y,Z,Y}; 70share({X,Y,Z,Z}) -> {X,Y,Z,Z}; 71%% 72share(Other) -> Other. 73 74make_vector({_,_,_}=Vec) -> Vec; 75make_vector(x) -> {1.0,0.0,0.0}; 76make_vector(y) -> {0.0,1.0,0.0}; 77make_vector(z) -> {0.0,0.0,1.0}; 78make_vector(free) -> free; 79make_vector(normal) -> normal; 80make_vector(intrude) -> normal; 81make_vector({region,normal}) -> normal; 82make_vector(Axis) when Axis == last_axis; Axis == default_axis -> 83 {_,Vec} = wings_pref:get_value(Axis), 84 Vec. 85 86 87key_format(Key, Msg) -> 88 [Key,160,Msg]. 89 90%% Like io_lib:format/2, but with very restricted format characters. 91%% BUT allows arguments to ~s to be lists containing Unicode characters. 92%% Now allows ~ts for translation of Asian glyphs. 93%% 94%% Format directives allowed: ~s ~p 95 96format(Format, Args) -> 97 format_1(Format, Args, []). 98 99rel2fam(Rel) -> 100 sofs:to_external(sofs:relation_to_family(sofs:relation(Rel))). 101 102quote(Str) when is_list(Str) -> 103 [$",Str,$"]. 104 105stringify({Atom,Other}) when is_atom(Atom) -> 106 translation_string(Atom) ++ 107 case stringify(Other) of 108 [] -> []; 109 Str -> "|" ++ Str 110 end; 111stringify(Atom) when is_atom(Atom) -> 112 translation_string(Atom); 113stringify(Int) when is_integer(Int) -> 114 integer_to_list(Int); 115stringify(_Other) -> []. 116 117cap(Str) when is_atom(Str) -> cap(atom_to_list(Str)); 118cap(Str) -> cap(Str, true). 119 120cap([Lower|T], true) when $a =< Lower, Lower =< $z -> 121 [Lower-$a+$A|cap(T, false)]; 122cap([$_|T], _Any) -> 123 [$\s|cap(T, true)]; 124cap([H|T], _Any) -> 125 [H|cap(T, false)]; 126cap([], _Flag) -> []. 127 128upper(Str) when is_atom(Str) -> upper(atom_to_list(Str)); 129upper([Lower|T]) when $a =< Lower, Lower =< $z -> 130 [Lower-$a+$A|upper(T)]; 131upper([H|T]) -> 132 [H|upper(T)]; 133upper([]) -> []. 134 135add_vpos(Vs, #we{vp=Vtab}) -> add_vpos(Vs, Vtab); 136add_vpos(Vs, Vtab) -> 137 foldl(fun(V, A) -> 138 [{V,array:get(V, Vtab)}|A] 139 end, [], Vs). 140 141update_vpos(Vs, #we{vp=Vtab}) -> update_vpos(Vs, Vtab); 142update_vpos(Vs, Vtab) -> 143 foldl(fun({V,_}, A) -> 144 [{V,array:get(V, Vtab)}|A]; 145 ({V,_,Dist,Inf}, A) -> 146 [{V,array:get(V, Vtab),Dist,Inf}|A] 147 end, [], reverse(Vs)). 148 149gb_trees_smallest_key(Tree) -> 150 {Key,_Val} = gb_trees:smallest(Tree), 151 Key. 152 153gb_trees_largest_key(Tree) -> 154 {Key,_Val} = gb_trees:largest(Tree), 155 Key. 156 157array_keys(Array) -> 158 array:sparse_foldr(fun(I, _, A) -> [I|A] end, [], Array). 159 160array_smallest_key(Array) -> 161 try 162 array:sparse_foldl(fun(I, _, _) -> throw(I) end, [], Array), 163 error(empty_array) 164 catch 165 throw:I when is_integer(I) -> 166 I 167 end. 168 169array_greatest_key(Array) -> 170 try 171 array:sparse_foldr(fun(I, _, _) -> throw(I) end, [], Array), 172 error(empty_array) 173 catch 174 throw:I when is_integer(I) -> 175 I 176 end. 177 178array_is_empty(Array) -> 179 try 180 array:sparse_foldr(fun(_, _, _) -> throw(false) end, [], Array), 181 throw(true) 182 catch 183 throw:Empty -> 184 Empty 185 end. 186 187%% array_entries(Array) -> NumberOfEntries 188%% Return the number of non-default entries in the array. 189%% 190array_entries(Array) -> 191 array:sparse_foldl(fun(_, _, N) -> N + 1 end, 0, Array). 192 193-spec nice_abs_vector(e3d_vec:vector()) -> iolist(). 194 195nice_abs_vector({X,Y,Z}) -> 196 nice_vector({abs(X),abs(Y),abs(Z)}). 197 198-spec nice_vector(e3d_vec:vector()) -> iolist(). 199 200nice_vector({X,Y,Z}) -> 201 ["<", 202 wings_util:nice_float(X)," ", 203 wings_util:nice_float(Y)," ", 204 wings_util:nice_float(Z), 205 ">"]. 206 207nice_float(F) when is_float(F) -> 208 simplify_float(lists:flatten(io_lib:format("~f", [F]))). 209 210simplify_float(F) -> 211 reverse(simplify_float_1(reverse(F))). 212 213simplify_float_1("0."++_=F) -> F; 214simplify_float_1("0"++F) -> simplify_float_1(F); 215simplify_float_1(F) -> F. 216 217 218string_to_float("NaN") -> 0.0; 219string_to_float(Str) -> 220 try list_to_float(Str) 221 catch _:_ -> make_float2(Str) 222 end. 223 224make_float2(Str) -> 225 try float(list_to_integer(Str)) 226 catch _:_ -> make_float3(Str) 227 end. 228 229make_float3(Str0) -> 230 Str = lists:flatten(string:tokens(Str0, "\t\s\n")), 231 try list_to_float(Str) 232 catch _:_ -> make_float4(Str) end. 233 234make_float4(Str) -> 235 WithDot = case string:tokens(Str, "eE") of 236 [Pre,Post] -> Pre ++ ".0e" ++ Post; 237 [Other] -> Other ++ ".0"; 238 Other -> Other 239 end, 240 list_to_float(WithDot). 241 242%% 243%% Finds the first map containing Key:=Value 244%% 245-spec mapsfind(term(), term(), list()) -> map()|false. 246mapsfind(Value, Key, [H|T]) -> 247 case H of 248 #{Key:=Value} -> H; 249 _ -> mapsfind(Value, Key, T) 250 end; 251mapsfind(_, _, []) -> false. 252 253 254%% Missing wx funcs 255-record(wx_ref, {ref, type, state}). 256wxequal(#wx_ref{ref=Ref1}, #wx_ref{ref=Ref2}) -> Ref1 =:= Ref2. 257wxset_pid(#wx_ref{}=R, Pid) when is_pid(Pid) -> 258 R#wx_ref{state=Pid}. 259 260min_wx({_,_}=Ver) -> 261 case get(wx_version) of 262 undefined -> 263 case filename:basename(code:lib_dir(wx)) of 264 [$w,$x,$-,Major,_,Minor|_] -> 265 Version = {Major-$0, Minor-$0}, 266 put(wx_version, Version), 267 Version >= Ver; 268 _Vsn -> %% erlang src build? assume 19.2 or later 269 true 270 end; 271 Version -> 272 Version >= Ver 273 end. 274 275%% 276%% Create a unique name by appending digits. 277%% 278 279unique_name(Name, Names) -> 280 case member(Name, Names) of 281 false -> Name; 282 true -> unique_name_1(reverse(Name), Names) 283 end. 284 285unique_name_1([C|Cs], Names) when $0 =< C, C =< $9, Cs /= [] -> 286 unique_name_1(Cs, Names); 287unique_name_1(Name, Names0) -> 288 Base0 = [First|_] = reverse(Name), 289 Names = [N || N <- Names0, hd(N) =:= First], 290 Base = case member($\s, Base0) andalso last(Base0) =/= $\s of 291 true -> Base0 ++ " "; 292 false -> Base0 293 end, 294 unique_name_2(Base, 2, gb_sets:from_list(Names)). 295 296unique_name_2(Base, I, Names) -> 297 Name = Base ++ integer_to_list(I), 298 case gb_sets:is_member(Name, Names) of 299 true -> unique_name_2(Base, I+1, Names); 300 false -> Name 301 end. 302 303tc(Fun,Mod,Line) -> 304 Before = os:timestamp(), 305 R = Fun(), 306 After = os:timestamp(), 307 io:format("~p:~p: Time: ~p\n", [Mod, Line, timer:now_diff(After,Before)]), 308 R. 309 310profile_start(fprof) -> 311 fprof:trace(start), 312 ok; 313profile_start(eprof) -> 314 eprof:start(), 315 profiling = eprof:start_profiling([whereis(wings), self(), whereis(wings_image)]), 316 ok. 317 318profile_stop(fprof) -> 319 fprof:trace(stop), 320 spawn_link(fun() -> 321 File = "fprof.analysis", 322 fprof:profile(), 323 fprof:analyse([{dest, File}, {cols, 120}]), 324 io:format("Analysis in: ~p~n", [filename:absname(File)]), 325 eprof:stop() 326 end), 327 ok; 328profile_stop(eprof) -> 329 eprof:stop_profiling(), 330 spawn_link(fun() -> 331 File = "eprof.analysis", 332 eprof:log(File), 333 eprof:analyze(), 334 io:format("Analysis in: ~p~n", [filename:absname(File)]) 335 end). 336 337limit(Val, {'-infinity',infinity}) -> Val; 338limit(Val, {Min,infinity}) when Val < Min -> Min; 339limit(Val, {'-infinity',Max}) when Val > Max -> Max; 340limit(Val, {Min,Max}) when Min < Max, Val < Min -> Min; 341limit(Val, {Min,Max}) when Min < Max, Val > Max -> Max; 342limit(Val, {Min,Max}) when Min < Max -> Val. 343 344%% 345%% Check if name match with the mask. 346%% 347 348is_name_masked(Name,Mask) -> 349 Mask0=string:to_upper(Mask), 350 Name0=string:to_upper(Name), 351 is_name_masked_0(Name0,Mask0,get_mask_pos(Mask0)). 352 353is_name_masked_0(_Name,"*",_MaskPos) -> true; 354is_name_masked_0([],_Mask,_MaskPos) -> false; 355is_name_masked_0(_Name,[],_MaskPos) -> false; 356is_name_masked_0(Name,Name,[]) -> true; 357is_name_masked_0(_Name,_Mask,[]) -> false; 358is_name_masked_0(Name,Mask,[H|[]]=_MaskPos) -> % *text with only one wildcard 359 Mlen=string:len(Mask), 360 case H of 361 1 -> % *text value 362 Mask0=string:sub_string(Mask,H+1), 363 MPos=string:rstr(Name,Mask0), 364 (string:len(Name)-MPos+1)=:=(Mlen-1); 365 Mlen -> % text value* 366 Mask0=string:sub_string(Mask,1,Mlen-1), 367 string:str(Name,Mask0)=:=1; 368 _ -> % text *value 369 Mask0=string:sub_string(Mask,1,H-1), 370 Mask1=string:sub_string(Mask,H+1), 371 MPos=string:rstr(Name,Mask1), 372 Mlen0=string:len(Mask1), 373 (string:str(Name,Mask0)=:=1) and ((string:len(Name)-MPos)=:=(Mlen0-1)) 374 end; 375is_name_masked_0(Name,Mask,[H|[H0|_T0]=_T]=_MaskPos) -> % *text with more than one wildcard 376 case H of 377 1 -> % *text value 378 Mask0=string:sub_string(Mask,H+1,H0-1), 379 Mask1=string:sub_string(Mask,H0), 380 case string:str(Name,Mask0) of 381 0 -> false; 382 NPos -> 383 Name0=string:sub_string(Name,NPos+H0-H-1), 384 is_name_masked_0(Name0,Mask1,get_mask_pos(Mask1)) 385 end; 386 _ -> % te*xt value* 387 Mask0=string:sub_string(Mask,1,H-1), 388 Mask1=string:sub_string(Mask,H), 389 case string:str(Name,Mask0) of 390 1 -> 391 Name0=string:sub_string(Name,H), 392 is_name_masked_0(Name0,Mask1,get_mask_pos(Mask1)); 393 _ -> false 394 end 395 end. 396 397%%% 398%%% Local functions. 399%%% 400 401format_1("~s"++F, [S0|Args], Acc) -> 402 S = if 403 is_atom(S0) -> atom_to_list(S0); 404 is_list(S0) -> S0; 405 true -> 406 io:format("Bad string formatter for ~p in ~p~n", 407 [S0, lists:flatten(reverse(Acc) ++ F)]), 408 error(badarg) 409 end, 410 format_1(F, Args, [S|Acc]); 411format_1("~p"++F, [S0|Args], Acc) -> 412 S = format_p(S0), 413 format_1(F, Args, [S|Acc]); 414format_1("~~"++F, Args, Acc) -> 415 format_1(F, Args, [$~|Acc]); 416format_1("~ts"++F, Args, Acc) -> 417 format_1("~s"++F, Args, Acc); 418format_1([C|F], Args, Acc) when C =/= $~ -> 419 format_1(F, Args, [C|Acc]); 420format_1([], [], Acc) -> reverse(Acc). 421 422format_p(Str) when is_list(Str) -> 423 [$",Str,$"]; 424format_p(Str) -> 425 io_lib:format("~p", [Str]). 426 427lib_dir(wings) -> 428 case code:lib_dir(wings) of 429 {error,bad_name} -> 430 ["wings.beam","ebin"|Rev] = lists:reverse(filename:split(code:which(wings))), 431 filename:join(lists:reverse(Rev)); 432 Dir -> 433 Dir 434 end; 435lib_dir(Lib) -> 436 code:lib_dir(Lib). 437 438get_mask_pos([]) -> []; 439get_mask_pos(Mask) -> 440 get_mask_pos_1(Mask,0,[]). 441 442get_mask_pos_1([],_,Acc) -> Acc; 443get_mask_pos_1(Mask,Offset,Acc) -> 444 case string:str(Mask,"*") of 445 0 -> Acc; 446 Pos -> 447 Pos0=Pos+Offset, 448 get_mask_pos_1(string:sub_string(Mask,Pos+1),Pos0,Acc++[Pos0]) 449 end. 450 451 452% % % % % % % % % % % % % % % % % % % 453%% Strings for Translating Hotkeys %% 454% % % % % % (not elegant) % % % % % % 455 456%%%% Selection Modes 457translation_string(vertex) -> ?__(1,"Vertex"); 458translation_string(edge) -> ?__(2,"Edge"); 459translation_string(face) -> ?__(3,"Face"); 460translation_string(body) -> ?__(4,"Body"); 461translation_string(light) -> ?__(5,"Light"); 462 463%%%% Menu Headers 464translation_string(file) -> ?__(6,"File"); 465translation_string(edit) -> ?__(7,"Edit"); 466translation_string(view) -> ?__(8,"View"); 467translation_string(select) -> ?__(9,"Select"); 468translation_string(tools) -> ?__(10,"Tools"); 469translation_string(window) -> ?__(11,"Window"); 470translation_string(help) -> ?__(12,"Help"); 471 472%%%% File Menu 473translation_string(new) -> ?__(13,"New"); 474translation_string(open) -> ?__(14,"Open"); 475translation_string(merge) -> ?__(15,"Merge"); 476translation_string(save) -> ?__(16,"Save"); 477translation_string(save_as) -> ?__(17,"Save As"); 478translation_string(save_selected) -> ?__(18,"Save Selected"); 479translation_string(save_incr) -> ?__(19,"Save Incrementally"); 480translation_string(revert) -> ?__(20,"Revert"); 481translation_string(import) -> ?__(21,"Import"); 482translation_string(export) -> ?__(22,"Export"); 483translation_string(export_selected) -> ?__(23,"Export Selected"); 484translation_string(import_image) -> ?__(24,"Import Image"); 485translation_string(render) -> ?__(25,"Render"); 486translation_string(install_plugin) -> ?__(26,"Install Plugin"); 487translation_string(quit) -> ?__(27,"Exit"); 488 489%%%% Import Export Formats 490%% these probably don't need translating 491 492%%%% Edit Menu 493translation_string(undo_toggle) -> ?__(28,"Undo/Redo"); 494translation_string(undo) -> ?__(29,"Undo"); 495translation_string(redo) -> ?__(30,"Redo"); 496translation_string(repeat) -> ?__(31,"Repeat"); 497translation_string(repeat_args) -> ?__(32,"Repeat Args"); 498translation_string(repeat_drag) -> ?__(33,"Repeat Drag"); 499translation_string(purge_undo) -> ?__(34,"Purge Undo"); 500translation_string(preferences) -> ?__(35,"Preferences"); 501translation_string(prefs) -> ?__(36,"Prefs"); 502translation_string(plugin_manager) -> ?__(37,"Plugin Manager"); 503 504%%%% View Menu 505translation_string(show_groundplane) -> ?__(38,"Show Ground Plane"); 506translation_string(show_axes) -> ?__(39,"Show Axes"); 507translation_string(show_info_text) -> ?__(40,"Show Info Text"); 508translation_string(workmode) -> ?__(41,"Workmode"); 509translation_string(wireframe) -> ?__(42,"Wireframe"); 510translation_string(shade) -> ?__(43,"Shade"); 511translation_string(toggle_wirefrfame) -> ?__(44,"Toggle Wireframe"); 512translation_string(show_edges) -> ?__(45,"Show Edges"); 513translation_string(show_wire_backfaces) -> ?__(46,"Show Wireframe Backfaces"); 514translation_string(smooth_proxy) -> ?__(47,"Toggle Smooth Proxy"); 515translation_string(quick_preview) -> ?__(48,"Quick Smoothed Preview"); 516translation_string(show_bb) -> ?__(49,"Show Bounding Box"); 517translation_string(clip_plane) -> ?__(50,"Clipping Plane"); 518translation_string(show_normals) -> ?__(51,"Show Normals"); 519translation_string(show_colors) -> ?__(52,"Show Colors"); 520translation_string(show_materials) -> ?__(53,"Show Materials"); 521translation_string(show_textures) -> ?__(54,"Show Textures"); 522translation_string(scene_lights) -> ?__(55,"Scene Lights"); 523translation_string(toggle_lights) -> ?__(56,"Toggle Lights"); 524translation_string(orthogonal_view) -> ?__(57,"Orthographic View"); 525translation_string(reset) -> ?__(58,"Reset View"); 526translation_string(aim) -> ?__(59,"Aim"); 527translation_string(highlight_aim) -> ?__(60,"Highlight Aim"); 528translation_string(frame) -> ?__(61,"Frame"); 529translation_string(frame_mode) -> ?__(62,"Frame Mode"); 530translation_string(align_to_selection) -> ?__(63,"Align to Selection"); 531translation_string(next) -> ?__(64,"Next"); 532translation_string(pref) -> ?__(65,"Prev"); 533translation_string(current) -> ?__(66,"Current"); 534translation_string(jump) -> ?__(67,"Jump"); 535translation_string(along) -> ?__(68,"Along"); 536translation_string(rename) -> ?__(69,"Rename"); 537translation_string(delete_all) -> ?__(70,"Delete All"); 538translation_string(camera_settings) -> ?__(71,"Camera Settings"); 539translation_string(auto_rotate) -> ?__(72,"Auto Rotate"); 540 541%%%% Select Menu 542translation_string(deselect) -> ?__(73,"Deselect"); 543translation_string(more) -> ?__(74,"More"); 544translation_string(less) -> ?__(75,"Less"); 545translation_string(similar) -> ?__(76,"Similar"); 546translation_string(edge_loop) -> ?__(77,"Edge Loop"); 547translation_string(edge_loop_to_region) -> ?__(78,"Edge Loop to Region"); 548translation_string(edge_ring) -> ?__(79,"Edge Ring"); 549translation_string(prev_edge_loop) -> ?__(80,"Previous Edge Loop"); 550translation_string(next_edge_loop) -> ?__(81,"Next Edge Loop"); 551translation_string(edge_link_incr) -> ?__(82,"Edge Link Increase"); 552translation_string(edge_link_decr) -> ?__(83,"Edge Link Decrease"); 553translation_string(edge_ring_incr) -> ?__(84,"Edge Ring Increase"); 554translation_string(edge_ring_decr) -> ?__(85,"Edge Ring Decrease"); 555translation_string(adjacent) -> ?__(86,"Adjacent"); 556translation_string(inverse) -> ?__(87,"Inverse"); 557translation_string(hide_selected) -> ?__(88,"Hide Selected"); 558translation_string(hide_unselected) -> ?__(89,"Hide Unselected"); 559translation_string(lock_unselected) -> ?__(90,"Lock Unselected"); 560translation_string(show_all) -> ?__(91,"Show All"); 561translation_string(store_selection) -> ?__(92,"Store Selection"); 562translation_string(recall_selection) -> ?__(93,"Recall Selection"); 563translation_string(new_group) -> ?__(94,"New Group"); 564translation_string(oriented_faces) -> ?__(95,"Similar Normals"); 565translation_string(similar_area) -> ?__(96,"Similar Area"); 566translation_string(delete_group) -> ?__(97,"Delete Group"); 567translation_string(add_to_group) -> ?__(98,"Add to Group"); 568translation_string(subtract_from_group) -> ?__(99,"Subtract from Group"); 569translation_string(select_group) -> ?__(100,"Select Group"); 570translation_string(union_group) -> ?__(101,"Union Group"); 571translation_string(subtract_group) -> ?__(102,"Subtract Group"); 572translation_string(intersect_group) -> ?__(103,"Intersect Group"); 573 574%%%% Select By Submenu 575translation_string(by) -> ?__(104,"By"); 576translation_string(hard_edges) -> ?__(105,"Hard Edges"); 577translation_string(isolated_vertices) -> ?__(106,"Isolated Vertices"); 578translation_string(nonplanar_faces) -> ?__(107,"Non-Planar Faces"); 579translation_string(vertices_with) -> ?__(108,"Vertices With"); 580translation_string(faces_with) -> ?__(109,"Faces With"); 581translation_string(non_quad) -> ?__(110,"Non Quadrangle"); 582translation_string(odd) -> ?__(111,"Odd"); 583translation_string(even) -> ?__(112,"Even"); 584translation_string(random) -> ?__(113,"Random"); 585translation_string(short_edges) -> ?__(114,"Short Edges"); 586translation_string(sharp_edges) -> ?__(115,"Sharp Edges"); 587translation_string(vertex_path) -> ?__(116,"Vertex Path"); 588translation_string(fewest_edges_path) -> ?__(117,"Fewest Edges Path"); 589translation_string(dijkstra_shortest_path) -> ?__(118,"Shortest Path (Dijkstra)"); 590translation_string(astar_shortest_path) -> ?__(119,"Shortest Path (A-Star)"); 591translation_string(material_edges) -> ?__(120,"Material Edges"); 592 593 594 595%%%% Tools Menu 596translation_string(align) -> ?__(121,"Align"); 597translation_string(save_bb) -> ?__(122,"Save Bounding Box"); 598translation_string(scale_to_bb) -> ?__(123,"Scale to Bounding Box"); 599translation_string(scale_to_bb_prop) -> ?__(124,"Scale to Bounding Box Proportionally"); 600translation_string(move_to_bb) -> ?__(125,"Move to Bounding Box"); 601translation_string(virtual_mirror) -> ?__(126,"Virtual Mirror"); 602translation_string(create) -> ?__(127,"Create"); 603translation_string(break) -> ?__(128,"Break"); 604translation_string(freeze) -> ?__(129,"Freeze"); 605translation_string(screenshot) -> ?__(130,"Screenshot"); 606translation_string(area_volume_info) -> ?__(131,"Area Volume Info"); 607translation_string(scene_size_info) -> ?__(132,"Memory Usage"); 608translation_string(put_on_ground) -> ?__(133,"Put on Ground"); 609translation_string(unitize) -> ?__(134,"Unitize"); 610translation_string(tweak) -> ?__(135,"Tweak"); 611translation_string(snap_image_mode) -> ?__(136,"Snap Image"); 612 613%%%% Window Menu 614translation_string(outliner) -> ?__(137,"Outliner"); 615translation_string(object) -> ?__(138,"Geometry Graph"); 616translation_string(palette) -> ?__(139,"Palette"); 617translation_string(console) -> ?__(140,"Console"); 618translation_string(geom_viewer) -> ?__(141,"New Geomerty Window"); 619translation_string(uv_editor_window) -> ?__(142,"UV Editor Window"); 620 621%%%% Help Menu 622translation_string(getting_started) -> ?__(143,"Getting Started"); 623translation_string(one_or_two) -> ?__(144,"Mouse Buttons"); 624translation_string(international) -> ?__(145,"International Keyboards"); 625translation_string(hotkeys) -> ?__(146,"Defined Hotkeys"); 626translation_string(defining_hotkeys) -> ?__(147,"Defining Hotkeys"); 627%%translation_string(advanced_menus) -> ?__(148,"Advanced Menus"); 628translation_string(default_commands) -> ?__(149,"Default Commands"); 629translation_string(performance_tips) -> ?__(150,"Performance Tips"); 630translation_string(opengl_info) -> ?__(151,"OpenGL Info"); 631translation_string(about) -> ?__(152,"About"); 632 633%%%% Primitives Menu 634translation_string(shapes) -> ?__(153,"Shapes"); 635translation_string(tetrahedron) -> ?__(154,"Tetrahedron"); 636translation_string(octahedron) -> ?__(155,"Octahedron"); 637translation_string(octotoad) -> ?__(156,"Octotoad"); 638translation_string(dodecahedron) -> ?__(157,"Dodecahedron"); 639translation_string(icosahedron) -> ?__(158,"Icosahedron"); 640translation_string(cube) -> ?__(159,"Cube"); 641translation_string(cylinder) -> ?__(160,"Cylinder"); 642translation_string(cone) -> ?__(161,"Cone"); 643translation_string(sphere) -> ?__(162,"Sphere"); 644translation_string(torus) -> ?__(163,"Torus"); 645translation_string(grid) -> ?__(164,"Grid"); 646translation_string(material) -> ?__(165,"Material"); 647translation_string(image) -> ?__(166,"Image"); 648translation_string(image_plane) -> ?__(167,"Image Plane"); 649translation_string(text) -> ?__(168,"Text"); 650%%%% More 651translation_string(gear) -> ?__(169,"Gear"); 652translation_string(tube) -> ?__(170,"Tube"); 653translation_string(geodome) -> ?__(171,"Geo Dome"); 654translation_string(knot) -> ?__(172,"Torus Knot"); 655translation_string(ncube) -> ?__(173,"N-Cube"); 656translation_string(ngon) -> ?__(174,"N-Gon"); 657translation_string(regularplane) -> ?__(175,"Regular Plane"); 658translation_string(lumpyplane) -> ?__(176,"Lumpy Plane"); 659translation_string(wavyplane) -> ?__(177,"Wavy Plane"); 660translation_string(sombreroplane) -> ?__(178,"Sombrero Plane"); 661translation_string(spiral) -> ?__(179,"Spiral"); 662translation_string(spring) -> ?__(180,"Spring"); 663translation_string(uvtorus) -> ?__(181,"UV Torus"); 664translation_string(lutorus) -> ?__(182,"Lumpy Torus"); 665translation_string(sptorus) -> ?__(183,"Spiral Torus"); 666 667%%%% Common Axis Descriptors 668translation_string(normal) -> ?__(184,"Normal"); 669translation_string(free) -> ?__(185,"Free"); 670translation_string(center) -> ?__(186,"Center"); 671translation_string(central_axis) -> ?__(187,"Central Axis"); 672translation_string(x) -> ?__(188,"X"); 673translation_string(y) -> ?__(189,"Y"); 674translation_string(z) -> ?__(190,"Z"); 675translation_string(neg_x) -> ?__(191,"-X"); 676translation_string(neg_y) -> ?__(192,"-Y"); 677translation_string(neg_z) -> ?__(193,"-Z"); 678translation_string(last_axis) -> ?__(194,"Last Axis"); 679translation_string(default_axis) -> ?__(195,"Default Axis"); 680translation_string(true) -> ?__(196,"True"); 681translation_string(false) -> ?__(197,"False"); 682translation_string(all) -> ?__(198,"All"); 683translation_string(pick_all) -> ?__(199,"Pick All"); 684translation_string(radial_x) -> ?__(200,"Radial X"); 685translation_string(radial_y) -> ?__(201,"Radial Y"); 686translation_string(radial_z) -> ?__(202,"Radial Z"); 687translation_string('ASK') -> ?__(203,"ASK"); 688translation_string(lmb) -> ?__(204,"LMB"); 689translation_string(mmb) -> ?__(205,"MMB"); 690translation_string(rmb) -> ?__(206,"RMB"); 691translation_string(relative) -> ?__(207,"Relative"); 692translation_string(absolute) -> ?__(208,"Absolute"); 693 694%%%% Common Commands 695translation_string(move) -> ?__(209,"Move"); 696translation_string(rotate) -> ?__(210,"Rotate"); 697translation_string(scale) -> ?__(211,"Scale"); 698translation_string(uniform) -> ?__(212,"Uniform"); 699translation_string(extrude) -> ?__(213,"Extrude"); 700translation_string(extract) -> ?__(214,"Extract"); 701translation_string(dissolve) -> ?__(215,"Dissolve"); 702translation_string(collapse) -> ?__(216,"Collapse"); 703translation_string(delete) -> ?__(217,"Delete"); 704translation_string(flatten) -> ?__(218,"Flatten"); 705translation_string(smooth) -> ?__(219,"Smooth"); 706translation_string(tighten) -> ?__(220,"Tighten"); 707translation_string(bevel) -> ?__(221,"Bevel"); 708translation_string(weld) -> ?__(222,"Weld"); 709translation_string(vertex_color) -> ?__(223,"Vertex Color"); 710translation_string(move_planar) -> ?__(290,"Move Planar"); 711 712%%%% Absolute Commands 713translation_string(snap) -> ?__(224,"Snap"); 714translation_string(nsnap) -> ?__(225,"Snap|Numeric Entry"); 715translation_string(ctscale) -> ?__(226,"Scale to Target Size"); 716translation_string(cscale) -> ?__(227,"Scale|Center"); 717 718%%%% Intersect 719translation_string(intersect) -> ?__(228,"Intersect"); 720translation_string(stay_on_line) -> ?__(229,"Stay on Line"); 721translation_string(stay_on_plane) -> ?__(230,"Stay on Plane"); 722translation_string(arc_intersect) -> ?__(289,"Rotate to Target"); 723 724%%%% Vertex Menu 725translation_string(connecting_edges) -> ?__(231,"Connecting Edges"); 726translation_string(bend) -> ?__(232,"Bend"); 727translation_string(shift) -> ?__(233,"Shift"); 728 729%%%% Vertex|Deform 730translation_string(deform) -> ?__(234,"Deform"); 731translation_string(crumple) -> ?__(235,"Crumple"); 732translation_string(taper) -> ?__(236,"Taper"); 733translation_string(twist) -> ?__(237,"Twist"); 734translation_string(torque) -> ?__(238,"Torque"); 735translation_string(inflate) -> ?__(239,"Inflate"); 736translation_string(cylindrilize) -> ?__(240,"Inflate Cylindrically"); 737translation_string(shear) -> ?__(241,"Shear"); 738 739%%%% Edge Menu 740translation_string(slide) -> ?__(242,"Slide"); 741translation_string(clean_dissolve) -> ?__(243,"Clean Dissolve"); 742translation_string(cut) -> ?__(244,"Cut"); 743translation_string(connect) -> ?__(245,"Connect"); 744translation_string(hardness) -> ?__(246,"Hardness"); 745translation_string(soft) -> ?__(247,"Soft"); 746translation_string(hard) -> ?__(248,"Hard"); 747translation_string(circularise) -> ?__(249,"Circularise"); 748translation_string(circularise_center) -> ?__(250,"Circularise|Center"); 749translation_string(loop_cut) -> ?__(251,"Loop Cut"); 750translation_string(turn_ccw) -> ?__(252,"Turn CCW"); 751translation_string(turn_cw) -> ?__(253,"Turn CW"); 752translation_string(turn_optimized) -> ?__(254,"Turn Optimized"); 753 754%%%% Face Menu 755translation_string(bridge) -> ?__(255,"Bridge"); 756translation_string(bump) -> ?__(256,"Bump"); 757translation_string(extrude_region) -> ?__(257,"Extrude Region"); 758translation_string(extract_region) -> ?__(258,"Extract Region"); 759translation_string(sweep_extrude) -> ?__(259,"Sweep Extrude"); 760translation_string(sweep_region) -> ?__(260,"Sweep Region"); 761translation_string(sweep_extract) -> ?__(261,"Sweep Extract"); 762translation_string(inset) -> ?__(262,"Inset"); 763translation_string(intrude) -> ?__(263,"Intrude"); 764translation_string(lift) -> ?__(264,"Lift"); 765translation_string(put_on) -> ?__(265,"Put On"); 766translation_string(clone_on) -> ?__(266,"Clone On"); 767translation_string(mirror) -> ?__(267,"Mirror"); 768translation_string(mirror_separate) -> ?__(268,"Mirror Separate"); 769translation_string(tesselate) -> ?__(269,"Tesselate"); 770translation_string(trianglulate) -> ?__(270,"Triangulate"); 771translation_string(quadrangulate) -> ?__(271,"Quadrangulate"); 772translation_string(untriangulate) -> ?__(272,"Untriangulate"); 773translation_string(hide) -> ?__(273,"Hide"); 774translation_string(wpc_autouv) -> ?__(274,"AutoUV"); 775translation_string(segment) -> ?__(275,"Segment"); 776translation_string(segment_old) -> ?__(276,"Segment Old"); 777translation_string(force_seg) -> ?__(277,"Force Segment"); 778 779%%%% Object Menu 780translation_string(flip) -> ?__(278,"Flip"); 781translation_string(invert) -> ?__(279,"Invert"); 782translation_string(doo_sabin) -> ?__(280,"Doo Sabin"); 783translation_string(combine) -> ?__(281,"Combine"); 784translation_string(separate) -> ?__(282,"Separate"); 785translation_string(cleanup) -> ?__(283,"Cleanup"); 786translation_string(auto_smooth) -> ?__(284,"Auto Smooth"); 787translation_string(duplicate) -> ?__(285,"Duplicate"); 788translation_string(vertex_color_mode) -> ?__(286,"Vertex Color Mode"); 789translation_string(to_arealight) -> ?__(287,"To Area Light"); 790translation_string(materials_to_colors) -> ?__(288,"Materials to Colors"); 791 792%%%% 793%%%% Translation strings used so far 1 - 290 794%%%% 795 796%%%% Others as yet to be added are processed here 797translation_string(Atom) when is_atom(Atom) -> 798 wings_util:cap(atom_to_list(Atom)). 799