diff --git a/Meter.c b/Meter.c index 3dbdfcc66..be3cc4347 100644 --- a/Meter.c +++ b/Meter.c @@ -24,6 +24,10 @@ in the source distribution for its full text. #include "XUtils.h" +#ifndef UINT32_WIDTH +#define UINT32_WIDTH 32 +#endif + #define GRAPH_HEIGHT 4 /* Unit: rows (lines) */ typedef struct MeterMode_ { @@ -380,7 +384,9 @@ Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type if (Meter_initFn(this)) { Meter_init(this); } + Meter_setMode(this, type->defaultMode); + assert(this->mode > 0); return this; } @@ -439,21 +445,28 @@ void Meter_setCaption(Meter* this, const char* caption) { } void Meter_setMode(Meter* this, MeterModeId modeIndex) { - if (modeIndex > 0 && modeIndex == this->mode) { + if (modeIndex == this->mode) { + assert(this->mode > 0); return; } - if (modeIndex == 0) { - modeIndex = 1; + uint32_t supportedModes = Meter_supportedModes(this); + if (!supportedModes) { + supportedModes = METERMODE_DEFAULT_SUPPORTED; } + assert(supportedModes); + assert(!(supportedModes & (1 << 0))); - assert(modeIndex < LAST_METERMODE); + assert(LAST_METERMODE <= UINT32_WIDTH); + if (modeIndex >= LAST_METERMODE || !(supportedModes & (1UL << modeIndex))) + return; + + assert(modeIndex >= 1); if (Meter_updateModeFn(this)) { assert(Meter_drawFn(this)); this->draw = Meter_drawFn(this); Meter_updateMode(this, modeIndex); } else { - assert(modeIndex >= 1); free(this->drawData.values); this->drawData.values = NULL; this->drawData.nValues = 0; @@ -465,6 +478,23 @@ void Meter_setMode(Meter* this, MeterModeId modeIndex) { this->mode = modeIndex; } +MeterModeId Meter_nextSupportedMode(const Meter* this) { + uint32_t supportedModes = Meter_supportedModes(this); + if (!supportedModes) { + supportedModes = METERMODE_DEFAULT_SUPPORTED; + } + assert(supportedModes); + + assert(this->mode < UINT32_WIDTH); + uint32_t modeMask = ((uint32_t)-1 << 1) << this->mode; + uint32_t nextModes = supportedModes & modeMask; + if (!nextModes) { + nextModes = supportedModes; + } + + return (MeterModeId)countTrailingZeros(nextModes); +} + ListItem* Meter_toListItem(const Meter* this, bool moving) { char mode[20]; if (this->mode > 0) { diff --git a/Meter.h b/Meter.h index 0d93759f6..6394ac342 100644 --- a/Meter.h +++ b/Meter.h @@ -65,6 +65,7 @@ typedef struct MeterClass_ { const Meter_GetCaption getCaption; const Meter_GetUiName getUiName; const MeterModeId defaultMode; + const uint32_t supportedModes; /* bitset of supported modes, 1<getUiName((const Meter*)(this_),n_,l_) #define Meter_getCaptionFn(this_) As_Meter(this_)->getCaption #define Meter_getCaption(this_) (Meter_getCaptionFn(this_) ? As_Meter(this_)->getCaption((const Meter*)(this_)) : (this_)->caption) +#define Meter_supportedModes(this_) As_Meter(this_)->supportedModes #define Meter_attributes(this_) As_Meter(this_)->attributes #define Meter_name(this_) As_Meter(this_)->name #define Meter_uiName(this_) As_Meter(this_)->uiName @@ -139,6 +141,8 @@ void Meter_setCaption(Meter* this, const char* caption); void Meter_setMode(Meter* this, MeterModeId modeIndex); +MeterModeId Meter_nextSupportedMode(const Meter* this); + ListItem* Meter_toListItem(const Meter* this, bool moving); extern const MeterClass BlankMeter_class; diff --git a/MeterMode.h b/MeterMode.h index fc5b7785a..8a4355417 100644 --- a/MeterMode.h +++ b/MeterMode.h @@ -19,4 +19,11 @@ enum MeterModeId_ { typedef unsigned int MeterModeId; +#define METERMODE_DEFAULT_SUPPORTED ( \ + (1 << BAR_METERMODE) | \ + (1 << TEXT_METERMODE) | \ + (1 << GRAPH_METERMODE) | \ + (1 << LED_METERMODE) | \ + 0) // Avoids edits when updating + #endif diff --git a/MetersPanel.c b/MetersPanel.c index 2b8049ca2..22b5daa77 100644 --- a/MetersPanel.c +++ b/MetersPanel.c @@ -108,9 +108,7 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) { if (!Vector_size(this->meters)) break; Meter* meter = (Meter*) Vector_get(this->meters, selected); - MeterModeId mode = meter->mode + 1; - if (mode == LAST_METERMODE) - mode = 1; + MeterModeId mode = Meter_nextSupportedMode(meter); Meter_setMode(meter, mode); Panel_set(super, selected, (Object*) Meter_toListItem(meter, this->moving)); result = HANDLED;