THE METER GRAPH PANE
MeterGraphPane class definition GraphPane subclass: #MeterGraphPane instanceVariableNames: 'min max value title' classVariableNames: '' poolDictionaries: 'ColorConstants' MeterGraphPane method definition instance setMin: aNumber min := aNumber MeterGraphPane method definition instance setMax: aNumber max := aNumber MeterGraphPane method definition instance setValue: aNumber value := aNumber MeterGraphPane method definition instance getValue ^ value MeterGraphPane method definition instance setTitle: aString title := aString MeterGraphPane method definition instance drawMeter | thePen meterWidth meterHeight xLft yBot xPointer yPointer ptrHeight ptrHalfWidth oldBackColor dialArray range step tics tickPlace tickHeight| self erase. thePen := self pen. meterHeight := 30. meterWidth := self width * 3 // 4. ptrHeight := 10. ptrHalfWidth := 5. xLft := self width - meterWidth // 2. yBot := self height * 3 // 8. "Draw frame for meter" thePen drawRectangle: ((xLft - ptrHalfWidth) @ yBot extent: (meterWidth + (ptrHalfWidth * 2)) @ meterHeight). "Draw tick marks. Adaped from code provided by Richard Lyon. Works well for all min and max values" range := max - min. range = 0 ifTrue: [self error: 'Cannot put tics in an interval of width zero']. range < 0 ifTrue: [step := -1. range := range negated] ifFalse: [step := 1]. [range <= 15] whileTrue: [range := range*10. step := step/10]. [range > 150] whileTrue: [range := range/10. step := step*10]. range <= 30 ifTrue: [tics := #(1 5 10)] ifFalse: [(range <= 60) ifTrue: [tics := #(2 10 20)] ifFalse: [tics := #(5 10 50)] ]. step := step * (tics at: 1). (((min // (step negated)) negated) to: (max // step)) do: [:k | (k \\ ((tics at: 3) / (tics at: 1)) = 0) ifTrue: [tickHeight := meterHeight * 3 // 4] ifFalse: [(k \\ ((tics at: 2) / (tics at: 1)) = 0) ifTrue: [tickHeight := meterHeight // 2] ifFalse: [tickHeight := meterHeight * 3 // 8]]. tickPlace := xLft + (k * meterWidth * step // max) - (min * meterWidth // range). thePen lineFrom: (tickPlace @ yBot) to: (tickPlace @ (yBot + tickHeight))]. "Write title" title notNil ifTrue: [thePen centerText: title at: ((self width) // 2) @ (yBot + meterHeight + (2 * thePen font height))]. "Write scale minimum, middle, and maximum" min notNil & max notNil ifTrue: [thePen centerText: min printString at: xLft @ yBot. thePen centerText: (max - min // 2 + min) printString at: (xLft + (meterWidth // 2)) @ yBot. thePen centerText: max printString at: (xLft + meterWidth) @ yBot]. "Draw pointer, if values set" min notNil & max notNil & value notNil & (value >= min) & (value <= max) ifTrue: [xPointer := (value - min) * meterWidth // (max - min) + xLft. yPointer := yBot + meterHeight - 1. oldBackColor := thePen backColor. thePen backColor: ClrBlack. dialArray := Array with: ((xPointer + ptrHalfWidth) @ yPointer) with: (xPointer @ (yPointer - ptrHeight)) with: ((xPointer - ptrHalfWidth) @ yPointer). thePen polygonFilled: dialArray. thePen backColor: oldBackColor]