packages feed

yi-0.4.6: Yi/UI/Cocoa/TextView.hs

{-# LANGUAGE TemplateHaskell, EmptyDataDecls, MultiParamTypeClasses #-}
--
-- Copyright (c) 2008 Gustav Munkby
--

-- | This declares our special text-view class. The textview interpretes
--   mouse events so that mouse-selection in Yi should function as in any
--   Cocoa application

module Yi.UI.Cocoa.TextView
  ( YiTextView
  , _YiTextView
  , initializeClass_YiTextView
  , _runBuffer
  , YiScrollView
  , _YiScrollView
  , initializeClass_YiScrollView
  , _leftScroller
  , visibleRange
  )where

import Yi.Buffer hiding (runBuffer)
import Yi.Buffer.HighLevel

import Foundation
import AppKit

import qualified AppKit.NSScrollView (contentView)

import Foreign
import Foreign.C

$(declareClass "YiTextView" "NSTextView")
$(exportClass "YiTextView" "ytv_" [
    InstanceVariable "runBuffer" [t| BufferM () -> IO () |] [| \_ -> return () |]
  , InstanceVariable "selectingPosition" [t| Maybe CUInt |] [| Nothing |]
  , InstanceMethod 'setSelectedRangeAffinityStillSelecting -- '
  ])

-- | Intercept mouse selection so that we can update Yi's selection
--   according to how Cocoa wants it.
ytv_setSelectedRangeAffinityStillSelecting :: NSRange -> NSSelectionAffinity -> Bool -> YiTextView () -> IO ()
ytv_setSelectedRangeAffinityStillSelecting r@(NSRange p1 l) a b v = do
  p <- v #. _selectingPosition
  case (b, p) of
    (True, Nothing) -> do
      -- Assume that the initial indication gives starting position
      v # setIVar _selectingPosition (Just p1)
    (False, Just p0) -> do
      v # setIVar _selectingPosition Nothing
      runbuf <- v #. _runBuffer
      runbuf $ do
        setVisibleSelection (l /= 0)
        setSelectionMarkPointB (fromIntegral p0)
        moveTo (fromIntegral $ if p1 == p0 then p1 + l else p1)
    _ -> do
      -- Ignore intermediate updates (Cocoa buffers events until selection finishes)
      -- Ignore direct updates (to avoid having to detect "our" updates)
      return ()

  super v # setSelectedRangeAffinityStillSelecting r a b

-- | Compute the currently visible text range in the view
visibleRange :: YiTextView () -> IO NSRange
visibleRange v = do
  -- Force redraw of the whole container to capture interactive style changes...
  NSPoint x y <- v # textContainerOrigin
  r <- v # visibleRect >>= \r -> nsOffsetRect r x y
  lm <- v # layoutManager
  tc <- v # textContainer
  gr <- lm # glyphRangeForBoundingRectInTextContainer r tc
  lm # characterRangeForGlyphRangeActualGlyphRange gr nullPtr

$(declareClass "YiScrollView" "NSScrollView")
$(exportClass "YiScrollView" "ysv_" [
    InstanceVariable "leftScroller" [t| Bool |] [| False |]
  , InstanceMethod 'tile -- '
  ])
  
ysv_tile :: YiScrollView () -> IO ()
ysv_tile slf = do
  super slf # tile
  moveScroller <- slf #. _leftScroller
  if not moveScroller
    then return ()
    else do
      -- Copied from NostalgicScrollView (found on /.)
      c <- slf # AppKit.NSScrollView.contentView
      s <- slf # verticalScroller
      sf <- s # frame
      s # setFrameOrigin (NSPoint 0.0 (nsMinY sf))
      c # frame >>= (flip setFrameOrigin c) . (NSPoint (nsWidth sf)) . nsMinY