windowmaker-wl/WINGs/wprogressindicator.c

244 lines
6.2 KiB
C

/*
* Original idea and implementation by Frederik Schueler <fr.schueler@netsurf.de>
* Rewritten by Pascal Hofstee <daeron@windowmaker.info>
* - Added options to set min/max values
* - centralized drawing into one pain function
*/
#include "WINGsP.h"
typedef struct W_ProgressIndicator {
W_Class widgetClass;
W_View *view;
int value;
int minValue;
int maxValue;
void *clientData;
} ProgressIndicator;
#define DEFAULT_PROGRESS_INDICATOR_WIDTH 276
#define DEFAULT_PROGRESS_INDICATOR_HEIGHT 16
/* define if only the ticks within the progress region should be displayed */
#undef SHOW_PROGRESS_TICKS_ONLY
static void didResizeProgressIndicator(W_ViewDelegate * self, WMView * view);
W_ViewDelegate _ProgressIndicatorDelegate = {
NULL,
NULL,
didResizeProgressIndicator,
NULL,
NULL
};
static void destroyProgressIndicator(ProgressIndicator * pPtr);
static void paintProgressIndicator(ProgressIndicator * pPtr);
static void handleEvents(WMEvent * event, void *data);
WMProgressIndicator *WMCreateProgressIndicator(WMWidget * parent)
{
ProgressIndicator *pPtr;
pPtr = wmalloc(sizeof(ProgressIndicator));
pPtr->widgetClass = WC_ProgressIndicator;
pPtr->view = W_CreateView(W_VIEW(parent));
if (!pPtr->view) {
wfree(pPtr);
return NULL;
}
pPtr->view->self = pPtr;
pPtr->view->delegate = &_ProgressIndicatorDelegate;
WMCreateEventHandler(pPtr->view, WM_EVMASK_EXPOSURE | WM_EVMASK_STRUCTURE_NOTIFY, handleEvents, pPtr);
W_ResizeView(pPtr->view, DEFAULT_PROGRESS_INDICATOR_WIDTH, DEFAULT_PROGRESS_INDICATOR_HEIGHT);
/* Initialize ProgressIndicator Values */
pPtr->value = 0;
pPtr->minValue = 0;
pPtr->maxValue = 100;
return pPtr;
}
void WMSetProgressIndicatorMinValue(WMProgressIndicator * progressindicator, int value)
{
CHECK_CLASS(progressindicator, WC_ProgressIndicator);
progressindicator->minValue = value;
if (progressindicator->value < value) {
progressindicator->value = value;
if (progressindicator->view->flags.mapped) {
paintProgressIndicator(progressindicator);
}
}
}
void WMSetProgressIndicatorMaxValue(WMProgressIndicator * progressindicator, int value)
{
CHECK_CLASS(progressindicator, WC_ProgressIndicator);
progressindicator->maxValue = value;
if (progressindicator->value > value) {
progressindicator->value = value;
if (progressindicator->view->flags.mapped) {
paintProgressIndicator(progressindicator);
}
}
}
void WMSetProgressIndicatorValue(WMProgressIndicator * progressindicator, int value)
{
CHECK_CLASS(progressindicator, WC_ProgressIndicator);
progressindicator->value = value;
/* Check if value is within min/max-range */
if (progressindicator->minValue > value)
progressindicator->value = progressindicator->minValue;
if (progressindicator->maxValue < value)
progressindicator->value = progressindicator->maxValue;
if (progressindicator->view->flags.mapped) {
paintProgressIndicator(progressindicator);
}
}
int WMGetProgressIndicatorMinValue(WMProgressIndicator * progressindicator)
{
CHECK_CLASS(progressindicator, WC_ProgressIndicator);
return progressindicator->minValue;
}
int WMGetProgressIndicatorMaxValue(WMProgressIndicator * progressindicator)
{
CHECK_CLASS(progressindicator, WC_ProgressIndicator);
return progressindicator->maxValue;
}
int WMGetProgressIndicatorValue(WMProgressIndicator * progressindicator)
{
CHECK_CLASS(progressindicator, WC_ProgressIndicator);
return progressindicator->value;
}
static void didResizeProgressIndicator(W_ViewDelegate * self, WMView * view)
{
WMProgressIndicator *pPtr = (WMProgressIndicator *) view->self;
int width = pPtr->view->size.width;
int height = pPtr->view->size.height;
/* Parameter not used, but tell the compiler that it is ok */
(void) self;
(void) width;
(void) height;
assert(width > 0);
assert(height > 0);
}
static void paintProgressIndicator(ProgressIndicator * pPtr)
{
W_Screen *scr = pPtr->view->screen;
const W_RenderBackend *R = scr->renderBackend;
void *rctx = scr->renderBackendCtx;
WMSize size = pPtr->view->size;
int perc, w, h;
double unit, i;
WMDrawable buffer;
unit = (double)(size.width - 3.0) / 100;
buffer = R->pixmap_create(rctx, size.width, size.height, scr->depth);
R->fill_rect(rctx, buffer, scr->gray, 0, 0, size.width, size.height);
/* Calculate size of Progress to draw and paint ticks */
perc = (pPtr->value - pPtr->minValue) * 100 / (pPtr->maxValue - pPtr->minValue);
w = (int)((double)(perc * unit));
h = size.height - 2;
if (w > (size.width - 3))
w = size.width - 3;
if (w > 0) {
R->fill_rect(rctx, buffer, scr->gray, 2, 1, w, h);
R->fill_stippled(rctx, buffer, scr->darkGray, 2, 1, w, h);
W_DrawRelief(scr, buffer, 2, 1, w, h, WRFlat);
/* Draw Progress Marks */
i = (5.0 * unit);
#ifdef SHOW_PROGRESS_TICKS_ONLY
while ((int)i < w + 5) {
#else
while ((int)i < (size.width - 3)) {
#endif
R->draw_line(rctx, buffer, scr->darkGray, (int)i + 2, h - 1, (int)i + 2, h - 3);
i += (5.0 * unit);
#ifdef SHOW_PROGRESS_TICKS_ONLY
if ((int)i >= w)
break;
#endif
R->draw_line(rctx, buffer, scr->darkGray, (int)i + 2, h - 1, (int)i + 2, h - 6);
i += (5.0 * unit);
}
}
R->draw_line(rctx, buffer, scr->black, w + 2, 1, w + 2, h + 1);
R->draw_line(rctx, buffer, scr->gray, 2, h, w + 2, h);
R->draw_line(rctx, buffer, scr->darkGray, 0, 0, 0, size.height - 1);
R->draw_line(rctx, buffer, scr->darkGray, 0, 0, size.width, 0);
R->draw_line(rctx, buffer, scr->black, 1, 1, 1, size.height - 1);
R->draw_line(rctx, buffer, scr->black, 1, 1, size.width - 1, 1);
R->draw_line(rctx, buffer, scr->white, size.width - 1, 0, size.width - 1, size.height - 1);
R->draw_line(rctx, buffer, scr->white, 0, size.height - 1, size.width - 1, size.height - 1);
R->pixmap_copy(rctx, buffer, (WMDrawable)pPtr->view->window, 0, 0, size.width, size.height, 0, 0);
R->pixmap_free(rctx, buffer);
}
static void handleEvents(WMEvent * event, void *data)
{
ProgressIndicator *pPtr = (ProgressIndicator *) data;
CHECK_CLASS(data, WC_ProgressIndicator);
switch (event->type) {
case WME_EXPOSE:
if (event->u.expose.count != 0)
break;
paintProgressIndicator(pPtr);
break;
case WME_DESTROY:
destroyProgressIndicator(pPtr);
break;
}
}
static void destroyProgressIndicator(ProgressIndicator * pPtr)
{
WMRemoveNotificationObserver(pPtr);
wfree(pPtr);
}