@@ -18,11 +18,19 @@ func init() {
18
18
19
19
type PaintFunc func (canvas * Canvas , updateBounds Rectangle ) error
20
20
21
+ type PaintMode int
22
+
23
+ const (
24
+ PaintNormal PaintMode = iota // erase background before PaintFunc
25
+ PaintNoErase // PaintFunc clears background, single buffered
26
+ PaintBuffered // PaintFunc clears background, double buffered
27
+ )
28
+
21
29
type CustomWidget struct {
22
30
WidgetBase
23
31
paint PaintFunc
24
- clearsBackground bool
25
32
invalidatesOnResize bool
33
+ paintMode PaintMode
26
34
}
27
35
28
36
func NewCustomWidget (parent Container , style uint , paint PaintFunc ) (* CustomWidget , error ) {
@@ -48,12 +56,20 @@ func (cw *CustomWidget) SizeHint() Size {
48
56
return Size {100 , 100 }
49
57
}
50
58
59
+ // deprecated, use PaintMode
51
60
func (cw * CustomWidget ) ClearsBackground () bool {
52
- return cw .clearsBackground
61
+ return cw .paintMode != PaintNormal
53
62
}
54
63
64
+ // deprecated, use SetPaintMode
55
65
func (cw * CustomWidget ) SetClearsBackground (value bool ) {
56
- cw .clearsBackground = value
66
+ if value != cw .ClearsBackground () {
67
+ if value {
68
+ cw .paintMode = PaintNoErase
69
+ } else {
70
+ cw .paintMode = PaintNormal
71
+ }
72
+ }
57
73
}
58
74
59
75
func (cw * CustomWidget ) InvalidatesOnResize () bool {
@@ -64,6 +80,14 @@ func (cw *CustomWidget) SetInvalidatesOnResize(value bool) {
64
80
cw .invalidatesOnResize = value
65
81
}
66
82
83
+ func (cw * CustomWidget ) PaintMode () PaintMode {
84
+ return cw .paintMode
85
+ }
86
+
87
+ func (cw * CustomWidget ) SetPaintMode (value PaintMode ) {
88
+ cw .paintMode = value
89
+ }
90
+
67
91
func (cw * CustomWidget ) WndProc (hwnd win.HWND , msg uint32 , wParam , lParam uintptr ) uintptr {
68
92
switch msg {
69
93
case win .WM_PAINT :
@@ -89,14 +113,18 @@ func (cw *CustomWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintpt
89
113
defer canvas .Dispose ()
90
114
91
115
r := & ps .RcPaint
92
- err = cw .paint (
93
- canvas ,
94
- Rectangle {
95
- int (r .Left ),
96
- int (r .Top ),
97
- int (r .Right - r .Left ),
98
- int (r .Bottom - r .Top ),
99
- })
116
+ bounds := Rectangle {
117
+ int (r .Left ),
118
+ int (r .Top ),
119
+ int (r .Right - r .Left ),
120
+ int (r .Bottom - r .Top ),
121
+ }
122
+ if cw .paintMode == PaintBuffered {
123
+ err = cw .bufferedPaint (canvas , bounds )
124
+ } else {
125
+ err = cw .paint (canvas , bounds )
126
+ }
127
+
100
128
if err != nil {
101
129
newError ("paint failed" )
102
130
break
@@ -105,7 +133,7 @@ func (cw *CustomWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintpt
105
133
return 0
106
134
107
135
case win .WM_ERASEBKGND :
108
- if ! cw .clearsBackground {
136
+ if cw .paintMode != PaintNormal {
109
137
return 1
110
138
}
111
139
@@ -117,3 +145,46 @@ func (cw *CustomWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintpt
117
145
118
146
return cw .WidgetBase .WndProc (hwnd , msg , wParam , lParam )
119
147
}
148
+
149
+ func (cw * CustomWidget ) bufferedPaint (canvas * Canvas , updateBounds Rectangle ) error {
150
+ hdc := win .CreateCompatibleDC (canvas .hdc )
151
+ if hdc == 0 {
152
+ return newError ("CreateCompatibleDC failed" )
153
+ }
154
+ defer win .DeleteDC (hdc )
155
+
156
+ buffered := Canvas {hdc : hdc , doNotDispose : true }
157
+ if _ , err := buffered .init (); err != nil {
158
+ return err
159
+ }
160
+
161
+ w , h := int32 (updateBounds .Width ), int32 (updateBounds .Height )
162
+ if w < 1 {
163
+ w = 1
164
+ }
165
+ if h < 1 {
166
+ h = 1
167
+ }
168
+ hbmp := win .CreateCompatibleBitmap (canvas .hdc , w , h )
169
+ if hbmp == 0 {
170
+ return lastError ("CreateCompatibleBitmap failed" )
171
+ }
172
+ defer win .DeleteObject (win .HGDIOBJ (hbmp ))
173
+
174
+ oldbmp := win .SelectObject (buffered .hdc , win .HGDIOBJ (hbmp ))
175
+ if oldbmp == 0 {
176
+ return newError ("SelectObject failed" )
177
+ }
178
+ defer win .SelectObject (buffered .hdc , oldbmp )
179
+
180
+ err := cw .paint (& buffered , updateBounds )
181
+
182
+ if ! win .BitBlt (canvas .hdc ,
183
+ int32 (updateBounds .X ), int32 (updateBounds .Y ), w , h ,
184
+ buffered .hdc ,
185
+ int32 (updateBounds .X ), int32 (updateBounds .Y ), win .SRCCOPY ) {
186
+ return lastError ("buffered BitBlt failed" )
187
+ }
188
+
189
+ return err
190
+ }
0 commit comments