{-# LANGUAGE CPP #-}
-- -*-haskell-*-
-- GIMP Toolkit (GTK) Widget UIManager
--
-- Author : Duncan Coutts
--
-- Created: 6 April 2005
--
-- Copyright (C) 2005 Duncan Coutts
--
-- 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.
--
-- TODO
-- check if uiManagerGetToplevels returns widgets derived from some common
-- class, eg ToolItem (though it looks like it can return MenuBars too)
--
-- |
-- Maintainer : gtk2hs-users@lists.sourceforge.net
-- Stability : provisional
-- Portability : portable (depends on GHC)
--
-- Constructing menus and toolbars from an XML description
--
-- * Module available since Gtk+ version 2.4
--
module Graphics.UI.Gtk.ActionMenuToolbar.UIManager (
-- * Detail
--
-- | A 'UIManager' constructs a user interface (menus and toolbars) from one
-- or more UI definitions, which reference actions from one or more action
-- groups.
-- ** UI Definitions
--
-- | #XML-UI# The UI definitions are specified in an XML format which can be roughly
-- described by the following DTD.
--
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- > action #IMPLIED >
-- > action #IMPLIED >
-- > action #IMPLIED >
-- > action #IMPLIED
-- > expand (true|false) #IMPLIED >
-- > action #IMPLIED >
-- > action #REQUIRED
-- > position (top|bot) #IMPLIED >
-- > action #REQUIRED
-- > position (top|bot) #IMPLIED >
-- > action #REQUIRED
-- > position (top|bot) #IMPLIED >
-- > action #REQUIRED >
--
-- There are some additional restrictions beyond those specified in the DTD,
-- e.g. every toolitem must have a toolbar in its anchestry and every menuitem
-- must have a menubar or popup in its anchestry. Since a GMarkup
-- parser is used to parse the UI description, it must not
-- only be valid XML, but valid GMarkup.
--
-- If a name is not specified, it defaults to the action. If an action is
-- not specified either, the element name is used. The name and action
-- attributes must not contain \'\/\' characters after parsing (since that
-- would mess up path lookup) and must be usable as XML attributes when
-- enclosed in doublequotes, thus they must not \'\"\' characters or references
-- to the " entity.
-- ** A UI definition
-- |
--
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- >
-- The constructed widget hierarchy is very similar to the element tree of
-- the XML, with the exception that placeholders are merged into their parents.
-- The correspondence of XML elements to widgets should be almost obvious:
--
-- [menubar] a 'MenuBar'
--
-- [toolbar] a 'Toolbar'
--
-- [popup] a toplevel 'Menu'
--
-- [menu] a 'Menu' attached to a menuitem
--
-- [menuitem] a 'MenuItem' subclass, the exact type depends on the action
--
-- [toolitem] a 'ToolItem' subclass, the exact type depends on the action.
-- Note that toolitem elements may contain a menu element, but only if their
-- associated action specifies a 'MenuToolButton' as proxy.
--
-- [separator] a 'SeparatorMenuItem' or 'SeparatorToolItem'
--
-- [accelerator] a keyboard accelerator
--
-- The \"position\" attribute determines where a constructed widget is
-- positioned wrt. to its siblings in the partially constructed tree. If it is
-- \"top\", the widget is prepended, otherwise it is appended.
-- ** UI Merging
--
-- | The most remarkable feature of 'UIManager' is that it can overlay a set
-- of menuitems and toolitems over another one, and demerge them later.
--
-- Merging is done based on the names of the XML elements. Each element is
-- identified by a path which consists of the names of its anchestors,
-- separated by slashes. For example, the menuitem named \"Left\" in the
-- example above has the path @\/ui\/menubar\/JustifyMenu\/Left@ and the
-- toolitem with the same name has path
-- @\/ui\/toolbar1\/JustifyToolItems\/Left@.
-- ** Accelerators
--
-- | Every action has an accelerator path. Accelerators are installed together
-- with menuitem proxies, but they can also be explicitly added with
-- \ elements in the UI definition. This makes it possible to have
-- accelerators for actions even if they have no visible proxies.
-- ** Smart Separators
--
-- | The separators created by 'UIManager' are \"smart\", i.e. they do not
-- show up in the UI unless they end up between two visible menu or tool items.
-- Separators which are located at the very beginning or end of the menu or
-- toolbar containing them, or multiple separators next to each other, are
-- hidden. This is a useful feature, since the merging of UI elements from
-- multiple sources can make it hard or impossible to determine in advance
-- whether a separator will end up in such an unfortunate position.
--
-- For separators in toolbars, you can set @expand=\"true\"@ to turn them
-- from a small, visible separator to an expanding, invisible one. Toolitems
-- following an expanding separator are effectively right-aligned.
-- ** Empty Menus
--
-- | Submenus pose similar problems to separators inconnection with merging.
-- It is impossible to know in advance whether they will end up empty after
-- merging. 'UIManager' offers two ways to treat empty submenus:
--
-- * make them disappear by hiding the menu item they\'re attached to
--
-- * add an insensitive \"Empty\" item
--
-- The behaviour is chosen based on the \"hide_if_empty\" property of the
-- action to which the submenu is associated.
--
-- * Class Hierarchy
-- |
-- @
-- | 'GObject'
-- | +----UIManager
-- @
#if GTK_CHECK_VERSION(2,4,0)
-- * Types
UIManager,
UIManagerClass,
castToUIManager, gTypeUIManager,
toUIManager,
UIManagerItemType(..),
MergeId,
-- * Constructors
uiManagerNew,
-- * Methods
uiManagerSetAddTearoffs,
uiManagerGetAddTearoffs,
uiManagerInsertActionGroup,
uiManagerRemoveActionGroup,
uiManagerGetActionGroups,
uiManagerGetAccelGroup,
uiManagerGetWidget,
uiManagerGetToplevels,
uiManagerGetAction,
uiManagerAddUiFromString,
uiManagerAddUiFromFile,
uiManagerNewMergeId,
uiManagerAddUi,
uiManagerRemoveUi,
uiManagerGetUi,
uiManagerEnsureUpdate,
-- * Attributes
uiManagerAddTearoffs,
uiManagerUi,
-- * Signals
addWidget,
actionsChanged,
-- * Deprecated
#ifndef DISABLE_DEPRECATED
onAddWidget,
afterAddWidget,
onActionsChanged,
afterActionsChanged,
onConnectProxy,
afterConnectProxy,
onDisconnectProxy,
afterDisconnectProxy,
onPreActivate,
afterPreActivate,
onPostActivate,
afterPostActivate,
#endif
#endif
) where
import Control.Monad (liftM)
import System.Glib.FFI
import System.Glib.Flags (Flags, fromFlags)
import System.Glib.UTFString
import System.Glib.GList
import System.Glib.GError
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#}
{# context lib="gtk" prefix="gtk" #}
#if GTK_CHECK_VERSION(2,4,0)
-- | These enumeration values are used by 'uiManagerAddUi' to determine what UI
-- element to create.
--
{# enum UIManagerItemType {underscoreToCase} deriving (Bounded) #}
instance Flags UIManagerItemType
newtype MergeId = MergeId { fromMergeId :: {# type guint #}}
--------------------
-- Constructors
-- | Creates a new ui manager object.
--
uiManagerNew :: IO UIManager
uiManagerNew =
wrapNewGObject mkUIManager $
{# call gtk_ui_manager_new #}
--------------------
-- Methods
-- | Returns an unused merge id, suitable for use with 'uiManagerAddUi'.
--
uiManagerNewMergeId :: UIManager -> IO MergeId
uiManagerNewMergeId self =
liftM MergeId $
{# call gtk_ui_manager_new_merge_id #}
self
-- | Sets the \"add_tearoffs\" property, which controls whether menus
-- generated by this 'UIManager' will have tearoff menu items.
--
-- Note that this only affects regular menus. Generated popup menus never
-- have tearoff menu items.
--
uiManagerSetAddTearoffs :: UIManager
-> Bool -- ^ @addTearoffs@ - whether tearoff menu items are added
-> IO ()
uiManagerSetAddTearoffs self addTearoffs =
{# call gtk_ui_manager_set_add_tearoffs #}
self
(fromBool addTearoffs)
-- | Returns whether menus generated by this 'UIManager' will have tearoff
-- menu items.
--
uiManagerGetAddTearoffs :: UIManager
-> IO Bool -- ^ returns whether tearoff menu items are added
uiManagerGetAddTearoffs self =
liftM toBool $
{# call gtk_ui_manager_get_add_tearoffs #}
self
-- | Inserts an action group into the list of action groups associated with
-- @self@. Actions in earlier groups hide actions with the same name in later
-- groups.
--
uiManagerInsertActionGroup :: UIManager
-> ActionGroup -- ^ @actionGroup@ - the action group to be inserted
-> Int -- ^ @pos@ - the position at which the group will be inserted.
-> IO ()
uiManagerInsertActionGroup self actionGroup pos =
{# call gtk_ui_manager_insert_action_group #}
self
actionGroup
(fromIntegral pos)
-- | Removes an action group from the list of action groups associated with
-- @self@.
--
uiManagerRemoveActionGroup :: UIManager
-> ActionGroup -- ^ @actionGroup@ - the action group to be removed
-> IO ()
uiManagerRemoveActionGroup self actionGroup =
{# call gtk_ui_manager_remove_action_group #}
self
actionGroup
-- | Returns the list of action groups associated with the UI manager.
--
uiManagerGetActionGroups :: UIManager -> IO [ActionGroup]
uiManagerGetActionGroups self =
{# call gtk_ui_manager_get_action_groups #}
self
>>= readGList
>>= mapM (\elemPtr -> makeNewGObject mkActionGroup (return elemPtr))
-- | Returns the 'AccelGroup' associated with @self@.
--
uiManagerGetAccelGroup :: UIManager
-> IO AccelGroup -- ^ returns the 'AccelGroup'.
uiManagerGetAccelGroup self =
makeNewGObject mkAccelGroup $
{# call gtk_ui_manager_get_accel_group #}
self
-- | Looks up a widget by following a path. The path consists of the names
-- specified in the XML description of the UI. separated by \'\/\'. Elements
-- which don't have a name or action attribute in the XML (e.g. \) can
-- be addressed by their XML element name (e.g. \"popup\"). The root element
-- (\"\/ui\") can be omitted in the path.
--
-- Note that the widget found by following a path that ends in a \