Home Segments Index Top Previous Next

904: Mainline

Here, then, is the method:

Meter method definition • instance 
displayOn: thePen 
  | meterWidth meterHeight xLft yBot xPointer yPointer 
    ptrHeight ptrHalfWidth dialArray stringHandle modelValue  
    range step tics tickPlace tickHeight| 
  thePen clear. 
  meterHeight := 30. ptrHeight := 10.  ptrHalfWidth := 5. 
  meterWidth := self bounds width * 3 // 4. 
  xLft := self bounds width - meterWidth // 2. 
  yBot := self bounds height * 3 // 8. 
  "Draw frame for meter" 
  thePen displayRectangularBorder: 
       ((0 @ 0)  
        extent: (meterWidth + (ptrHalfWidth * 2)) @ meterHeight) 
     at: ((xLft - ptrHalfWidth) @ yBot). 
  "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 
	        displayLineFrom: (tickPlace @ yBot) 
                             to: (tickPlace @ (yBot + tickHeight))]. 
  "Write title" 
  title notNil 
    ifTrue: 
      [thePen displayString: title 
          at: ((self bounds width) 
               - (title asComposedText width) // 2)  
              @ (yBot + meterHeight + (thePen font height * 1.1))]. 
  "Write scale minimum, middle, and maximum" 
  min notNil & max notNil 
    ifTrue: 
      [thePen displayString: (stringHandle := min printString) 
          at: (xLft - (stringHandle asComposedText width // 2)) 
              @ (yBot - (thePen font height * 0.2)) asInteger. 
       thePen displayString: 
            (stringHandle := (max - min // 2) printString) 
          at: 
            (xLft + (meterWidth  
                     - stringHandle asComposedText width // 2)) 
            @ (yBot - (thePen font height * 0.2)). 
       thePen displayString: max printString 
          at: (xLft + meterWidth  
               - (min printString asComposedText width // 2)) 
              @ (yBot - (thePen font height * 0.2))]. 
  "Continued ..." 
  "Draw pointer, if modelValue set" 
  modelValue := self model value. 
  min notNil & max notNil & modelValue notNil 
             & (modelValue >= min) & (modelValue <= max) 
    ifTrue: 
      [xPointer :=  
         (((modelValue - min) * meterWidth // (max - min)))  
         + xLft. 
       yPointer := yBot + meterHeight - 1. 
       dialArray := Array 
                      with: ((xPointer + ptrHalfWidth) @ yPointer) 
                      with: (xPointer @ (yPointer - ptrHeight)) 
                      with: ((xPointer - ptrHalfWidth) @ yPointer). 
       thePen displayPolygon: dialArray]