Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wprogressindicator.c
1 /*
2  * Original idea and implementation by Frederik Schueler <fr.schueler@netsurf.de>
3  * Rewritten by Pascal Hofstee <daeron@windowmaker.info>
4  * - Added options to set min/max values
5  * - centralized drawing into one pain function
6  */
7
8 #include "WINGsP.h"
9
10 typedef struct W_ProgressIndicator {
11         W_Class widgetClass;
12         W_View *view;
13
14         int value;
15         int minValue;
16         int maxValue;
17
18         void *clientData;
19 } ProgressIndicator;
20
21 #define DEFAULT_PROGRESS_INDICATOR_WIDTH        276
22 #define DEFAULT_PROGRESS_INDICATOR_HEIGHT       16
23
24 /* define if only the ticks within the progress region should be displayed */
25 #undef SHOW_PROGRESS_TICKS_ONLY
26
27 static void didResizeProgressIndicator();
28
29 W_ViewDelegate _ProgressIndicatorDelegate = {
30         NULL,
31         NULL,
32         didResizeProgressIndicator,
33         NULL,
34         NULL
35 };
36
37 static void destroyProgressIndicator(ProgressIndicator * pPtr);
38 static void paintProgressIndicator(ProgressIndicator * pPtr);
39 static void handleEvents(XEvent * event, void *data);
40
41 WMProgressIndicator *WMCreateProgressIndicator(WMWidget * parent)
42 {
43         ProgressIndicator *pPtr;
44
45         pPtr = wmalloc(sizeof(ProgressIndicator));
46         memset(pPtr, 0, sizeof(ProgressIndicator));
47
48         pPtr->widgetClass = WC_ProgressIndicator;
49
50         pPtr->view = W_CreateView(W_VIEW(parent));
51         if (!pPtr->view) {
52                 wfree(pPtr);
53                 return NULL;
54         }
55
56         pPtr->view->self = pPtr;
57
58         pPtr->view->delegate = &_ProgressIndicatorDelegate;
59
60         WMCreateEventHandler(pPtr->view, ExposureMask | StructureNotifyMask, handleEvents, pPtr);
61
62         W_ResizeView(pPtr->view, DEFAULT_PROGRESS_INDICATOR_WIDTH, DEFAULT_PROGRESS_INDICATOR_HEIGHT);
63
64         /* Initialize ProgressIndicator Values */
65         pPtr->value = 0;
66         pPtr->minValue = 0;
67         pPtr->maxValue = 100;
68
69         return pPtr;
70 }
71
72 void WMSetProgressIndicatorMinValue(WMProgressIndicator * progressindicator, int value)
73 {
74         CHECK_CLASS(progressindicator, WC_ProgressIndicator);
75
76         progressindicator->minValue = value;
77         if (progressindicator->value < value) {
78                 progressindicator->value = value;
79                 if (progressindicator->view->flags.mapped) {
80                         paintProgressIndicator(progressindicator);
81                 }
82         }
83 }
84
85 void WMSetProgressIndicatorMaxValue(WMProgressIndicator * progressindicator, int value)
86 {
87         CHECK_CLASS(progressindicator, WC_ProgressIndicator);
88
89         progressindicator->maxValue = value;
90         if (progressindicator->value > value) {
91                 progressindicator->value = value;
92                 if (progressindicator->view->flags.mapped) {
93                         paintProgressIndicator(progressindicator);
94                 }
95         }
96 }
97
98 void WMSetProgressIndicatorValue(WMProgressIndicator * progressindicator, int value)
99 {
100         CHECK_CLASS(progressindicator, WC_ProgressIndicator);
101
102         progressindicator->value = value;
103
104         /* Check if value is within min/max-range */
105         if (progressindicator->minValue > value)
106                 progressindicator->value = progressindicator->minValue;
107
108         if (progressindicator->maxValue < value)
109                 progressindicator->value = progressindicator->maxValue;
110
111         if (progressindicator->view->flags.mapped) {
112                 paintProgressIndicator(progressindicator);
113         }
114 }
115
116 int WMGetProgressIndicatorMinValue(WMProgressIndicator * progressindicator)
117 {
118         CHECK_CLASS(progressindicator, WC_ProgressIndicator);
119
120         return progressindicator->minValue;
121 }
122
123 int WMGetProgressIndicatorMaxValue(WMProgressIndicator * progressindicator)
124 {
125         CHECK_CLASS(progressindicator, WC_ProgressIndicator);
126
127         return progressindicator->maxValue;
128 }
129
130 int WMGetProgressIndicatorValue(WMProgressIndicator * progressindicator)
131 {
132         CHECK_CLASS(progressindicator, WC_ProgressIndicator);
133
134         return progressindicator->value;
135 }
136
137 static void didResizeProgressIndicator(W_ViewDelegate * self, WMView * view)
138 {
139         WMProgressIndicator *pPtr = (WMProgressIndicator *) view->self;
140         int width = pPtr->view->size.width;
141         int height = pPtr->view->size.height;
142
143         assert(width > 0);
144         assert(height > 0);
145 }
146
147 static void paintProgressIndicator(ProgressIndicator * pPtr)
148 {
149         W_Screen *scr = pPtr->view->screen;
150         GC bgc;
151         GC wgc;
152         GC lgc;
153         GC dgc;
154         WMSize size = pPtr->view->size;
155         int perc, w, h;
156         double unit, i;
157         Pixmap buffer;
158
159         bgc = WMColorGC(scr->black);
160         wgc = WMColorGC(scr->white);
161         lgc = WMColorGC(scr->gray);
162         dgc = WMColorGC(scr->darkGray);
163
164         unit = (double)(size.width - 3.0) / 100;
165
166         buffer = XCreatePixmap(scr->display, pPtr->view->window, size.width, size.height, scr->depth);
167
168         XFillRectangle(scr->display, buffer, lgc, 0, 0, size.width, size.height);
169
170         /* Calculate size of Progress to draw and paint ticks */
171         perc = (pPtr->value - pPtr->minValue) * 100 / (pPtr->maxValue - pPtr->minValue);
172
173         w = (int)((double)(perc * unit));
174         h = size.height - 2;
175
176         if (w > (size.width - 3))
177                 w = size.width - 3;
178
179         if (w > 0) {
180                 XFillRectangle(scr->display, buffer, lgc, 2, 1, w, h);
181                 XFillRectangle(scr->display, buffer, scr->stippleGC, 2, 1, w, h);
182                 W_DrawRelief(scr, buffer, 2, 1, w, h, WRFlat);
183
184                 /* Draw Progress Marks */
185                 i = (5.0 * unit);
186
187 #ifdef SHOW_PROGRESS_TICKS_ONLY
188                 while ((int)i < w + 5) {
189 #else
190                 while ((int)i < (size.width - 3)) {
191 #endif
192                         XDrawLine(scr->display, buffer, dgc, (int)i + 2, h - 1, i + 2, h - 3);
193
194                         i += (5.0 * unit);
195
196 #ifdef SHOW_PROGRESS_TICKS_ONLY
197                         if ((int)i >= w)
198                                 break;
199 #endif
200
201                         XDrawLine(scr->display, buffer, dgc, (int)i + 2, h - 1, i + 2, h - 6);
202
203                         i += (5.0 * unit);
204                 }
205         }
206
207         XDrawLine(scr->display, buffer, bgc, w + 2, 1, w + 2, h + 1);
208         XDrawLine(scr->display, buffer, lgc, 2, h, w + 2, h);
209
210         XDrawLine(scr->display, buffer, dgc, 0, 0, 0, size.height - 1);
211         XDrawLine(scr->display, buffer, dgc, 0, 0, size.width, 0);
212         XDrawLine(scr->display, buffer, bgc, 1, 1, 1, size.height - 1);
213         XDrawLine(scr->display, buffer, bgc, 1, 1, size.width - 1, 1);
214
215         XDrawLine(scr->display, buffer, wgc, size.width - 1, 0, size.width - 1, size.height - 1);
216         XDrawLine(scr->display, buffer, wgc, 0, size.height - 1, size.width - 1, size.height - 1);
217
218         XCopyArea(scr->display, buffer, pPtr->view->window, scr->copyGC, 0, 0, size.width, size.height, 0, 0);
219
220         XFreePixmap(scr->display, buffer);
221 }
222
223 static void handleEvents(XEvent * event, void *data)
224 {
225         ProgressIndicator *pPtr = (ProgressIndicator *) data;
226
227         CHECK_CLASS(data, WC_ProgressIndicator);
228
229         switch (event->type) {
230         case Expose:
231                 if (event->xexpose.count != 0)
232                         break;
233                 paintProgressIndicator(pPtr);
234                 break;
235         case DestroyNotify:
236                 destroyProgressIndicator(pPtr);
237                 break;
238         }
239 }
240
241 static void destroyProgressIndicator(ProgressIndicator * pPtr)
242 {
243         WMRemoveNotificationObserver(pPtr);
244
245         wfree(pPtr);
246 }