Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -module(drawtree).
- -compile(export_all).
- -define(EXTENT_SEPARATOR, 15).
- -define(LAYER_HEIGHT, 30).
- -define(LINE_Y_OFFSET, 10).
- -define(LINE_X_OFFSET, 3).
- -define(LINE_VERTICAL_LENGTH, 7).
- -define(LETTER_WIDTH, 7).
- -define(TREE_POS_X, 350).
- -define(TREE_POS_Y, 30).
- -define(WINDOW_WIDTH, 1000).
- -define(WINDOW_HEIGHT, 500).
- -record(pnode, {label = "LABEL", pos = 0, children = []}).
- -record(extent, {left, right}).
- init() ->
- S = gs:start(),
- Win = gs:window(ui_main_window, S, [{width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]),
- gs:config(Win, {map, true}),
- Canvas = gs:canvas(Win, [{x, 0}, {y, 0}, {width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]),
- do_drawings(Canvas),
- loop(),
- init:stop().
- move_ptree({[], _X}) -> [];
- move_ptree({#pnode{pos = Pos} = Node, X}) ->
- Node#pnode{pos = Pos + X}.
- make_extent(Left, Right) ->
- #extent{left = Left, right = Right}.
- make_pnode(Label) ->
- #pnode{label = Label}.
- make_pnode(Label, Pos, Children) ->
- #pnode{label = Label, pos = Pos, children = Children}.
- add_pnode(#pnode{children = Children} = Tree, PNode) ->
- Tree#pnode{children = [PNode | Children]}.
- add_pnodes(#pnode{children = Children} = Tree, PNodes) ->
- Tree#pnode{children = PNodes ++ Children}.
- do_drawings(Canvas) ->
- Tree = add_pnodes(
- add_pnode(
- make_pnode("@"),
- add_pnodes(
- make_pnode("Beta"),
- [make_pnode("Code"),
- add_pnodes(
- make_pnode("Dad"),
- [make_pnode("1st"),
- make_pnode("2nd")]
- ),
- make_pnode("Exit"),
- add_pnodes(
- make_pnode("Fall"),
- [make_pnode("111"),
- make_pnode("222"),
- make_pnode("333"),
- make_pnode("444"),
- make_pnode("555"),
- make_pnode("666")]
- ),
- add_pnodes(
- make_pnode("Gravity"),
- [make_pnode("1_milk"),
- make_pnode("2_apple"),
- make_pnode("3_juice"),
- make_pnode("4_banana"),
- make_pnode("5_orange")]
- ),
- make_pnode("Hope"),
- make_pnode("Illness"),
- make_pnode("Joke")]
- )
- ),
- [add_pnodes(
- make_pnode("Kernel"),
- [make_pnode("Load"),
- make_pnode("Module"),
- make_pnode("Nop"),
- make_pnode("Operator"),
- make_pnode("Point")]
- ),
- make_pnode("Quit"),
- make_pnode("Rest"),
- make_pnode("Set"),
- make_pnode("Terminate")]
- ),
- io:format("Source = ~p~n", [Tree]),
- {DesignedTree, Extents} = design_tree(Tree),
- io:format("DesignedTree = ~p~n", [DesignedTree]),
- io:format("Extents = ~p~n", [Extents]),
- draw_designed_tree(Canvas, ?TREE_POS_X, ?TREE_POS_Y, DesignedTree).
- move_extent({#extent{left = Left, right = Right} = Extent, Offset}) ->
- Extent#extent{left = Left + Offset, right = Right + Offset};
- move_extent({ExtentList, Offset}) ->
- lists:map(fun(Extent) -> move_extent({Extent, Offset}) end, ExtentList).
- merge_extent({#extent{left = Left}, #extent{right = Right}}) ->
- #extent{left = Left, right = Right};
- merge_extent({[], []}) -> [];
- merge_extent({[], Extent}) -> Extent;
- merge_extent({Extent, []}) -> Extent;
- merge_extent({[Left | LeftRest], [Right | RightRest]}) ->
- [merge_extent({Left, Right}) | merge_extent({LeftRest, RightRest})].
- merge_extent_list(ExtentList) ->
- % IMPORTANT: Notice Elem and Acc change!
- % fun(Elem, Acc) -> merge_extent({Acc, Elem}
- lists:foldl(fun(Elem, Acc) -> merge_extent({Acc, Elem}) end, [], ExtentList).
- fit_extent({#extent{right = Right}, #extent{left = Left}}) ->
- Right - Left + ?EXTENT_SEPARATOR;
- fit_extent({[], []}) ->
- 0;
- fit_extent({[First | FirstRest], [Second | SecondRest]}) ->
- erlang:max(fit_extent({First, Second}), fit_extent({FirstRest, SecondRest}));
- fit_extent({_A, _B}) ->
- 0.
- fit_extent_list_l(ExtentList) ->
- fit_extent_list_l([], ExtentList).
- fit_extent_list_l(_Acc, []) -> [];
- fit_extent_list_l(Acc, [Extent | Rest]) ->
- X = fit_extent({Acc, Extent}),
- [X | fit_extent_list_l(merge_extent({Acc, move_extent({Extent, X})}), Rest)].
- flip_extent(#extent{left = Left, right = Right} = Extent) ->
- Extent#extent{left = -Right, right = -Left};
- flip_extent(ExtentList) ->
- [flip_extent(Extent) || Extent <- ExtentList].
- fit_extent_list_r(ExtentList) ->
- lists:reverse(
- [-X || X <- fit_extent_list_l(
- lists:map(
- fun flip_extent/1,
- lists:reverse(ExtentList)
- )
- )]
- ).
- % fit_extent_list_r(ExtentList) ->
- % lists:reverse(fit_extent_list_r([], lists:reverse(ExtentList))).
- % fit_extent_list_r(_Acc, []) -> [];
- % fit_extent_list_r(Acc, [Extent | Rest]) ->
- % X = - fit_extent({Extent, Acc}),
- % [X | fit_extent_list_r(merge_extent({move_extent({Extent, X}), Acc}), Rest)].
- mean({X, Y}) ->
- trunc((X + Y) / 2).
- fit_extent_list(ExtentList) ->
- lists:map(
- fun mean/1,
- lists:zip(fit_extent_list_l(ExtentList), fit_extent_list_r(ExtentList))
- ).
- label_width(Label) ->
- ?LETTER_WIDTH * length(Label).
- design_tree(#pnode{label = Label, children = []}) ->
- {make_pnode(Label, 0, []), [make_extent(0, label_width(Label))]};
- design_tree(#pnode{label = Label, children = Children} = Node) ->
- {Trees, Extents} = lists:unzip(lists:map(fun design_tree/1, Children)),
- Positions = fit_extent_list(Extents),
- PTrees = lists:map(fun move_ptree/1, lists:zip(Trees, Positions)),
- PExtents = lists:map(fun move_extent/1, lists:zip(Extents, Positions)),
- ResultExtent = [make_extent(0, label_width(Label)) | merge_extent_list(PExtents)],
- ResultTree = Node#pnode{pos = 0, children = PTrees},
- {ResultTree, ResultExtent}.
- draw_designed_tree(Canvas, X, Y,
- #pnode{label = Label, pos = Pos, children = Children}) ->
- NewX = X + ?LINE_X_OFFSET,
- NewY = Y - ?LINE_Y_OFFSET,
- gs:line(Canvas, [{coords, [
- {NewX, NewY - ?LINE_VERTICAL_LENGTH},
- {NewX, NewY},
- {NewX + Pos, NewY},
- {NewX + Pos, NewY + ?LINE_VERTICAL_LENGTH}
- ]}]),
- gs:text(Canvas, [
- {coords, [{X + Pos, Y}]},
- {text, Label}
- ]),
- lists:map(
- fun(Node) ->
- draw_designed_tree(Canvas, X + Pos, Y + ?LAYER_HEIGHT, Node)
- end,
- Children),
- ok.
- loop() ->
- receive
- {gs, ui_main_window, destroy, _Data, _Args} ->
- ok;
- _Other ->
- loop()
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement