4
%% Copyright Ericsson AB 2009. All Rights Reserved.
6
%% The contents of this file are subject to the Erlang Public License,
7
%% Version 1.1, (the "License"); you may not use this file except in
8
%% compliance with the License. You should have received a copy of the
9
%% Erlang Public License along with this software. If not, it can be
10
%% retrieved online at http://www.erlang.org/.
12
%% Software distributed under the License is distributed on an "AS IS"
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
%% the License for the specific language governing rights and limitations
19
-module(ex_canvas_paint).
21
-behavoiur(wx_object).
26
%% wx_object callbacks
27
-export([init/1, terminate/2, code_change/3,
28
handle_info/2, handle_call/3, handle_event/2, handle_sync_event/3]).
30
-include_lib("wx/include/wx.hrl").
44
wx_object:start_link(?MODULE, Config, []).
46
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48
wx:batch(fun() -> do_init(Config) end).
51
Parent = proplists:get_value(parent, Config),
52
Panel = wxPanel:new(Parent, []),
55
MainSizer = wxBoxSizer:new(?wxVERTICAL),
56
Sizer = wxStaticBoxSizer:new(?wxVERTICAL, Panel,
58
Canvas = wxPanel:new(Panel, [{style, ?wxFULL_REPAINT_ON_RESIZE}]),
59
wxPanel:setToolTip(Panel,
60
"Left-click and hold to draw something - release to stop drawing.\n"
61
"Middle-click to fill with pink\n"
62
"Middle-dclick to fill with white.\n"
63
"Right-click to clear."),
65
Brush = wxBrush:new(?wxWHITE),
66
Pen = wxPen:new(?wxBLACK, [{width, 2}]),
69
wxSizer:add(Sizer, Canvas, [{flag, ?wxEXPAND},
72
wxSizer:add(MainSizer, Sizer, [{flag, ?wxEXPAND},
74
{W,H} = wxPanel:getSize(Canvas),
75
Bitmap = wxBitmap:new(W,H),
77
wxPanel:connect(Canvas, paint, [callback]),
78
wxPanel:connect(Canvas, size),
79
wxPanel:connect(Canvas, left_down),
80
wxPanel:connect(Canvas, left_dclick),
81
wxPanel:connect(Canvas, left_up),
82
wxPanel:connect(Canvas, right_down),
83
wxPanel:connect(Canvas, middle_down),
84
wxPanel:connect(Canvas, middle_dclick),
85
wxPanel:setSizer(Panel, MainSizer),
86
wxSizer:layout(MainSizer),
87
{Panel, #state{parent=Panel, config=Config,
88
canvas = Canvas, pen = Pen,
89
brush = Brush, bitmap = Bitmap}}.
91
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92
%% Callbacks handled as normal gen_server callbacks
93
handle_info(Msg, State) ->
94
demo:format(State#state.config, "Got Info ~p\n", [Msg]),
97
handle_call(Msg, _From, State) ->
98
demo:format(State#state.config, "Got Call ~p\n", [Msg]),
99
{reply,{error, nyi}, State}.
101
%% Sync event from callback events, paint event must be handled in callbacks
102
%% otherwise nothing will be drawn on windows.
103
handle_sync_event(#wx{event = #wxPaint{}}, _wxObj, #state{canvas=Canvas, bitmap=Bitmap}) ->
104
DC = wxPaintDC:new(Canvas),
106
wxPaintDC:destroy(DC),
109
%% Async Events are handled in handle_event as in handle_info
111
handle_event(#wx{event = #wxMouse{type = motion, x = X, y = Y}},
112
State = #state{canvas = Canvas, pen = Pen, brush = Brush}) ->
114
fun(DC) -> wxDC:setPen(DC, Pen),
115
wxBrush:setColour(Brush, ?wxBLACK),
116
wxDC:setBrush(DC, Brush),
117
wxDC:drawLine(DC, {X,Y}, State#state.old_pos)
119
draw(Canvas,State#state.bitmap, Fun),
120
{noreply, State#state{old_pos = {X,Y}}};
121
handle_event(#wx{event = #wxSize{size = {W,H}}}, State = #state{bitmap=Prev}) ->
122
wxBitmap:destroy(Prev),
123
Bitmap = wxBitmap:new(W,H),
124
draw(State#state.canvas, Bitmap, fun(DC) -> wxDC:clear(DC) end),
125
{noreply, State#state{bitmap=Bitmap}};
126
handle_event(#wx{event = #wxMouse{type = left_dclick,x = X,y = Y}}, State = #state{}) ->
127
wxPanel:connect(State#state.canvas, motion),
128
{noreply, State#state{old_pos = {X,Y}}};
129
handle_event(#wx{event = #wxMouse{type = left_down,x = X,y = Y}}, State = #state{}) ->
130
wxPanel:connect(State#state.canvas, motion),
131
{noreply, State#state{old_pos = {X,Y}}};
133
%% Fill with pink color
134
handle_event(#wx{event = #wxMouse{type = middle_down,x = X, y =Y}}, State = #state{}) ->
136
fun(DC) -> wxBrush:setColour(State#state.brush, {255,125,255,255}),
137
wxDC:setBrush(DC, State#state.brush),
138
wxDC:floodFill(DC, {X,Y}, ?wxBLACK, [{style, ?wxFLOOD_BORDER}])
141
draw(State#state.canvas, State#state.bitmap, Fun),
144
%% Fill with white color
145
handle_event(#wx{event = #wxMouse{type = middle_dclick,x = X, y =Y}}, State = #state{}) ->
147
fun(DC) -> wxBrush:setColour(State#state.brush, ?wxWHITE),
148
wxDC:setBrush(DC, State#state.brush),
149
wxDC:floodFill(DC, {X,Y}, ?wxBLACK, [{style, ?wxFLOOD_BORDER}])
152
draw(State#state.canvas, State#state.bitmap,Fun),
154
handle_event(#wx{event = #wxMouse{type = left_up}}, State = #state{}) ->
155
wxPanel:disconnect(State#state.canvas, motion),
157
handle_event(#wx{event = #wxMouse{type = right_down}}, State = #state{}) ->
158
draw(State#state.canvas, State#state.bitmap, fun(DC) -> wxDC:clear(DC) end),
160
handle_event(Ev = #wx{}, State = #state{}) ->
161
demo:format(State#state.config, "Got Event ~p\n", [Ev]),
164
code_change(_, _, State) ->
165
{stop, ignore, State}.
167
terminate(_Reason, _State) ->
170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
174
draw(Canvas, Bitmap, Fun) ->
175
MemoryDC = wxMemoryDC:new(Bitmap),
176
CDC = wxClientDC:new(Canvas),
180
wxDC:blit(CDC, {0,0},
181
{wxBitmap:getWidth(Bitmap), wxBitmap:getHeight(Bitmap)},
184
wxClientDC:destroy(CDC),
185
wxMemoryDC:destroy(MemoryDC).
188
redraw(DC, Bitmap) ->
189
MemoryDC = wxMemoryDC:new(Bitmap),
192
{wxBitmap:getWidth(Bitmap), wxBitmap:getHeight(Bitmap)},
195
wxMemoryDC:destroy(MemoryDC).