Advertisement
Guest User

baltazar

a guest
Apr 22nd, 2010
405
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 6.84 KB | None | 0 0
  1. -module(drawtree).
  2. -compile(export_all).
  3.  
  4. -define(EXTENT_SEPARATOR, 15).
  5. -define(LAYER_HEIGHT, 30).
  6. -define(LINE_Y_OFFSET, 10).
  7. -define(LINE_X_OFFSET, 3).
  8. -define(LINE_VERTICAL_LENGTH, 7).
  9. -define(LETTER_WIDTH, 7).
  10. -define(TREE_POS_X, 350).
  11. -define(TREE_POS_Y, 30).
  12.  
  13. -define(WINDOW_WIDTH, 1000).
  14. -define(WINDOW_HEIGHT, 500).
  15.  
  16. -record(pnode, {label = "LABEL", pos = 0, children = []}).
  17. -record(extent, {left, right}).
  18.  
  19. init() ->
  20.     S = gs:start(),
  21.     Win = gs:window(ui_main_window, S, [{width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]),
  22.     gs:config(Win, {map, true}),
  23.     Canvas = gs:canvas(Win, [{x, 0}, {y, 0}, {width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]),
  24.  
  25.     do_drawings(Canvas),
  26.    
  27.     loop(),
  28.     init:stop().
  29.  
  30. move_ptree({[], _X}) -> [];
  31. move_ptree({#pnode{pos = Pos} = Node, X}) ->
  32.     Node#pnode{pos = Pos + X}.
  33.  
  34. make_extent(Left, Right) ->
  35.     #extent{left = Left, right = Right}.
  36.  
  37. make_pnode(Label) ->
  38.     #pnode{label = Label}.
  39. make_pnode(Label, Pos, Children) ->
  40.     #pnode{label = Label, pos = Pos, children = Children}.
  41.  
  42. add_pnode(#pnode{children = Children} = Tree, PNode) ->
  43.     Tree#pnode{children = [PNode | Children]}.
  44.  
  45. add_pnodes(#pnode{children = Children} = Tree, PNodes) ->
  46.     Tree#pnode{children = PNodes ++ Children}.
  47.  
  48. do_drawings(Canvas) ->
  49.     Tree = add_pnodes(
  50.         add_pnode(
  51.             make_pnode("@"),
  52.             add_pnodes(
  53.                 make_pnode("Beta"),
  54.                 [make_pnode("Code"),
  55.                  add_pnodes(
  56.                     make_pnode("Dad"),
  57.                     [make_pnode("1st"),
  58.                      make_pnode("2nd")]
  59.                  ),
  60.                  make_pnode("Exit"),
  61.                  add_pnodes(
  62.                     make_pnode("Fall"),
  63.                     [make_pnode("111"),
  64.                      make_pnode("222"),
  65.                      make_pnode("333"),
  66.                      make_pnode("444"),
  67.                      make_pnode("555"),
  68.                      make_pnode("666")]
  69.                  ),
  70.                  add_pnodes(
  71.                     make_pnode("Gravity"),
  72.                     [make_pnode("1_milk"),
  73.                      make_pnode("2_apple"),
  74.                      make_pnode("3_juice"),
  75.                      make_pnode("4_banana"),
  76.                      make_pnode("5_orange")]
  77.                  ),
  78.                  make_pnode("Hope"),
  79.                  make_pnode("Illness"),
  80.                  make_pnode("Joke")]
  81.             )
  82.         ),
  83.         [add_pnodes(
  84.             make_pnode("Kernel"),
  85.             [make_pnode("Load"),
  86.              make_pnode("Module"),
  87.              make_pnode("Nop"),
  88.              make_pnode("Operator"),
  89.              make_pnode("Point")]
  90.          ),
  91.          make_pnode("Quit"),
  92.          make_pnode("Rest"),
  93.          make_pnode("Set"),
  94.          make_pnode("Terminate")]
  95.     ),
  96.     io:format("Source = ~p~n", [Tree]),
  97.     {DesignedTree, Extents} = design_tree(Tree),
  98.     io:format("DesignedTree = ~p~n", [DesignedTree]),
  99.     io:format("Extents = ~p~n", [Extents]),
  100.  
  101.     draw_designed_tree(Canvas, ?TREE_POS_X, ?TREE_POS_Y, DesignedTree).
  102.  
  103. move_extent({#extent{left = Left, right = Right} = Extent, Offset}) ->
  104.     Extent#extent{left = Left + Offset, right = Right + Offset};
  105. move_extent({ExtentList, Offset}) ->
  106.     lists:map(fun(Extent) -> move_extent({Extent, Offset}) end, ExtentList).
  107.  
  108. merge_extent({#extent{left = Left}, #extent{right = Right}}) ->
  109.     #extent{left = Left, right = Right};
  110. merge_extent({[], []}) -> [];
  111. merge_extent({[], Extent}) -> Extent;
  112. merge_extent({Extent, []}) -> Extent;
  113. merge_extent({[Left | LeftRest], [Right | RightRest]}) ->
  114.     [merge_extent({Left, Right}) | merge_extent({LeftRest, RightRest})].
  115.  
  116. merge_extent_list(ExtentList) ->
  117.     % IMPORTANT: Notice Elem and Acc change!
  118.     % fun(Elem, Acc) -> merge_extent({Acc, Elem}
  119.     lists:foldl(fun(Elem, Acc) -> merge_extent({Acc, Elem}) end, [], ExtentList).
  120.  
  121. fit_extent({#extent{right = Right}, #extent{left = Left}}) ->
  122.     Right - Left + ?EXTENT_SEPARATOR;
  123. fit_extent({[], []}) ->
  124.     0;
  125. fit_extent({[First | FirstRest], [Second | SecondRest]}) ->
  126.     erlang:max(fit_extent({First, Second}), fit_extent({FirstRest, SecondRest}));
  127. fit_extent({_A, _B}) ->
  128.     0.
  129.  
  130. fit_extent_list_l(ExtentList) ->
  131.     fit_extent_list_l([], ExtentList).
  132.  
  133. fit_extent_list_l(_Acc, []) -> [];
  134. fit_extent_list_l(Acc, [Extent | Rest]) ->
  135.     X = fit_extent({Acc, Extent}),
  136.     [X | fit_extent_list_l(merge_extent({Acc, move_extent({Extent, X})}), Rest)].
  137.  
  138. flip_extent(#extent{left = Left, right = Right} = Extent) ->
  139.     Extent#extent{left = -Right, right = -Left};
  140. flip_extent(ExtentList) ->
  141.     [flip_extent(Extent) || Extent <- ExtentList].
  142.  
  143. fit_extent_list_r(ExtentList) ->
  144.     lists:reverse(
  145.         [-X || X <- fit_extent_list_l(
  146.             lists:map(
  147.                 fun flip_extent/1,
  148.                 lists:reverse(ExtentList)
  149.             )
  150.         )]
  151.     ).
  152.  
  153. % fit_extent_list_r(ExtentList) ->
  154.     % lists:reverse(fit_extent_list_r([], lists:reverse(ExtentList))).
  155.  
  156. % fit_extent_list_r(_Acc, []) -> [];
  157. % fit_extent_list_r(Acc, [Extent | Rest]) ->
  158.     % X = - fit_extent({Extent, Acc}),
  159.     % [X | fit_extent_list_r(merge_extent({move_extent({Extent, X}), Acc}), Rest)].
  160.  
  161. mean({X, Y}) ->
  162.     trunc((X + Y) / 2).
  163.  
  164. fit_extent_list(ExtentList) ->
  165.     lists:map(
  166.         fun mean/1,
  167.         lists:zip(fit_extent_list_l(ExtentList), fit_extent_list_r(ExtentList))
  168.     ).
  169.  
  170. label_width(Label) ->
  171.     ?LETTER_WIDTH * length(Label).
  172.  
  173. design_tree(#pnode{label = Label, children = []}) ->
  174.     {make_pnode(Label, 0, []), [make_extent(0, label_width(Label))]};
  175. design_tree(#pnode{label = Label, children = Children} = Node) ->
  176.     {Trees, Extents} = lists:unzip(lists:map(fun design_tree/1, Children)),
  177.     Positions = fit_extent_list(Extents),
  178.     PTrees = lists:map(fun move_ptree/1, lists:zip(Trees, Positions)),
  179.     PExtents = lists:map(fun move_extent/1, lists:zip(Extents, Positions)),
  180.     ResultExtent = [make_extent(0, label_width(Label)) | merge_extent_list(PExtents)],
  181.     ResultTree = Node#pnode{pos = 0, children = PTrees},
  182.     {ResultTree, ResultExtent}.
  183.  
  184. draw_designed_tree(Canvas, X, Y,
  185.                    #pnode{label = Label, pos = Pos, children = Children}) ->
  186.     NewX = X + ?LINE_X_OFFSET,
  187.     NewY = Y - ?LINE_Y_OFFSET,
  188.     gs:line(Canvas, [{coords, [
  189.         {NewX, NewY - ?LINE_VERTICAL_LENGTH},
  190.         {NewX, NewY},
  191.         {NewX + Pos, NewY},
  192.         {NewX + Pos, NewY + ?LINE_VERTICAL_LENGTH}
  193.     ]}]),
  194.  
  195.     gs:text(Canvas, [
  196.         {coords, [{X + Pos, Y}]},
  197.         {text, Label}
  198.     ]),
  199.    
  200.     lists:map(
  201.         fun(Node) ->
  202.             draw_designed_tree(Canvas, X + Pos, Y + ?LAYER_HEIGHT, Node)
  203.         end,
  204.         Children),
  205.     ok.
  206.    
  207. loop() ->
  208.     receive
  209.         {gs, ui_main_window, destroy, _Data, _Args} ->
  210.             ok;
  211.         _Other ->
  212.             loop()
  213.     end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement