;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; scrollbar widget
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
define new-scrollbar-widget(type)
  define super new-basic-widget()
  define min-value 0
  define max-value 100
  define current-value 0
  define host-id #nil
  ;;
  define horiz?()
    {super[direction:] = HORIZ}
  ;;
  method-lambda scrollbar-widget
    super: (self)
      super
    type: (self)
      type
    selectable?: (self)
      #f
    ;;
    host-id: (self)
      host-id
    host-id-set!: (self value)
      {host-id := value}
      self
    ;;
    min-value: (self)
      min-value
    min-value-set!: (self value)
      assert {number? value} "invalid scrollbar min value"
      if {min-value <> value}
        then
          {min-value := value}
          ;need-repaint!()
      self
    ;;
    max-value: (self)
      max-value
    max-value-set!: (self value)
      assert {number? value} "invalid scrollbar max value"
      if {max-value <> value}
        then
          {max-value := value}
          ;need-repaint!()
      self
    ;;
    current-value: (self)
      current-value
    current-value-set!: (self value)
      assert {number? value} "invalid scrollbar current value"
      if {current-value <> value}
        then
          {current-value := value}
          ;need-repaint!()
      self
    ;;
    ;; return number of filled pixels
    %calc-pos: (self)
      define res
      ;define old-curr current-value
      if {min-value > max-value}
        then
          {res := min-value}
          {min-value := max-value}
          {max-value := res}
      {current-value := clamp(current-value min-value max-value)}
      define size {(if horiz?() self[final-width:] self[final-height:]) - 2}
      define len {max-value - min-value}
      if {{positive? len} and {positive? size}}
        {res := trunc{{size / len} * current-value}}
        {res := 0}
      ;printf "min=%o; max=%o; curr=%o; res=%o\n" min-value max-value current-value res
      ;;
      ;if {current-value <> old-curr}
      ;  need-repaint!()
      res
    ;;
    %calc-value: (self pos)
      define res #f
      define size {(if horiz?() self[final-width:] self[final-height:]) - 2}
      ;define old-curr current-value
      if (and {size > 1}
              {min-value < max-value}
              between?(pos -1 size))
        then
          define len {max-value - min-value}
          if {{positive? len} and {positive? size}}
            {res := clamp({min-value + {len * {{pos + 1} / size}}} min-value max-value)}
          ;printf "pos=%o; size=%o; min=%o; max=%o; res=%o\n" pos size min-value max-value res
      res
    ;;
    paint: (self)
      define host self[find-widget: self[host-id:]]
      if {not-null? host}
        if horiz?()
          then
            {self[min-value:] := host[h-scrollbar-min:]}
            {self[max-value:] := host[h-scrollbar-max:]}
            {self[current-value:] := host[h-scrollbar-current:]}
          else
            {self[min-value:] := host[v-scrollbar-min:]}
            {self[max-value:] := host[v-scrollbar-max:]}
            {self[current-value:] := host[v-scrollbar-current:]}
      define wdt self[final-width:]
      define hgt self[final-height:]
      define fc self[style-color-prop: "full"]
      define filled self[%calc-pos:]
      lgfx:draw-round-rect 0 0 wdt hgt self[style-color-prop: "frame"]
      self[update-clip-rect: 1 1 {wdt - 2} {hgt - 2}]
      if {self[min-value:] >= self[max-value:]}
        lgfx:fill-rect 0 0 wdt hgt fc
        else
          lgfx:fill-rect 0 0 wdt hgt self[style-color-prop: "empty"]
          cond
            horiz?()
              if {positive? filled}
                lgfx:fill-rect 1 1 filled {hgt - 2} fc
            else
              if {positive? filled}
                lgfx:fill-rect 1 1 {wdt - 2} filled fc
      self
    ;;
    handle-event: (self evt)
      define process-mouse-xy(self x y)
        define host self[find-widget: self[host-id:]]
        if {not-null? host}
          then
            define size
            define pos
            if horiz?()
              then
                {size := {self[final-width:] - 2}}
                {pos := {x - 1}}
              else
                {size := {self[final-height:] - 2}}
                {pos := {y - 1}}
            if {{size > 1} and between?(pos -1 size)}
              then
                evt[eat!:]
                if horiz?()
                  host[h-scrollbar-scroll-to: self[%calc-value: pos]]
                  host[v-scrollbar-scroll-to: self[%calc-value: pos]]
      ;;
      if evt[alive?:]
        case evt[type:]
          (MOUSE-DOWN)
            process-mouse-xy self evt[x:] evt[y:]
          (MOUSE-MOTION)
            if {evt[destination:] eq? self}
              then
                process-mouse-xy self evt[x:] evt[y:]
                evt[eat!:]
          else #void
      if evt[alive?:]
        inherited handle-event: evt
    ;;
    handle-property: (self name value)
      self[property-changed: name value]
      case name
        (host-id:)
          {self[host-id:] := value}
          #t
        (min-value:)
          {self[min-value:] := value}
          #t
        (max-value:)
          {self[max-value:] := value}
          #t
        (current-value:)
          {self[current-value:] := value}
          #t
        else
          inherited handle-property: name value
    ;;
    else
      super


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
register-widget v-scrollbar:
  lambda v-scrollbar-ctor ()
    new-scrollbar-widget(v-scrollbar:)

register-widget h-scrollbar:
  lambda h-scrollbar-ctor ()
    new-scrollbar-widget(h-scrollbar:)
