text: {-# LANGUAGE CPP #-}
  -- -*-haskell-*-
  --  GIMP Toolkit (GTK) Widget Container
  --
  --  Author : Axel Simon
  --
  --  Created: 15 May 2001
  --
  --  Copyright (C) 1999-2005 Axel Simon
  --
  --  This library is free software; you can redistribute it and/or
  --  modify it under the terms of the GNU Lesser General Public
  --  License as published by the Free Software Foundation; either
  --  version 2.1 of the License, or (at your option) any later version.
  --
  --  This library is distributed in the hope that it will be useful,
  --  but WITHOUT ANY WARRANTY; without even the implied warranty of
  --  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  --  Lesser General Public License for more details.
  --
  -- |
  -- Maintainer  : gtk2hs-users@lists.sourceforge.net
  -- Stability   : provisional
  -- Portability : portable (depends on GHC)
  --
  -- Base class for widgets which contain other widgets
  --
  module Graphics.UI.Gtk.Abstract.Container (
  -- * Detail
  --
  -- | A Gtk+ user interface is constructed by nesting widgets inside widgets.
  -- Container widgets are the inner nodes in the resulting tree of widgets: they
  -- contain other widgets. So, for example, you might have a 'Window' containing
  -- a 'Frame' containing a 'Label'. If you wanted an image instead of a textual
  -- label inside the frame, you might replace the 'Label' widget with a 'Image'
  -- widget.
  --
  -- There are two major kinds of container widgets in Gtk+. Both are
  -- subclasses of the abstract 'Container' base class.
  --
  -- The first type of container widget has a single child widget and derives
  -- from 'Bin'. These containers are decorators, which add some kind of
  -- functionality to the child. For example, a 'Button' makes its child into a
  -- clickable button; a 'Frame' draws a frame around its child and a 'Window'
  -- places its child widget inside a top-level window.
  --
  -- The second type of container can have more than one child; its purpose is
  -- to manage layout. This means that these containers assign sizes and
  -- positions to their children. For example, a 'HBox' arranges its children in
  -- a horizontal row, and a 'Table' arranges the widgets it contains in a
  -- two-dimensional grid.
  --
  -- To fulfill its task, a layout container must negotiate the size
  -- requirements with its parent and its children. This negotiation is carried
  -- out in two phases, size requisition and size allocation.
  
  -- ** Size Requisition
  --
  -- | The size requisition of a widget is it's desired width and height. This
  -- is represented by a 'Requisition'.
  --
  -- How a widget determines its desired size depends on the widget. A
  -- 'Label', for example, requests enough space to display all its text.
  -- Container widgets generally base their size request on the requisitions of
  -- their children.
  --
  -- The size requisition phase of the widget layout process operates
  -- top-down. It starts at a top-level widget, typically a 'Window'. The
  -- top-level widget asks its child for its size requisition by calling
  -- 'widgetSizeRequest'. To determine its requisition, the child asks its own
  -- children for their requisitions and so on. Finally, the top-level widget
  -- will get a requisition back from its child.
  
  -- ** Size Allocation
  --
  -- | When the top-level widget has determined how much space its child would
  -- like to have, the second phase of the size negotiation, size allocation,
  -- begins. Depending on its configuration (see 'windowSetResizable'), the
  -- top-level widget may be able to expand in order to satisfy the size request
  -- or it may have to ignore the size request and keep its fixed size. It then
  -- tells its child widget how much space it gets by calling
  -- 'widgetSizeAllocate'. The child widget divides the space among its children
  -- and tells each child how much space it got, and so on. Under normal
  -- circumstances, a 'Window' will always give its child the amount of space the
  -- child requested.
  --
  -- A child's size allocation is represented by an 'Allocation'.
  -- This contains not only a width and height, but also a
  -- position (i.e. X and Y coordinates), so that containers can tell their
  -- children not only how much space they have gotten, but also where they are
  -- positioned inside the space available to the container.
  --
  -- Widgets are required to honor the size allocation they receive; a size
  -- request is only a request, and widgets must be able to cope with any size.
  
  -- ** Child attributes
  --
  -- | 'Container' introduces child attributes - these are object attributes
  -- that are not specific to either the container or the contained widget, but
  -- rather to their relation. Typical examples of child attributes are the
  -- position or pack-type of a widget which is contained in a 'Box'.
  --
  -- The 'Container' class does not itself define any child attributes, they are
  -- defined (and documented) by the various 'Container' subclasses.
  --
  -- Child attributes can be set or obtained in a similar way to ordinary
  -- attributes. So ordinary attributes are set like so:
  --
  -- > set object [ attr := value ]
  --
  -- Whereas child attributes take the child object as a parameter:
  --
  -- > set container [ attr child := value ]
  --
  -- And similarily for getting a child attribute's value:
  --
  -- > value <- get container (attr child)
  --
  
  -- * Class Hierarchy
  -- |
  -- @
  -- |  'GObject'
  -- |   +----'Object'
  -- |         +----'Widget'
  -- |               +----Container
  -- |                     +----'Bin'
  -- |                     +----'Box'
  -- |                     +----'CList'
  -- |                     +----'Fixed'
  -- |                     +----'Paned'
  -- |                     +----'IconView'
  -- |                     +----'Layout'
  -- |                     +----'List'
  -- |                     +----'MenuShell'
  -- |                     +----'Notebook'
  -- |                     +----'Socket'
  -- |                     +----'Table'
  -- |                     +----'TextView'
  -- |                     +----'Toolbar'
  -- |                     +----'TreeView'
  -- @
  
  -- * Types
    Container,
    ContainerClass,
    castToContainer, gTypeContainer,
    toContainer,
    ContainerForeachCB,
    ResizeMode(..),
  
  -- * Methods
    containerAdd,
    containerRemove,
    containerForeach,
    containerForall,
    containerGetChildren,
    containerSetFocusChild,
    containerSetFocusChain,
    containerGetFocusChain,
    containerUnsetFocusChain,
    containerSetFocusVAdjustment,
    containerGetFocusVAdjustment,
    containerSetFocusHAdjustment,
    containerGetFocusHAdjustment,
    containerResizeChildren,
    containerSetBorderWidth,
    containerGetBorderWidth,
    containerGetResizeMode,
    containerSetResizeMode,
  
  -- * Attributes
    containerResizeMode,
    containerBorderWidth,
    containerChild,
    containerFocusHAdjustment,
    containerFocusVAdjustment,
  
  -- * Signals
    add,
    checkResize,
    remove,
    setFocusChild,
  
  -- * Deprecated
  #ifndef DISABLE_DEPRECATED
    onAdd,
    afterAdd,
    onCheckResize,
    afterCheckResize,
    onRemove,
    afterRemove,
    onSetFocusChild,
    afterSetFocusChild,
  #endif
    ) where
  
  import Control.Monad    (liftM)
  
  import System.Glib.FFI
  import System.Glib.Attributes
  import System.Glib.Properties
  import Graphics.UI.Gtk.Abstract.Object  (makeNewObject)
  {#import Graphics.UI.Gtk.Types#}
  {#import Graphics.UI.Gtk.Signals#}
  import System.Glib.GList                (fromGList, withGList)
  import Graphics.UI.Gtk.General.Enums    (ResizeMode(..))
  
  {# context lib="gtk" prefix="gtk" #}
  
  --------------------
  -- Methods
  
  -- | Adds @widget@ to the container. Typically used for simple containers such
  -- as 'Window', 'Frame', or 'Button'; for more complicated layout containers
  -- such as 'Box' or 'Table', this function will pick default packing parameters
  -- that may not be correct. So consider functions such as 'boxPackStart' and
  -- 'tableAttach' as an alternative to 'containerAdd' in those cases. A widget
  -- may be added to only one container at a time; you can't place the same
  -- widget inside two different containers.
  --
  containerAdd :: (ContainerClass self, WidgetClass widget) => self
   -> widget -- ^ @widget@ - a widget to be placed inside @container@
   -> IO ()
  containerAdd self widget =
    {# call container_add #}
      (toContainer self)
      (toWidget widget)
  
  -- | Removes @widget@ from @container@. @widget@ must be inside @container@.
  --
  containerRemove :: (ContainerClass self, WidgetClass widget) => self
   -> widget -- ^ @widget@ - a current child of @container@
   -> IO ()
  containerRemove self widget =
    {# call container_remove #}
      (toContainer self)
      (toWidget widget)
  
  -- | Maps @callback@ over each non-internal child of @container@. See
  -- 'containerForall' for details on what constitutes an \"internal\" child.
  -- Most applications should use 'containerForeach', rather than
  -- 'containerForall'.
  --
  containerForeach :: ContainerClass self => self
   -> ContainerForeachCB
   -> IO ()
  containerForeach self fun = do
    fPtr <- mkContainerForeachFunc (\wPtr _ -> do
      w <- makeNewObject mkWidget (return wPtr)
      fun w)
    {# call container_foreach #}
      (toContainer self)
      fPtr
      nullPtr
    freeHaskellFunPtr fPtr
  
  -- | A function that is invoked for all widgets in a container.
  type ContainerForeachCB = Widget -> IO ()
  {#pointer Callback#}
  
  foreign import ccall "wrapper" mkContainerForeachFunc ::
    (Ptr Widget -> Ptr () -> IO ()) -> IO Callback
  
  -- | Maps @callback@ over each child of @container@, including children that
  -- are considered \"internal\" (implementation details of the container).
  -- \"Internal\" children generally weren't added by the user of the container,
  -- but were added by the container implementation itself. Most applications
  -- should use 'containerForeach', rather than 'containerForall'.
  --
  containerForall :: ContainerClass self => self
   -> ContainerForeachCB -- ^ @callback@ - a callback
   -> IO ()
  containerForall self fun = do
    fPtr <- mkContainerForeachFunc (\wPtr _ -> do
      w <- makeNewObject mkWidget (return wPtr)
      fun w)
    {# call container_forall #}
      (toContainer self)
      fPtr
      nullPtr
    freeHaskellFunPtr fPtr
  
  -- | Returns the container's non-internal children. See 'containerForall' for
  -- details on what constitutes an \"internal\" child.
  --
  containerGetChildren :: ContainerClass self => self
   -> IO [Widget]
  containerGetChildren self = do
    glist <- {# call container_get_children #} (toContainer self)
    widgetPtrs <- fromGList glist
    mapM (makeNewObject mkWidget . return) widgetPtrs
  
  -- | Give the focus to a specific child of the container.
  --
  containerSetFocusChild :: (ContainerClass self, WidgetClass child) => self
   -> child -- ^ @child@
   -> IO ()
  containerSetFocusChild self child =
    {# call container_set_focus_child #}
      (toContainer self)
      (toWidget child)
  
  -- | Sets a focus chain, overriding the one computed automatically by Gtk+.
  --
  -- In principle each widget in the chain should be a descendant of the
  -- container, but this is not enforced by this method, since it's allowed to
  -- set the focus chain before you pack the widgets, or have a widget in the
  -- chain that isn't always packed. The necessary checks are done when the focus
  -- chain is actually traversed.
  --
  containerSetFocusChain :: ContainerClass self => self
   -> [Widget] -- ^ @focusableWidgets@ - the new focus chain.
   -> IO ()
  containerSetFocusChain self chain =
    withForeignPtrs (map unWidget chain) $ \wPtrs ->
    withGList wPtrs $ \glist ->
    {# call container_set_focus_chain #}
      (toContainer self)
      glist
  
  -- | Retrieves the focus chain of the container, if one has been set
  -- explicitly. If no focus chain has been explicitly set, Gtk+ computes the
  -- focus chain based on the positions of the children. In that case the
  -- function returns @Nothing@.
  --
  containerGetFocusChain :: ContainerClass self => self
   -> IO (Maybe [Widget])
  containerGetFocusChain self =
    alloca $ \glistPtr -> do
    {# call container_get_focus_chain #}
      (toContainer self)
      glistPtr
    if glistPtr == nullPtr then return Nothing else liftM Just $ do
      glist <- peek glistPtr
      widgetPtrs <- fromGList glist
      mapM (makeNewObject mkWidget . return) widgetPtrs
  
  -- | Removes a focus chain explicitly set with 'containerSetFocusChain'.
  --
  containerUnsetFocusChain :: ContainerClass self => self -> IO ()
  containerUnsetFocusChain self =
    {# call container_unset_focus_chain #}
      (toContainer self)
  
  -- | Hooks up an adjustment to focus handling in a container, so when a child
  -- of the container is focused, the adjustment is scrolled to show that widget.
  -- This function sets the vertical alignment. See
  -- 'scrolledWindowGetVAdjustment' for a typical way of obtaining the adjustment
  -- and 'containerSetFocusHAdjustment' for setting the horizontal adjustment.
  --
  -- The adjustments have to be in pixel units and in the same coordinate
  -- system as the allocation for immediate children of the container.
  --
  containerSetFocusVAdjustment :: ContainerClass self => self
   -> Adjustment -- ^ @adjustment@ - an adjustment which should be adjusted when
                 -- the focus is moved among the descendents of @container@
   -> IO ()
  containerSetFocusVAdjustment self adjustment =
    {# call container_set_focus_vadjustment #}
      (toContainer self)
      adjustment
  
  -- | Retrieves the vertical focus adjustment for the container. See
  -- 'containerSetFocusVAdjustment'.
  --
  containerGetFocusVAdjustment :: ContainerClass self => self
   -> IO (Maybe Adjustment) -- ^ returns the vertical focus adjustment, or
                            -- @Nothing@ if none has been set.
  containerGetFocusVAdjustment self =
    maybeNull (makeNewObject mkAdjustment) $
    {# call unsafe container_get_focus_vadjustment #}
      (toContainer self)
  
  -- | Hooks up an adjustment to focus handling in a container, so when a child
  -- of the container is focused, the adjustment is scrolled to show that widget.
  -- This function sets the horizontal alignment. See
  -- 'scrolledWindowGetHAdjustment' for a typical way of obtaining the adjustment
  -- and 'containerSetFocusVAdjustment' for setting the vertical adjustment.
  --
  -- The adjustments have to be in pixel units and in the same coordinate
  -- system as the allocation for immediate children of the container.
  --
  containerSetFocusHAdjustment :: ContainerClass self => self
   -> Adjustment -- ^ @adjustment@ - an adjustment which should be adjusted when
                 -- the focus is moved among the descendents of @container@
   -> IO ()
  containerSetFocusHAdjustment self adjustment =
    {# call container_set_focus_hadjustment #}
      (toContainer self)
      adjustment
  
  -- | Retrieves the horizontal focus adjustment for the container. See
  -- 'containerSetFocusHAdjustment'.
  --
  containerGetFocusHAdjustment :: ContainerClass self => self
   -> IO (Maybe Adjustment) -- ^ returns the horizontal focus adjustment, or
                            -- @Nothing@ if none has been set.
  containerGetFocusHAdjustment self =
    maybeNull (makeNewObject mkAdjustment) $
    {# call unsafe container_get_focus_hadjustment #}
      (toContainer self)
  
  -- | Make the container resize its children.
  --
  containerResizeChildren :: ContainerClass self => self -> IO ()
  containerResizeChildren self =
    {# call container_resize_children #}
      (toContainer self)
  
  -- | Sets the border width of the container.
  --
  -- The border width of a container is the amount of space to leave around
  -- the outside of the container. The only exception to this is 'Window';
  -- because toplevel windows can't leave space outside, they leave the space
  -- inside. The border is added on all sides of the container. To add space to
  -- only one side, one approach is to create a 'Alignment' widget, call
  -- 'widgetSetUsize' to give it a size, and place it on the side of the
  -- container as a spacer.
  --
  containerSetBorderWidth :: ContainerClass self => self
   -> Int   -- ^ @borderWidth@ - amount of blank space to leave /outside/ the
            -- container. Valid values are in the range 0-65535 pixels.
   -> IO ()
  containerSetBorderWidth self borderWidth =
    {# call container_set_border_width #}
      (toContainer self)
      (fromIntegral borderWidth)
  
  -- | Retrieves the border width of the container. See
  -- 'containerSetBorderWidth'.
  --
  containerGetBorderWidth :: ContainerClass self => self
   -> IO Int -- ^ returns the current border width
  containerGetBorderWidth self =
    liftM fromIntegral $
    {# call unsafe container_get_border_width #}
      (toContainer self)
  
  -- | Returns the resize mode for the container. See 'containerSetResizeMode'.
  --
  containerGetResizeMode :: ContainerClass self => self
   -> IO ResizeMode -- ^ returns the current resize mode
  containerGetResizeMode self =
    liftM (toEnum . fromIntegral) $
    {# call gtk_container_get_resize_mode #}
      (toContainer self)
  
  -- | Sets the resize mode for the container.
  --
  -- The resize mode of a container determines whether a resize request will
  -- be passed to the container's parent, queued for later execution or executed
  -- immediately.
  --
  containerSetResizeMode :: ContainerClass self => self
   -> ResizeMode -- ^ @resizeMode@ - the new resize mode.
   -> IO ()
  containerSetResizeMode self resizeMode =
    {# call gtk_container_set_resize_mode #}
      (toContainer self)
      ((fromIntegral . fromEnum) resizeMode)
  
  --------------------
  -- Attributes
  
  -- | Specify how resize events are handled.
  --
  -- Default value: 'ResizeParent'
  --
  containerResizeMode :: ContainerClass self => Attr self ResizeMode
  containerResizeMode = newAttr
    containerGetResizeMode
    containerSetResizeMode
  
  -- | The width of the empty border outside the containers children.
  --
  -- Allowed values: \<= @('maxBound' :: Int)@
  --
  -- Default value: 0
  --
  containerBorderWidth :: ContainerClass self => Attr self Int
  containerBorderWidth = newAttr
    containerGetBorderWidth
    containerSetBorderWidth
  
  -- | Can be used to add a new child to the container.
  --
  containerChild :: (ContainerClass self, WidgetClass widget) => WriteAttr self widget
  containerChild = writeAttrFromObjectProperty "child"
    {# call pure unsafe gtk_widget_get_type #}
  
  -- | \'focusHadjustment\' property. See 'containerGetFocusHAdjustment' and
  -- 'containerSetFocusHAdjustment'
  --
  containerFocusHAdjustment :: ContainerClass self => ReadWriteAttr self (Maybe Adjustment) Adjustment
  containerFocusHAdjustment = newAttr
    containerGetFocusHAdjustment
    containerSetFocusHAdjustment
  
  -- | \'focusVadjustment\' property. See 'containerGetFocusVAdjustment' and
  -- 'containerSetFocusVAdjustment'
  --
  containerFocusVAdjustment :: ContainerClass self => ReadWriteAttr self (Maybe Adjustment) Adjustment
  containerFocusVAdjustment = newAttr
    containerGetFocusVAdjustment
    containerSetFocusVAdjustment
  
  --------------------
  -- Signals
  
  -- %hash c:26b d:af3f
  -- | A widget was added to the container.
  --
  add :: ContainerClass self => Signal self (Widget -> IO ())
  add = Signal (connect_OBJECT__NONE "add")
  
  -- %hash c:f43a d:af3f
  -- | A widget was removed from the container.
  --
  remove :: ContainerClass self => Signal self (Widget -> IO ())
  remove = Signal (connect_OBJECT__NONE "remove")
  
  -- %hash c:21a9 d:af3f
  -- | Emitted when widgets need to be queried again for their preferred size.
  --
  checkResize :: ContainerClass self => Signal self (IO ())
  checkResize = Signal (connect_NONE__NONE "check-resize")
  
  -- %hash c:b3a d:af3f
  -- | A widget in the container received or lost the input focus.
  --
  setFocusChild :: ContainerClass self => Signal self (Maybe Widget -> IO ())
  setFocusChild = Signal (connect_MOBJECT__NONE "set-focus-child")
  
  --------------------
  -- Deprecated Signals
  
  #ifndef DISABLE_DEPRECATED
  -- %hash c:fb37
  onAdd :: ContainerClass self => self
   -> (Widget -> IO ())
   -> IO (ConnectId self)
  onAdd = connect_OBJECT__NONE "add" False
  {-# DEPRECATED onAdd "instead of 'onAdd obj' use 'on obj add'" #-}
  
  -- %hash c:c9d6
  afterAdd :: ContainerClass self => self
   -> (Widget -> IO ())
   -> IO (ConnectId self)
  afterAdd = connect_OBJECT__NONE "add" True
  {-# DEPRECATED afterAdd "instead of 'afterAdd obj' use 'after obj add'" #-}
  
  -- %hash c:9b66
  onRemove :: ContainerClass self => self
   -> (Widget -> IO ())
   -> IO (ConnectId self)
  onRemove = connect_OBJECT__NONE "remove" False
  {-# DEPRECATED onRemove "instead of 'onRemove obj' use 'on obj remove'" #-}
  
  -- %hash c:f165
  afterRemove :: ContainerClass self => self
   -> (Widget -> IO ())
   -> IO (ConnectId self)
  afterRemove = connect_OBJECT__NONE "remove" True
  {-# DEPRECATED afterRemove "instead of 'afterRemove obj' use 'after obj remove'" #-}
  
  -- %hash c:8424
  onCheckResize :: ContainerClass self => self
   -> IO ()
   -> IO (ConnectId self)
  onCheckResize = connect_NONE__NONE "check_resize" False
  {-# DEPRECATED onCheckResize "instead of 'onCheckResize obj' use 'on obj checkResize'" #-}
  
  -- %hash c:6803
  afterCheckResize :: ContainerClass self => self
   -> IO ()
   -> IO (ConnectId self)
  afterCheckResize = connect_NONE__NONE "check_resize" True
  {-# DEPRECATED afterCheckResize "instead of 'afterCheckResize obj' use 'after obj checkResize'" #-}
  
  -- %hash c:1ac6
  onSetFocusChild :: ContainerClass self => self
   -> (Maybe Widget -> IO ())
   -> IO (ConnectId self)
  onSetFocusChild = connect_MOBJECT__NONE "set-focus-child" False
  {-# DEPRECATED onSetFocusChild "instead of 'onSetFocusChild obj' use 'on obj setFocusChild'" #-}
  
  -- %hash c:23e5
  afterSetFocusChild :: ContainerClass self => self
   -> (Maybe Widget -> IO ())
   -> IO (ConnectId self)
  afterSetFocusChild = connect_MOBJECT__NONE "set-focus-child" True
  {-# DEPRECATED afterSetFocusChild "instead of 'afterSetFocusChild obj' use 'after obj setFocusChild'" #-}
  #endif
  