gtk-0.11.0: Graphics/UI/Gtk/Abstract/Container.chs
{-# 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 the input focus.
--
setFocusChild :: ContainerClass self => Signal self (Widget -> IO ())
setFocusChild = Signal (connect_OBJECT__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
-> (Widget -> IO ())
-> IO (ConnectId self)
onSetFocusChild = connect_OBJECT__NONE "set-focus-child" False
{-# DEPRECATED onSetFocusChild "instead of 'onSetFocusChild obj' use 'on obj setFocusChild'" #-}
-- %hash c:23e5
afterSetFocusChild :: ContainerClass self => self
-> (Widget -> IO ())
-> IO (ConnectId self)
afterSetFocusChild = connect_OBJECT__NONE "set-focus-child" True
{-# DEPRECATED afterSetFocusChild "instead of 'afterSetFocusChild obj' use 'after obj setFocusChild'" #-}
#endif