Mercurial > projects > dynamin
annotate dynamin/gui/button.d @ 78:651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Sat, 06 Feb 2010 15:12:52 -0600 |
parents | 84beb40c1665 |
children | 73060bc3f004 |
rev | line source |
---|---|
0 | 1 // Written in the D programming language |
2 // www.digitalmars.com/d/ | |
3 | |
4 /* | |
5 * The contents of this file are subject to the Mozilla Public License Version | |
6 * 1.1 (the "License"); you may not use this file except in compliance with | |
7 * the License. You may obtain a copy of the License at | |
8 * http://www.mozilla.org/MPL/ | |
9 * | |
10 * Software distributed under the License is distributed on an "AS IS" basis, | |
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 * for the specific language governing rights and limitations under the | |
13 * License. | |
14 * | |
15 * The Original Code is the Dynamin library. | |
16 * | |
17 * The Initial Developer of the Original Code is Jordan Miner. | |
18 * Portions created by the Initial Developer are Copyright (C) 2006-2009 | |
19 * the Initial Developer. All Rights Reserved. | |
20 * | |
21 * Contributor(s): | |
22 * Jordan Miner <jminer7@gmail.com> | |
23 * | |
24 */ | |
25 | |
26 module dynamin.gui.button; | |
27 | |
28 import dynamin.all_core; | |
29 import dynamin.all_gui; | |
30 import dynamin.all_painting; | |
62 | 31 import dynamin.gui.control; |
32 import dynamin.gui.events; | |
0 | 33 import tango.io.Stdout; |
34 import dynamin.c.cairo; // TODO: remove | |
35 | |
36 // TODO: maybe change to ControlState and add Disabled ? | |
37 enum ButtonState { | |
38 Normal, Hot, Pressed | |
39 } | |
40 // TODO: move to another file | |
41 enum TextImageRelation { | |
42 Overlay, TextBeforeImage, ImageBeforeText, TextAboveImage, ImageAboveText | |
43 } | |
44 | |
45 /** | |
46 * A button is a control that can be clicked to perform an action. | |
47 * | |
48 * The appearance of a button with Windows Classic: | |
49 * | |
50 * $(IMAGE ../web/example_button.png) | |
51 */ | |
52 class Button : Control { | |
53 protected: | |
62 | 54 package bool _isDefault; |
0 | 55 ButtonState _state; |
62 | 56 override void whenFocusGained(EventArgs e) { |
57 super.whenFocusGained(e); | |
58 auto anc = findAncestor((Container c) { | |
59 return c.defaultButton !is null; | |
60 }); | |
61 if(anc) { | |
62 foreach(d; &anc.descendants) { | |
63 if(auto b = cast(Button)d) | |
64 b._isDefault = false; | |
65 } | |
66 } | |
67 _isDefault = true; | |
68 } | |
69 override void whenFocusLost(EventArgs e) { | |
70 super.whenFocusLost(e); | |
71 _isDefault = false; | |
72 auto anc = findAncestor((Container c) { | |
73 return c.defaultButton !is null; | |
74 }); | |
75 if(anc) | |
76 anc.defaultButton._isDefault = true; | |
77 } | |
0 | 78 override void whenMouseDragged(MouseEventArgs e) { |
79 if(contains(e.x, e.y)) | |
80 state = ButtonState.Pressed; | |
81 else | |
82 state = ButtonState.Normal; | |
83 } | |
84 override void whenMouseEntered(EventArgs e) { | |
85 state = ButtonState.Hot; | |
86 } | |
87 override void whenMouseLeft(EventArgs e) { | |
88 state = ButtonState.Normal; | |
89 } | |
90 override void whenMouseDown(MouseEventArgs e) { | |
91 if(e.button == MouseButton.Left) { | |
92 state = ButtonState.Pressed; | |
93 focus(); | |
94 } | |
95 } | |
96 override void whenMouseUp(MouseEventArgs e) { | |
97 if(state != ButtonState.Pressed) return; | |
98 state = ButtonState.Hot; | |
99 clicked(new EventArgs); | |
100 } | |
101 override void whenKeyDown(KeyEventArgs e) { | |
62 | 102 if(e.key == Key.Space) { |
0 | 103 state = ButtonState.Pressed; |
62 | 104 e.stopped = true; |
105 } else if(e.key == Key.Enter) { // being default is implied in keyDown | |
106 scope e2 = new EventArgs; | |
107 clicked(e2); | |
108 e.stopped = true; | |
109 } | |
0 | 110 } |
111 override void whenKeyUp(KeyEventArgs e) { | |
112 if(e.key == Key.Space) { | |
113 if(state != ButtonState.Pressed) return; | |
114 state = ButtonState.Normal; | |
62 | 115 scope e2 = new EventArgs; |
116 clicked(e2); | |
117 e.stopped = true; | |
0 | 118 } |
119 } | |
120 override void whenPainting(PaintingEventArgs e) { | |
121 Theme.current.Button_paint(this, e.graphics); | |
122 return; | |
123 // TODO: move to a theme or delete | |
124 with(e.graphics) { | |
125 if(_state == ButtonState.Hot) | |
126 source = Color(200, 0, 0); | |
127 else if(_state == ButtonState.Pressed) | |
128 source = Color(110, 0, 0); | |
129 else | |
130 source = Color(220, 80, 80); | |
131 moveTo(3, 0); | |
132 lineTo(width-3, 0); | |
133 lineTo(width, 3); | |
134 lineTo(width, height-3); | |
135 lineTo(width-3, height); | |
136 lineTo(3, height); | |
137 lineTo(0, height-3); | |
138 lineTo(0, 3); | |
139 closePath(); | |
140 fill(); | |
141 auto grad = cairo_pattern_create_linear(0, 0, 0, height/2+3); | |
142 cairo_pattern_add_color_stop_rgba(grad, 0, 1, 1, 1, .4); | |
143 cairo_pattern_add_color_stop_rgba(grad, 1, 1, 1, 1, .05); | |
144 cairo_set_source(handle, grad); | |
145 cairo_pattern_destroy(grad); | |
146 moveTo(3, 0); | |
147 lineTo(width-3, 0); | |
148 lineTo(width, 3); | |
149 lineTo(width, cast(int)height/2-3); | |
150 lineTo(width-3, cast(int)height/2); | |
151 lineTo(3, cast(int)height/2); | |
152 lineTo(0, cast(int)height/2+3); | |
153 lineTo(0, 3); | |
154 closePath(); | |
155 fill(); | |
156 | |
157 source = _state == ButtonState.Pressed ? Color.White : Color.Black; | |
158 fontSize = 13; | |
159 drawText(text, 5, height/2); | |
160 } | |
161 return; | |
162 | |
163 } | |
164 public void paintFore(Graphics g) { | |
165 auto extents = g.getTextExtents(text); | |
166 g.drawText(text, (width-extents.width)/2, (height-extents.height)/2); | |
167 } | |
168 | |
169 public: | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
170 /// Override this method in a subclass to handle the clicked event. |
0 | 171 protected void whenClicked(EventArgs e) { } |
172 /// This event occurs after the button has been clicked. | |
10
ccc108b25a0a
Convert to using a struct for events. Fix some comments too.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
173 Event!(whenClicked) clicked; |
0 | 174 |
63 | 175 /// |
0 | 176 this() { |
78
651082a9b364
Add Event.setUp() and use in place of mainHandler and dispatcher.
Jordan Miner <jminer7@gmail.com>
parents:
63
diff
changeset
|
177 clicked.setUp(&whenClicked); |
0 | 178 _focusable = true; |
179 } | |
63 | 180 /// |
0 | 181 this(string text) { |
182 this(); | |
183 this.text = text; | |
184 } | |
185 override Size bestSize() { return Theme.current.Button_bestSize(this); } | |
63 | 186 /// |
0 | 187 ButtonState state() { return _state; } |
63 | 188 /// |
0 | 189 void state(ButtonState s) { _state = s; repaint(); } |
62 | 190 /** |
191 * Returns true if this button should be painted as being default. | |
192 * Mainly for themes. | |
193 */ | |
194 bool isDefault() { return _isDefault; } | |
0 | 195 } |