// widgetSlider.c — Slider (trackbar) widget #include "widgetInternal.h" // ============================================================ // wgtSlider // ============================================================ WidgetT *wgtSlider(WidgetT *parent, int32_t minVal, int32_t maxVal) { WidgetT *w = widgetAlloc(parent, WidgetSliderE); if (w) { w->as.slider.value = minVal; w->as.slider.minValue = minVal; w->as.slider.maxValue = maxVal; w->as.slider.vertical = false; w->weight = 100; } return w; } // ============================================================ // wgtSliderGetValue // ============================================================ int32_t wgtSliderGetValue(const WidgetT *w) { VALIDATE_WIDGET(w, WidgetSliderE, 0); return w->as.slider.value; } // ============================================================ // wgtSliderSetValue // ============================================================ void wgtSliderSetValue(WidgetT *w, int32_t value) { VALIDATE_WIDGET_VOID(w, WidgetSliderE); if (value < w->as.slider.minValue) { value = w->as.slider.minValue; } if (value > w->as.slider.maxValue) { value = w->as.slider.maxValue; } w->as.slider.value = value; wgtInvalidatePaint(w); } // ============================================================ // widgetSliderCalcMinSize // ============================================================ void widgetSliderCalcMinSize(WidgetT *w, const BitmapFontT *font) { (void)font; if (w->as.slider.vertical) { w->calcMinW = SLIDER_THUMB_W + 4; w->calcMinH = SLIDER_THUMB_W * 5; } else { w->calcMinW = SLIDER_THUMB_W * 5; w->calcMinH = SLIDER_THUMB_W + 4; } } // ============================================================ // widgetSliderOnKey // ============================================================ void widgetSliderOnKey(WidgetT *w, int32_t key, int32_t mod) { (void)mod; int32_t step = 1; int32_t range = w->as.slider.maxValue - w->as.slider.minValue; if (range > 100) { step = range / 100; } if (w->as.slider.vertical) { if (key == (0x48 | 0x100)) { w->as.slider.value -= step; } else if (key == (0x50 | 0x100)) { w->as.slider.value += step; } else if (key == (0x47 | 0x100)) { w->as.slider.value = w->as.slider.minValue; } else if (key == (0x4F | 0x100)) { w->as.slider.value = w->as.slider.maxValue; } else { return; } } else { if (key == (0x4B | 0x100)) { w->as.slider.value -= step; } else if (key == (0x4D | 0x100)) { w->as.slider.value += step; } else if (key == (0x47 | 0x100)) { w->as.slider.value = w->as.slider.minValue; } else if (key == (0x4F | 0x100)) { w->as.slider.value = w->as.slider.maxValue; } else { return; } } w->as.slider.value = clampInt(w->as.slider.value, w->as.slider.minValue, w->as.slider.maxValue); if (w->onChange) { w->onChange(w); } wgtInvalidatePaint(w); } // ============================================================ // widgetSliderOnMouse // ============================================================ void widgetSliderOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { (void)root; hit->focused = true; int32_t range = hit->as.slider.maxValue - hit->as.slider.minValue; if (range <= 0) { return; } int32_t thumbRange; int32_t thumbPos; int32_t mousePos; if (hit->as.slider.vertical) { thumbRange = hit->h - SLIDER_THUMB_W; thumbPos = ((hit->as.slider.value - hit->as.slider.minValue) * thumbRange) / range; mousePos = vy - hit->y; if (mousePos >= thumbPos && mousePos < thumbPos + SLIDER_THUMB_W) { // Click on thumb — start drag sDragSlider = hit; sDragOffset = mousePos - thumbPos; } else { // Click on track — jump to position int32_t newVal = hit->as.slider.minValue + ((mousePos - SLIDER_THUMB_W / 2) * range) / thumbRange; if (newVal < hit->as.slider.minValue) { newVal = hit->as.slider.minValue; } if (newVal > hit->as.slider.maxValue) { newVal = hit->as.slider.maxValue; } hit->as.slider.value = newVal; if (hit->onChange) { hit->onChange(hit); } } } else { thumbRange = hit->w - SLIDER_THUMB_W; thumbPos = ((hit->as.slider.value - hit->as.slider.minValue) * thumbRange) / range; mousePos = vx - hit->x; if (mousePos >= thumbPos && mousePos < thumbPos + SLIDER_THUMB_W) { // Click on thumb — start drag sDragSlider = hit; sDragOffset = mousePos - thumbPos; } else { // Click on track — jump to position int32_t newVal = hit->as.slider.minValue + ((mousePos - SLIDER_THUMB_W / 2) * range) / thumbRange; if (newVal < hit->as.slider.minValue) { newVal = hit->as.slider.minValue; } if (newVal > hit->as.slider.maxValue) { newVal = hit->as.slider.maxValue; } hit->as.slider.value = newVal; if (hit->onChange) { hit->onChange(hit); } } } } // ============================================================ // widgetSliderPaint // ============================================================ void widgetSliderPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) { (void)font; uint32_t fg = w->fgColor ? w->fgColor : colors->contentFg; uint32_t tickFg = w->enabled ? fg : colors->windowShadow; uint32_t thumbFg = w->enabled ? colors->buttonFace : colors->scrollbarTrough; int32_t range = w->as.slider.maxValue - w->as.slider.minValue; if (range <= 0) { range = 1; } if (w->as.slider.vertical) { // Track groove int32_t trackX = w->x + (w->w - SLIDER_TRACK_H) / 2; BevelStyleT groove; groove.highlight = colors->windowShadow; groove.shadow = colors->windowHighlight; groove.face = colors->scrollbarTrough; groove.width = 1; drawBevel(d, ops, trackX, w->y, SLIDER_TRACK_H, w->h, &groove); // Thumb int32_t thumbRange = w->h - SLIDER_THUMB_W; int32_t thumbY = w->y + ((w->as.slider.value - w->as.slider.minValue) * thumbRange) / range; BevelStyleT thumb; thumb.highlight = colors->windowHighlight; thumb.shadow = colors->windowShadow; thumb.face = thumbFg; thumb.width = 2; drawBevel(d, ops, w->x, thumbY, w->w, SLIDER_THUMB_W, &thumb); // Center tick on thumb drawHLine(d, ops, w->x + 3, thumbY + SLIDER_THUMB_W / 2, w->w - 6, tickFg); } else { // Track groove int32_t trackY = w->y + (w->h - SLIDER_TRACK_H) / 2; BevelStyleT groove; groove.highlight = colors->windowShadow; groove.shadow = colors->windowHighlight; groove.face = colors->scrollbarTrough; groove.width = 1; drawBevel(d, ops, w->x, trackY, w->w, SLIDER_TRACK_H, &groove); // Thumb int32_t thumbRange = w->w - SLIDER_THUMB_W; int32_t thumbX = w->x + ((w->as.slider.value - w->as.slider.minValue) * thumbRange) / range; BevelStyleT thumb; thumb.highlight = colors->windowHighlight; thumb.shadow = colors->windowShadow; thumb.face = thumbFg; thumb.width = 2; drawBevel(d, ops, thumbX, w->y, SLIDER_THUMB_W, w->h, &thumb); // Center tick on thumb drawVLine(d, ops, thumbX + SLIDER_THUMB_W / 2, w->y + 3, w->h - 6, tickFg); } if (w->focused) { drawFocusRect(d, ops, w->x, w->y, w->w, w->h, fg); } }