summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCamil Staps2019-11-01 18:41:10 +0100
committerCamil Staps2019-11-01 18:41:10 +0100
commit0497dfb79211aa1e64304fa446d230c41ca73daa (patch)
treecc29910a32b81db4430aff1a74172174039e9c25
parentRemove dependency on supporting C code (diff)
Cleanup and add documentation
-rw-r--r--src/Gtk.dcl29
-rw-r--r--src/Gtk/Internal.dcl9
-rw-r--r--src/Gtk/Shares.dcl17
-rw-r--r--src/Gtk/Signal.dcl57
-rw-r--r--src/Gtk/Signal.icl58
-rw-r--r--src/Gtk/State.dcl44
-rw-r--r--src/Gtk/Tune.dcl16
-rw-r--r--src/Gtk/Tune.icl8
-rw-r--r--src/Gtk/Types.dcl25
-rw-r--r--src/Gtk/Widgets.dcl185
-rw-r--r--src/Gtk/Widgets.icl64
-rw-r--r--src/Gtk/Widgets/Sheet.dcl13
-rw-r--r--src/Gtk/Widgets/Sheet/Signal.dcl7
-rw-r--r--src/Gtk/Widgets/Sheet/Signal.icl6
14 files changed, 441 insertions, 97 deletions
diff --git a/src/Gtk.dcl b/src/Gtk.dcl
index 964d2a4..9728d3e 100644
--- a/src/Gtk.dcl
+++ b/src/Gtk.dcl
@@ -1,5 +1,34 @@
definition module Gtk
+/**
+ * This library provides an application framework based on the Gtk+ 3 GUI
+ * toolkit. For information about the C library, see the documentation at
+ * https://developer.gnome.org/gtk3/stable/.
+ *
+ * For a low-level interface to Gtk, see `Gtk.Internal`. This module can be
+ * used without dependencies on the framework, which provides additional
+ * abstractions.
+ *
+ * The application framework is monadic; see `Gtk.State`. A typical application
+ * will consist of a setup function which populates the initial window and sets
+ * up signals for buttons, menu items, etc. The setup function is run with
+ * `runGtk` (`Gtk.State`), which then enters the Glib main loop to handle
+ * events. Signal handlers are Clean functions and may modify the monadic
+ * state.
+ *
+ * For an overview of the available GUI elements, see `Gtk.Widgets`. The
+ * relevant signals are provided in `Gtk.Signals`. Check the reference manual
+ * to see which signals are emitted for which types of widgets.
+ *
+ * NB: this library is not intended to be an exhaustive interface to Gtk. New
+ * functionality is added on a by-need basis. There is, however, enough example
+ * code available in these modules to be able to quickly add support for so far
+ * unsupported parts of Gtk.
+ *
+ * A simple share system, based on that of iTasks, is provided in `Gtk.Shares`
+ * and allows the programmer to easily keep shared data.
+ */
+
import Gtk.Shares
import Gtk.Signal
import Gtk.State
diff --git a/src/Gtk/Internal.dcl b/src/Gtk/Internal.dcl
index 5b4d55d..8950cf9 100644
--- a/src/Gtk/Internal.dcl
+++ b/src/Gtk/Internal.dcl
@@ -1,5 +1,14 @@
definition module Gtk.Internal
+/**
+ * This module provides low-level access to the Gtk+ 3 library. If you use the
+ * abstractions exported by the `Gtk` module, you should not need to use it
+ * directly.
+ *
+ * For documentation, see the Gtk+ 3 reference manual:
+ * https://developer.gnome.org/gtk3/stable/
+ */
+
from StdMaybe import :: Maybe
from System._Pointer import :: Pointer
diff --git a/src/Gtk/Shares.dcl b/src/Gtk/Shares.dcl
index d1e5556..48db8eb 100644
--- a/src/Gtk/Shares.dcl
+++ b/src/Gtk/Shares.dcl
@@ -1,20 +1,35 @@
definition module Gtk.Shares
+/**
+ * This module provides shares in the `GtkM` monad, allowing the programmer to
+ * abstract from global state. They are loosely based on SDSs in iTasks, but
+ * much less advanced.
+ */
+
from Gtk.State import :: GtkM
+//* Identifier of a share.
:: ShareId :== String
-//* Exported to have a TC instance -- do not use directly!
+//* Exported to have a TC instance --- do not use directly!
:: Shared a :== (String,a)
+//* Types must instantiate this class to be able to be shared.
class shared a | TC a
+//* Sets up a share with a default value (cf. iTasks' `sharedStore`).
share :: !ShareId a -> Shared a | shared a
getShared :: !(Shared a) -> GtkM a | shared a
setShared :: !(Shared a) !a -> GtkM a | shared a
updateShared :: !(a -> a) !(Shared a) -> GtkM a | shared a
+/**
+ * A share with an initialization function. It will always return the same
+ * value, namely the result of the initialization function, but that function
+ * will only be evaluated once. It can be seen as an impure CAF.
+ */
singletonShared :: !String !(GtkM a) -> GtkM a | shared a
+//* Evaluate a function with a temporary share.
withShared :: a !((Shared a) -> GtkM b) -> GtkM b | shared a
diff --git a/src/Gtk/Signal.dcl b/src/Gtk/Signal.dcl
index fa9babf..85a780c 100644
--- a/src/Gtk/Signal.dcl
+++ b/src/Gtk/Signal.dcl
@@ -1,5 +1,9 @@
definition module Gtk.Signal
+/**
+ * This module provides functionality for Gtk signals.
+ */
+
from System._Pointer import :: Pointer
from Gdk.Events import :: GdkEvent
@@ -8,13 +12,19 @@ from Gtk.Tune import class tune
from Gtk.Types import :: GtkPropagate, :: GtkTimeout
from Gtk.Widgets import class gtkWidget
+/**
+ * If more handlers are defined outside this module (and hence outside the
+ * `GSignalHandler` type), they must instantiate this class to be able to be
+ * installed on widgets.
+ */
class signalHandler h
where
+ //* The name of the signal, e.g. `destroy` or `key-press-event`.
signalName :: !h -> String
+ //* An internal representation of the handler.
signalHandler :: !h -> SignalHandlerInternal
-:: SignalHandler = E.h: SignalHandler h & signalHandler h
-
+//* A number of basic signals. See the Gtk documentation for their usage.
:: GSignalHandler
= ActivateHandler !(GtkM ())
| ChangedHandler !(GtkM ())
@@ -29,28 +39,57 @@ where
instance signalHandler GSignalHandler
+/**
+ * Inner representation of the various types of signal handlers that there are.
+ * This is only needed outside this module when adding more signals.
+ */
:: SignalHandlerInternal
= SHI_Void !(GtkM ())
| SHI_Pointer_Bool !(Pointer -> GtkM Bool)
| SHI_Int_Int_Bool !(Int Int -> GtkM Bool)
| SHI_Int_Int_Pointer_Pointer_Bool !(Int Int Pointer Pointer -> GtkM Bool)
+/**
+ * Install a signal handler on a widget. Often, the `tune` instance defined
+ * below leads to more readable code.
+ */
installSignalHandler :: !h !w -> GtkM w | signalHandler h & gtkWidget w
-instance tune w SignalHandler | gtkWidget w
+//* Alternative for `installSignalHandler` for more readable code.
instance tune w GSignalHandler | gtkWidget w
-saveState :: GtkM ()
-retrieveState :: GtkM GtkState
+/**
+ * Run a function at a certain interval. The function will continue to run
+ * until it returns `False`. Note that Glib timeouts cannot be used for precise
+ * timing; see the documentation for more details:
+ * https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add
+ */
+addTimeout :: !GtkTimeout !(GtkM Bool) -> GtkM ()
-//* Wrap functionality in `saveState` and `retrieveState` if it can be re-entrant.
+/**
+ * Wrap functionality with `saveState` and `retrieveState`. This is needed if
+ * it can be re-entrant, for example when it can trigger signals. See the
+ * documentation on `saveState` for more details.
+ */
withPossibleCallback :: !(GtkM a) -> GtkM a
-// Only for foreign export:
+/**
+ * Some functions can lead to Gtk signals to be emitted. If these signals have
+ * handlers set up, the function is re-entrant (may return to Clean code). For
+ * this kind of functions, we need to save the `GtkM` state beforehand and
+ * retrieve it afterwards, because the signal handler may rely on that state
+ * and may modify it. `saveState` saves the state internally; `retrieveState`
+ * restores it. `withPossibleCallback` is a convenient wrapper combining both.
+ */
+saveState :: GtkM ()
+
+//* Retrieve the state saved with `saveState`.
+retrieveState :: GtkM GtkState
+
+// The functions below are only exported because they need a foreign export entry point:
handleSignal_void :: !Pointer !Int -> Int
handleSignal_pointer_bool :: !Pointer !Pointer !Int -> Int
handleSignal_int_int_bool :: !Pointer !Int !Int !Int -> Int
handleSignal_int_int_pointer_pointer_bool :: !Pointer !Int !Int !Pointer !Pointer !Int -> Int
-addTimeout :: !GtkTimeout !(GtkM Bool) -> GtkM ()
-handleTimeout :: !Int -> Int // only for foreign export
+handleTimeout :: !Int -> Int
diff --git a/src/Gtk/Signal.icl b/src/Gtk/Signal.icl
index 254523a..543c7a2 100644
--- a/src/Gtk/Signal.icl
+++ b/src/Gtk/Signal.icl
@@ -76,14 +76,37 @@ where
pushLc handleSignal_int_int_pointer_pointer_bool
}
-instance tune w SignalHandler | gtkWidget w
-where
- tune (SignalHandler handler) widget = installSignalHandler handler widget
-
instance tune w GSignalHandler | gtkWidget w
where
tune handler widget = installSignalHandler handler widget
+addTimeout :: !GtkTimeout !(GtkM Bool) -> GtkM ()
+addTimeout interval callback =
+ modState (\st ->
+ let id = st.timeout_counter+1 in
+ { st
+ & timeouts = 'Data.Map'.put id (wrapped_callback id) st.timeouts
+ , timeout_counter = id
+ }) >>= \{timeout_counter=id} ->
+ case interval of
+ Milliseconds ms -> toState (g_timeout_add ms get_handleTimeout_address id)
+ Seconds s -> toState (g_timeout_add_seconds s get_handleTimeout_address id)
+where
+ wrapped_callback id =
+ callback >>= \r ->
+ if r
+ getState
+ (modState \st -> {st & timeouts='Data.Map'.del id st.timeouts}) >>|
+ pure r
+
+ get_handleTimeout_address :: Pointer
+ get_handleTimeout_address = code {
+ pushLc handleTimeout
+ }
+
+withPossibleCallback :: !(GtkM a) -> GtkM a
+withPossibleCallback m = saveState >>| m >>= \r -> retrieveState >>| pure r
+
// NB: low-level hacking to use and modify the GtkState from within callbacks.
// We use a CAF to keep track of the state. In runGtk, the state is saved with
// saveState. This state is retrieved with retrieveState there (to check
@@ -111,9 +134,6 @@ saveState = getState >>= \state -> toState (save_state state)
retrieveState :: GtkM GtkState
retrieveState = modState (const saved_state.[0])
-withPossibleCallback :: !(GtkM a) -> GtkM a
-withPossibleCallback m = saveState >>| m >>= \r -> retrieveState >>| pure r
-
foreign export handleSignal_void
handleSignal_void :: !Pointer !Int -> Int
handleSignal_void _ id = handleSignal id \h -> case h of
@@ -159,30 +179,6 @@ handleSignal id handle
# (r,st) = f st
-> save_state st r
-addTimeout :: !GtkTimeout !(GtkM Bool) -> GtkM ()
-addTimeout interval callback =
- modState (\st ->
- let id = st.timeout_counter+1 in
- { st
- & timeouts = 'Data.Map'.put id (wrapped_callback id) st.timeouts
- , timeout_counter = id
- }) >>= \{timeout_counter=id} ->
- case interval of
- Milliseconds ms -> toState (g_timeout_add ms get_handleTimeout_address id)
- Seconds s -> toState (g_timeout_add_seconds s get_handleTimeout_address id)
-where
- wrapped_callback id =
- callback >>= \r ->
- if r
- getState
- (modState \st -> {st & timeouts='Data.Map'.del id st.timeouts}) >>|
- pure r
-
- get_handleTimeout_address :: Pointer
- get_handleTimeout_address = code {
- pushLc handleTimeout
- }
-
foreign export handleTimeout
handleTimeout :: !Int -> Int
handleTimeout id
diff --git a/src/Gtk/State.dcl b/src/Gtk/State.dcl
index c4e17a2..1dde9d1 100644
--- a/src/Gtk/State.dcl
+++ b/src/Gtk/State.dcl
@@ -1,5 +1,10 @@
definition module Gtk.State
+/**
+ * This module provides types and functions to set up the monadic state of a
+ * Gtk program and run an application.
+ */
+
from StdMaybe import :: Maybe
from Control.Applicative import class pure, class <*>, class Applicative
@@ -10,6 +15,10 @@ from Data.Map import :: Map
from Gtk.Shares import :: ShareId
from Gtk.Signal import :: SignalHandlerInternal
+/**
+ * In the internal state of the `GtkM` monad. It is exported for use in other
+ * modules of the Gtk library; it should not normally be used by applications.
+ */
:: GtkState =
{ world :: !()
, return :: !Bool
@@ -17,9 +26,10 @@ from Gtk.Signal import :: SignalHandlerInternal
, signal_counter :: !Int
, timeouts :: !Map Int (GtkM Bool)
, timeout_counter :: !Int
- , shares :: !Map ShareId Dynamic // TODO: make this map strict to be able to free references in it
+ , shares :: !Map ShareId Dynamic
}
+//* The Gtk state monad.
:: GtkM a =: GtkM (GtkState -> (a, GtkState))
instance Functor GtkM
@@ -27,18 +37,50 @@ instance pure GtkM
instance <*> GtkM
instance Monad GtkM
+//* A new, empty state.
newGtkState :: GtkState
+//* Run a Gtk monad in a new, empty state.
runGtk :: !(GtkM a) !*World -> (!a, !*World)
+//* Get the internal state.
getState :: GtkM GtkState
+//* Modify the internal state.
modState :: !(GtkState -> GtkState) -> GtkM GtkState
+/**
+ * Run a function in the `GtkM` monad and discard its result. This function is
+ * typically used with functions from `Gtk.Internal` and is not normally used
+ * directly.
+ */
toState :: !(A.a: a -> a) -> GtkM ()
+
+/**
+ * Run a function in the `GtkM` monad and return its result. This function is
+ * typically used with functions from `Gtk.Internal` and is not normally used
+ * directly.
+ */
toStateR :: !(A.a: a -> (r,a)) -> GtkM r
+//* Apply a function with side effects in the `GtkM` monad.
appWorld :: !(*World -> *World) -> GtkM ()
+//* Apply a function with side effects in the `GtkM` monad; return its result.
accWorld :: !(*World -> (r,*World)) -> GtkM r
+/**
+ * Request graceful termination of the program. This sets the `return` field
+ * of the `GtkState`, after which `runGtk` will terminate before the next
+ * iteration.
+ */
quit :: GtkM ()
+
+/**
+ * Run the Glib main loop as long as there are events pending. This may be
+ * useful before starting a long blocking operation in Clean, such that all
+ * updates to the views have been applied. You can thus set text in a status
+ * bar or show a spinner before the blocking operation starts.
+ *
+ * Unfortunately, threading or Glib's background task mechanism is not
+ * implemented, so the blocking operation will still freeze the GUI.
+ */
runWhileEventsPending :: GtkM ()
diff --git a/src/Gtk/Tune.dcl b/src/Gtk/Tune.dcl
index f5966ec..63e48a4 100644
--- a/src/Gtk/Tune.dcl
+++ b/src/Gtk/Tune.dcl
@@ -1,12 +1,18 @@
definition module Gtk.Tune
+/**
+ * This module provides a class and useful infix operators for 'tuning' things.
+ * Tuning involves modifying an existing element, typically a widget. A single
+ * `tune` class avoids the need for a variety of `set...` functions.
+ */
+
from Gtk.State import :: GtkM
-from Gtk.Types import :: GtkCSSClass, :: GtkMargins
-from Gtk.Widgets import :: GtkWidget, class gtkWidget
+//* Modify `elem` with `option`.
class tune elem option :: !option !elem -> GtkM elem
+/**
+ * Infix operator to tune something, typically used when creating the element.
+ * For example: `newTextView <<@ Insensitive >>= \text_view -> ...`.
+ */
(<<@) infixl 2 :: !(GtkM elem) !option -> GtkM elem | tune elem option
-
-instance tune w GtkMargins | gtkWidget w
-instance tune w GtkCSSClass | gtkWidget w
diff --git a/src/Gtk/Tune.icl b/src/Gtk/Tune.icl
index a275ea2..f4553bc 100644
--- a/src/Gtk/Tune.icl
+++ b/src/Gtk/Tune.icl
@@ -9,11 +9,3 @@ import Gtk
(<<@) infixl 2 :: !(GtkM elem) !option -> GtkM elem | tune elem option
(<<@) elemf option = elemf >>= tune option
-
-instance tune w GtkMargins | gtkWidget w
-where
- tune margins widget = setMargins margins widget
-
-instance tune w GtkCSSClass | gtkWidget w
-where
- tune cls widget = addCSSClass cls widget
diff --git a/src/Gtk/Types.dcl b/src/Gtk/Types.dcl
index 9dac38d..1e2ed78 100644
--- a/src/Gtk/Types.dcl
+++ b/src/Gtk/Types.dcl
@@ -1,5 +1,17 @@
definition module Gtk.Types
+/**
+ * This module provides common types for the Gtk library.
+ *
+ * Most of these types map directly to Glib, Gdk, or Gtk `enum`s --- for more
+ * explanation, see the Gtk+ 3 reference manual:
+ * https://developer.gnome.org/gtk3/stable/
+ *
+ * Some types, like `GtkExpand`, map to booleans in the C libraries, and are
+ * merely provided for more readable Clean code (in the case of `GtkExpand` for
+ * example for `packBox`).
+ */
+
from StdOverloaded import class fromInt, class toInt
:: GType
@@ -110,8 +122,17 @@ instance toInt GtkJustification
, bottom :: !Int
}
+//* Creates a `GtkMargins` record where all margins are the same.
margin :: !Int -> GtkMargins
+/**
+ * Used to avoid multiple `setMarkup` functions. This is like `GtkText`, but
+ * assumes that the string contains Pango markup. For an overview of the Pango
+ * markup language, see the documentation:
+ * https://developer.gnome.org/pygtk/stable/pango-markup-language.html
+ */
+:: GtkMarkup =: Markup String
+
:: GtkMessageType
= InfoMessage
| WarningMessage
@@ -186,6 +207,10 @@ instance toInt GtkScrollbarPolicy
instance toInt GtkStylePriority
+/**
+ * Used to avoid multiple `setText` functions.
+ * The string is assumed to be valid UTF-8.
+ */
:: GtkText =: Text String
:: GtkTimeout
diff --git a/src/Gtk/Widgets.dcl b/src/Gtk/Widgets.dcl
index 65f8c87..957838b 100644
--- a/src/Gtk/Widgets.dcl
+++ b/src/Gtk/Widgets.dcl
@@ -1,5 +1,25 @@
definition module Gtk.Widgets
+/**
+ * This module provides functionality for common widgets in the Gtk library.
+ * See the Gtk+ 3 reference manual for more details about what they are used
+ * for: https://developer.gnome.org/gtk3/stable/
+ *
+ * Also see the widget gallery for a quick overview of the different widgets:
+ * https://developer.gnome.org/gtk3/stable/ch03.html
+ *
+ * The Gtk library is object-oriented. This is mirrored here with classes. For
+ * example, all subclasses of `GtkWidget` implement the `gtkWidget` class, and
+ * common methods of the `GtkWidget` class correspond to overloaded functions
+ * in Clean.
+ *
+ * NB: The types of widgets are exported here because (1) newtypes cannot be
+ * abstract and (2) they must be able to implement `TC` so that they can be
+ * shared (see `Gtk.Shares`). When the compiler supports abstract newtypes and
+ * `TC` instantiation of hidden types, the implementation of these types may
+ * be removed from the definition module; do not rely on it!
+ */
+
from StdMaybe import :: Maybe
from System.FilePath import :: FilePath
@@ -12,29 +32,49 @@ from Gtk.Types import
:: GdkModifier,
:: GtkAlign, :: GtkButtonsType, :: GtkCompletionMode, :: GtkCSSClass,
:: GtkDirection, :: GtkExpand, :: GtkFileChooserAction, :: GtkMargins,
- :: GtkMessageType, :: GtkModal, :: GtkOrientation, :: GtkPanedHandleWidth,
- :: GtkResize, :: GtkResponse, :: GtkScrollbarPolicy, :: GtkSensitivity,
- :: GtkShrink, :: GtkSizeRequest, :: GtkSpacing, :: GtkStylePriority,
- :: GtkText, :: GtkTitle, :: GtkWrapMode
-
+ :: GtkMarkup, :: GtkMessageType, :: GtkModal, :: GtkOrientation,
+ :: GtkPanedHandleWidth, :: GtkResize, :: GtkResponse,
+ :: GtkScrollbarPolicy, :: GtkSensitivity, :: GtkShrink, :: GtkSizeRequest,
+ :: GtkSpacing, :: GtkStylePriority, :: GtkText, :: GtkTitle, :: GtkWrapMode
+
+/**
+ * A `GtkAccelGroup` is needed for a `GtkAccelerator`. 'Accelerator' is Gtk's
+ * term for what most people call shortcuts, i.e. `Ctrl`-`S`, etc.
+ */
:: GtkAccelGroup =: GtkAccelGroup Pointer
newAccelGroup :: !w -> GtkM GtkAccelGroup | gtkWindow w
+/**
+ * An accelerator is what people normally call a shortcut (e.g. `Ctrl`-`S`).
+ * The `String` is the name of the key that is pressed. See `gdkkeysyms.h` and
+ * remove the `GDK_KEY_` prefix; hence e.g. `s` for the letter `s` or `Return`
+ * for the return/enter key.
+ */
:: GtkAccelerator = Accelerator !GtkAccelGroup !String ![GdkModifier]
+//* An action bar typically holds a number of buttons.
:: GtkActionBar =: GtkActionBar Pointer
instance gtkWidget GtkActionBar
newActionBar :: GtkM GtkActionBar
+
+//* Add `w` to the start or end of the action bar.
packActionBar :: !GtkActionBar !GtkDirection !w -> GtkM w | gtkWidget w
+//* A box holds a number of child widgets in some direction with spacing.
:: GtkBox =: GtkBox Pointer
instance gtkWidget GtkBox
instance gtkContainer GtkBox
instance gtkOrientable GtkBox
-newBox :: !GtkOrientation !Int -> GtkM GtkBox
+newBox :: !GtkOrientation -> GtkM GtkBox
+
+/**
+ * Add `w` to the start or the end of the box. When used with `Expand`,
+ * additional space for the box is given to this child (and all other children
+ * with `Expand` set).
+ */
packBox :: !GtkBox !GtkDirection !GtkExpand !w -> GtkM w | gtkWidget w
instance tune GtkBox GtkSpacing
@@ -42,6 +82,12 @@ instance tune GtkBox GtkSpacing
:: GtkButton =: GtkButton Pointer
instance gtkWidget GtkButton
+/**
+ * Create a button with a single icon. See the icon naming specification for a
+ * list of common icon names:
+ * https://developer.gnome.org/icon-naming-spec/
+ * You can also see the icons in `/usr/share/icons/<theme>/<size>.
+ */
newButtonFromIconName :: !String -> GtkM GtkButton
:: GtkContainer =: GtkContainer Pointer
@@ -53,6 +99,7 @@ instance gtkContainer GtkContainer
addToContainer :: !c !w -> GtkM w | gtkWidget w & gtkContainer c
+//* A dialog is a popup window.
:: GtkDialog =: GtkDialog Pointer
class gtkDialog a :: !a -> GtkDialog
@@ -62,18 +109,39 @@ instance gtkContainer GtkDialog
instance gtkWindow GtkDialog
instance gtkDialog GtkDialog
+//* If a dialog is `Modal` it prevents interaction with the underlying window.
instance tune d GtkModal | gtkDialog d
newDialog :: !GtkWindow -> GtkM GtkDialog
+
+/**
+ * Runs a dialog, returning when a button has been activated or the dialog has
+ * been closed somehow (typically by pressing `Esc`). Note that you still need
+ * to `destroy` the dialog (this allows you to not close the dialog and show an
+ * error message, if appropriate).
+ */
runDialog :: !d -> GtkM GtkResponse | gtkDialog d
+/**
+ * Add a button with the given `String` as text to the dialog. When pressed,
+ * the dialog returns the given `GtkResponse`.
+ */
addButton :: !String !GtkResponse !d -> GtkM GtkButton | gtkDialog d
getContentArea :: !d -> GtkBox | gtkDialog d
+//* Convenience function to create a simple message dialog.
newMessageDialog :: !GtkWindow !GtkMessageType !GtkButtonsType !String -> GtkM GtkDialog
+
+/**
+ * Convenience function to select a file or folder. The optional `String` is
+ * the title for the dialog. This function internally calls `runDialog` and
+ * returns the chosen file path, or `Nothing` if the dialog has been cancelled
+ * somehow.
+ */
getFileWithDialog :: !GtkWindow !GtkFileChooserAction !(Maybe String) -> GtkM (Maybe FilePath)
+//* An entry is a simple text field. Subclasses allow more advanced input.
:: GtkEntry =: GtkEntry Pointer
class gtkEntry a :: !a -> GtkEntry
@@ -87,50 +155,97 @@ getText :: !e -> GtkM String | gtkEntry e
instance tune GtkEntry GtkText
instance tune GtkEntry GtkEntryCompletion
+/**
+ * See the Gtk documentation an overview of user input completion:
+ * https://developer.gnome.org/gtk3/stable/GtkEntryCompletion.html#GtkEntryCompletion.description
+ *
+ * We do not provide all features here, but assume the common use case of a
+ * `GtkListStore` that is filtered with the default match function. It is
+ * possible to tune the completion method with a `GtkCompletionMode`, however.
+ */
:: GtkEntryCompletion =: GtkEntryCompletion Pointer
newEntryCompletion :: GtkM GtkEntryCompletion
+
+//* Sets the column of the `GtkListStore` to be used for completion.
setTextColumn :: !Int !GtkEntryCompletion -> GtkM GtkEntryCompletion
instance tune GtkEntryCompletion GtkListStore
instance tune GtkEntryCompletion GtkCompletionMode
+//* A frame holds a single child, with a border and an optional title.
:: GtkFrame =: GtkFrame Pointer
instance gtkWidget GtkFrame
instance gtkContainer GtkFrame
+//* Create a new frame with `w` as the child.
newFrame :: !GtkTitle !w -> GtkM GtkFrame | gtkWidget w
+//* Convenience function to create a widget and a frame around it at once.
framed :: !GtkTitle !(GtkM w) -> GtkM (w, GtkFrame) | gtkWidget w
+/**
+ * A grid is a generalized table, allowing outlining child widget positions to
+ * each other.
+ */
:: GtkGrid =: GtkGrid Pointer
instance gtkWidget GtkGrid
newGrid :: GtkM GtkGrid
+
+/**
+ * Attach `w` to the given grid. The first `(Int,Int)` argument is the position
+ * in the grid (where the top left is `(0,0)`); the second `(Int,Int)` argument
+ * is the number of rows and columns that the widget occupies.
+ */
attachGrid :: !GtkGrid !(!Int,!Int) !(!Int,!Int) !w -> GtkM w | gtkWidget w
+//* A label is used to display a small or medium amount of text.
:: GtkLabel =: GtkLabel Pointer
instance gtkWidget GtkLabel
newLabel :: GtkM GtkLabel
instance tune GtkLabel GtkText
+/**
+ * A list store holds values in a list. It is used in several places, like for
+ * `GtkEntryCompletion` and `GtkTreeView`.
+ */
:: GtkListStore =: GtkListStore Pointer
+//* Create a new list store where rows are lists of values of the given types.
newListStore :: ![GType] -> GtkM GtkListStore
+
+//* Remove all items from the list store.
clearListStore :: !GtkListStore -> GtkM GtkListStore
+
+//* Add a new value to the end of the list store.
appendToListStore :: ![GValue] !GtkListStore -> GtkM GtkListStore
+
+//* Swap the items at the given indices in the list store, returning success.
swapItems :: !Int !Int !GtkListStore -> GtkM Bool
+/**
+ * A menu provides actions to the user. `GtkMenu` by itself is useful to create
+ * sub-menus (see `setSubMenu`). For a top-level menu, see `GtkMenuBar`.
+ */
:: GtkMenu =: GtkMenu Pointer
instance gtkWidget GtkMenu
newMenu :: GtkM GtkMenu
+/**
+ * A menu bar is usually placed at the top of a window, providing actions to
+ * the user.
+ */
:: GtkMenuBar =: GtkMenuBar Pointer
instance gtkWidget GtkMenuBar
newMenuBar :: GtkM GtkMenuBar
+/**
+ * A menu item is an item in a menu. Attach an `ActivateHandler` or set a
+ * sub-menu with `setSubMenu`.
+ */
:: GtkMenuItem =: GtkMenuItem Pointer
class gtkMenuItem a :: !a -> GtkMenuItem
@@ -139,22 +254,31 @@ instance gtkWidget GtkMenuItem
instance gtkMenuItem GtkMenuItem
newMenuItem :: !String -> GtkM GtkMenuItem
+
+//* Attach the menu as a sub-menu to `mi`.
setSubMenu :: !mi !GtkMenu -> GtkM GtkMenu | gtkMenuItem mi
+//* A check menu item is a menu item with a checkbox.
:: GtkCheckMenuItem =: GtkCheckMenuItem Pointer
instance gtkWidget GtkCheckMenuItem
instance gtkMenuItem GtkCheckMenuItem
newCheckMenuItem :: !String -> GtkM GtkCheckMenuItem
+
+//* Check whether the checkbox of the menu item is checked.
isActive :: !GtkCheckMenuItem -> GtkM Bool
+
+//* Modify the checked status of the checkbox of the menu item.
setActive :: !Bool !GtkCheckMenuItem -> GtkM GtkCheckMenuItem
+//* A separator menu item draws as a simple line to group other items together.
:: GtkSeparatorMenuItem =: GtkSeparatorMenuItem Pointer
instance gtkWidget GtkSeparatorMenuItem
instance gtkMenuItem GtkSeparatorMenuItem
newSeparatorMenuItem :: GtkM GtkSeparatorMenuItem
+//* This is an interface for widgets that hold a collection of menu items.
:: GtkMenuShell =: GtkMenuShell Pointer
instance gtkWidget GtkMenuShell
@@ -163,12 +287,14 @@ instance gtkMenuShell GtkMenu, GtkMenuBar, GtkMenuShell
appendToMenuShell :: !s !mi -> GtkM mi | gtkMenuShell s & gtkMenuItem mi
+//* This is an interface for widgets of which the children can be oriented.
:: GtkOrientable =: GtkOrientable Pointer
class gtkOrientable a :: !a -> GtkOrientable
instance tune o GtkOrientation | gtkOrientable o
+//* A paned holds two children, with a (usually moveable) handle in between.
:: GtkPaned =: GtkPaned Pointer
instance gtkWidget GtkPaned
instance gtkContainer GtkPaned
@@ -177,6 +303,10 @@ newPaned :: !GtkOrientation !GtkPanedHandleWidth -> GtkM GtkPaned
packPane1 :: !GtkPaned !GtkResize !GtkShrink !w -> GtkM w | gtkWidget w
packPane2 :: !GtkPaned !GtkResize !GtkShrink !w -> GtkM w | gtkWidget w
+/**
+ * A scrolled window holds a single child and uses a scrollbar if it does not
+ * fit in the outer dimensions.
+ */
:: GtkScrolledWindow =: GtkScrolledWindow Pointer
instance gtkWidget GtkScrolledWindow
instance gtkContainer GtkScrolledWindow
@@ -186,17 +316,20 @@ newScrolledWindow :: GtkM GtkScrolledWindow
instance tune GtkScrolledWindow (GtkScrollbarPolicy, GtkScrollbarPolicy)
where tune :: !(!GtkScrollbarPolicy, !GtkScrollbarPolicy) !GtkScrolledWindow -> GtkM GtkScrolledWindow
+//* A search entry is a special entry with a search icon and clear button.
:: GtkSearchEntry =: GtkSearchEntry Pointer
instance gtkWidget GtkSearchEntry
instance gtkEntry GtkSearchEntry
newSearchEntry :: GtkM GtkSearchEntry
+//* A separator is a simple line, allowing for separation between widgets.
:: GtkSeparator =: GtkSeparator Pointer
instance gtkWidget GtkSeparator
newSeparator :: !GtkOrientation -> GtkM GtkSeparator
+//* A spinner is an animated widget signaling indefinite progress.
:: GtkSpinner =: GtkSpinner Pointer
instance gtkWidget GtkSpinner
@@ -204,12 +337,14 @@ newSpinner :: GtkM GtkSpinner
startSpinner :: !GtkSpinner -> GtkM GtkSpinner
stopSpinner :: !GtkSpinner -> GtkM GtkSpinner
+//* A text buffer is viewed by a `GtkTextView`; updates occur on this type.
:: GtkTextBuffer =: GtkTextBuffer Pointer
-setText :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
-setMarkup :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
+instance tune GtkTextBuffer GtkText
+instance tune GtkTextBuffer GtkMarkup
insertAtCursor :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
+//* A text view holds a larger amount of text than a `GtkLabel`.
:: GtkTextView =: GtkTextView Pointer
instance gtkWidget GtkTextView
instance gtkContainer GtkTextView
@@ -219,16 +354,33 @@ getTextBuffer :: !GtkTextView -> GtkTextBuffer
instance tune GtkTextView GtkWrapMode
+//* A tree view is a view on a `GtkListStore` with customizable columns.
:: GtkTreeView =: GtkTreeView Pointer
instance gtkWidget GtkTreeView
newTreeView :: !GtkListStore -> GtkM GtkTreeView
+
+/**
+ * Append a column with a given title to the tree view. The `Int` argument is
+ * the column index in the list store that is shown. When `Expand` is used,
+ * excess space of the tree view is (partially) given to this column.
+ */
appendColumnToTreeView :: !String !Int !GtkExpand !GtkTreeView -> GtkM GtkTreeView
+//* Add a signal handler for the event that the user selects a different row.
addSelectionChangedHandler :: !(GtkM ()) !GtkTreeView -> GtkM GtkTreeView
+
+/**
+ * Gets the path to the currently selected item, or `Nothing` if no item is
+ * selected. For list stores, this is a singleton list containing the row
+ * number.
+ */
getPathToSelection :: !GtkTreeView -> GtkM (Maybe [Int])
+
+//* Select an item in the view, by its path (see `getPathToSelection`).
selectPath :: ![Int] !GtkTreeView -> GtkM Bool
+//* This is an abstract class; every GUI element is a widget.
:: GtkWidget =: GtkWidget Pointer
class gtkWidget a :: !a -> GtkWidget
@@ -237,14 +389,20 @@ instance gtkWidget GtkWidget
show :: !w -> GtkM w | gtkWidget w
hide :: !w -> GtkM w | gtkWidget w
+
+//* Check whether this widget and all of its parents are visible.
isVisible :: !w -> GtkM Bool | gtkWidget w
+
+//* Destroy the widget, freeing all related memory.
destroy :: !w -> GtkM () | gtkWidget w
+
+//* Grabs user input focus. This only makes sense for `GtkEntry` and similar.
grabFocus :: !w -> GtkM w | gtkWidget w
-addCSSClass :: !GtkCSSClass !w -> GtkM w | gtkWidget w
removeCSSClass :: !GtkCSSClass !w -> GtkM () | gtkWidget w
-setMargins :: !GtkMargins !w -> GtkM w | gtkWidget w
+instance tune w GtkCSSClass | gtkWidget w
+instance tune w GtkMargins | gtkWidget w
instance tune w GtkSensitivity | gtkWidget w
instance tune w (GtkAlign,GtkAlign) | gtkWidget w
where tune :: !(!GtkAlign, !GtkAlign) !w -> GtkM w | gtkWidget w
@@ -253,6 +411,7 @@ where tune :: !(!GtkExpand, !GtkExpand) !w -> GtkM w | gtkWidget w
instance tune w GtkAccelerator | gtkWidget w
instance tune w GtkSizeRequest | gtkWidget w
+//* A window is a top-level element, holding a single child widget.
:: GtkWindow =: GtkWindow Pointer
class gtkWindow a :: !a -> GtkWindow
@@ -263,6 +422,12 @@ instance gtkWindow GtkWindow
newPopup :: GtkM GtkWindow
newWindow :: GtkM GtkWindow
+
+/**
+ * Adds CSS from a local file to the window and all its child widgets.
+ * @result Success (the operation may fail if the file cannot be found or
+ * contains illegal syntax).
+ */
addCSSFromFile :: !GtkStylePriority !FilePath !GtkWindow -> GtkM Bool
instance tune w GtkTitle | gtkWindow w
diff --git a/src/Gtk/Widgets.icl b/src/Gtk/Widgets.icl
index 2c522d0..702ea0e 100644
--- a/src/Gtk/Widgets.icl
+++ b/src/Gtk/Widgets.icl
@@ -42,9 +42,9 @@ instance gtkWidget GtkBox where gtkWidget (GtkBox b) = GtkWidget b
instance gtkContainer GtkBox where gtkContainer (GtkBox b) = GtkContainer b
instance gtkOrientable GtkBox where gtkOrientable (GtkBox b) = GtkOrientable b
-newBox :: !GtkOrientation !Int -> GtkM GtkBox
-newBox orientation spacing =
- toStateR (gtk_box_new orientation=:Vertical spacing) >>= \b ->
+newBox :: !GtkOrientation -> GtkM GtkBox
+newBox orientation =
+ toStateR (gtk_box_new orientation=:Vertical 0) >>= \b ->
show (GtkBox b)
packBox :: !GtkBox !GtkDirection !GtkExpand !w -> GtkM w | gtkWidget w
@@ -425,19 +425,21 @@ stopSpinner spinner=:(GtkSpinner s) =
toState (gtk_spinner_stop s) >>|
pure spinner
-setText :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
-setText s buffer=:(GtkTextBuffer b) =
- toState (gtk_text_buffer_set_text b s (size s)) >>|
- pure buffer
+instance tune GtkTextBuffer GtkText
+where
+ tune (Text s) buffer=:(GtkTextBuffer b) =
+ toState (gtk_text_buffer_set_text b s (size s)) >>|
+ pure buffer
-setMarkup :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
-setMarkup s buffer=:(GtkTextBuffer b) =
- toStateR (gtk_text_buffer_get_start_iter b) >>= \start ->
- toStateR (gtk_text_buffer_get_end_iter b) >>= \end ->
- toState (gtk_text_buffer_delete b start end) >>|
- toStateR (gtk_text_buffer_get_start_iter b) >>= \start ->
- toState (gtk_text_buffer_insert_markup b start s) >>|
- pure buffer
+instance tune GtkTextBuffer GtkMarkup
+where
+ tune (Markup s) buffer=:(GtkTextBuffer b) =
+ toStateR (gtk_text_buffer_get_start_iter b) >>= \start ->
+ toStateR (gtk_text_buffer_get_end_iter b) >>= \end ->
+ toState (gtk_text_buffer_delete b start end) >>|
+ toStateR (gtk_text_buffer_get_start_iter b) >>= \start ->
+ toState (gtk_text_buffer_insert_markup b start s) >>|
+ pure buffer
insertAtCursor :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
insertAtCursor s buffer=:(GtkTextBuffer b) =
@@ -540,27 +542,29 @@ grabFocus widget =
toState (gtk_widget_grab_focus w) >>|
pure widget
-addCSSClass :: !GtkCSSClass !w -> GtkM w | gtkWidget w
-addCSSClass (Class cls) widget =
- let (GtkWidget w) = gtkWidget widget in
- toStateR (gtk_widget_get_style_context w) >>= \context ->
- toState (gtk_style_context_add_class context cls) >>|
- pure widget
-
removeCSSClass :: !GtkCSSClass !w -> GtkM () | gtkWidget w
removeCSSClass (Class cls) widget =
let (GtkWidget w) = gtkWidget widget in
toStateR (gtk_widget_get_style_context w) >>= \context ->
toState (gtk_style_context_remove_class context cls)
-setMargins :: !GtkMargins !w -> GtkM w | gtkWidget w
-setMargins {left,top,right,bottom} widget =
- let (GtkWidget w) = gtkWidget widget in
- toState (gtk_widget_set_margin_left w left) >>|
- toState (gtk_widget_set_margin_top w top) >>|
- toState (gtk_widget_set_margin_right w right) >>|
- toState (gtk_widget_set_margin_bottom w bottom) >>|
- pure widget
+instance tune w GtkCSSClass | gtkWidget w
+where
+ tune (Class cls) widget =
+ let (GtkWidget w) = gtkWidget widget in
+ toStateR (gtk_widget_get_style_context w) >>= \context ->
+ toState (gtk_style_context_add_class context cls) >>|
+ pure widget
+
+instance tune w GtkMargins | gtkWidget w
+where
+ tune {left,top,right,bottom} widget =
+ let (GtkWidget w) = gtkWidget widget in
+ toState (gtk_widget_set_margin_left w left) >>|
+ toState (gtk_widget_set_margin_top w top) >>|
+ toState (gtk_widget_set_margin_right w right) >>|
+ toState (gtk_widget_set_margin_bottom w bottom) >>|
+ pure widget
instance tune w GtkSensitivity | gtkWidget w
where
diff --git a/src/Gtk/Widgets/Sheet.dcl b/src/Gtk/Widgets/Sheet.dcl
index 2541242..0f365d2 100644
--- a/src/Gtk/Widgets/Sheet.dcl
+++ b/src/Gtk/Widgets/Sheet.dcl
@@ -4,6 +4,8 @@ definition module Gtk.Widgets.Sheet
* This module provides support for GtkSheet; a spreadsheet widget. See
* https://fpaquet.github.io/gtksheet/ for more details and installation
* instructions. Use the 'Gtk with GtkSheet' environment.
+ *
+ * Note that the C library is slightly buggy.
*/
from StdMaybe import :: Maybe
@@ -26,8 +28,19 @@ instance gtkWidget GtkSheet
instance gtkContainer GtkSheet
newSheet :: !Int !Int !String -> GtkM GtkSheet
+
+/**
+ * Freezing a sheet means that the GUI will not be updated; all model updates
+ * are collected and the GUI is updated in a single step when the sheet is
+ * unfrozen. This is a wrapper function which freezes the sheet, executes the
+ * monad, and then unfreezes the sheet again.
+ */
whileFrozen :: !(GtkM a) !GtkSheet -> GtkM a
+/**
+ * Make sure the sheet has the given width and height by adding or deleting
+ * rows and columns.
+ */
ensureDimensions :: !Int !Int !GtkSheet -> GtkM GtkSheet
setColumnTitle :: !Int !String !GtkSheet -> GtkM GtkSheet
diff --git a/src/Gtk/Widgets/Sheet/Signal.dcl b/src/Gtk/Widgets/Sheet/Signal.dcl
index 5708651..9084b4d 100644
--- a/src/Gtk/Widgets/Sheet/Signal.dcl
+++ b/src/Gtk/Widgets/Sheet/Signal.dcl
@@ -4,11 +4,16 @@ from StdMaybe import :: Maybe
from Gtk.Signal import class signalHandler, :: SignalHandlerInternal
from Gtk.State import :: GtkM
+from Gtk.Tune import class tune
+from Gtk.Types import :: GtkPropagate
+from Gtk.Widgets import class gtkWidget
:: GtkSheetSignalHandler
= DeactivateHandler !(Int Int -> GtkM Bool)
- | EnterPressedHandler !(GtkM Bool)
+ | EnterPressedHandler !(GtkM GtkPropagate)
| SheetActivateHandler !(Int Int -> GtkM ())
| TraverseHandler !((Maybe (Int,Int)) (Int,Int) -> GtkM (Maybe (Int, Int)))
instance signalHandler GtkSheetSignalHandler
+
+instance tune w GtkSheetSignalHandler | gtkWidget w
diff --git a/src/Gtk/Widgets/Sheet/Signal.icl b/src/Gtk/Widgets/Sheet/Signal.icl
index 6de4209..d08f4dd 100644
--- a/src/Gtk/Widgets/Sheet/Signal.icl
+++ b/src/Gtk/Widgets/Sheet/Signal.icl
@@ -18,7 +18,7 @@ where
TraverseHandler _ -> "traverse"
signalHandler handler = case handler of
DeactivateHandler f -> SHI_Int_Int_Bool f
- EnterPressedHandler f -> SHI_Pointer_Bool \_ -> not <$> f
+ EnterPressedHandler f -> SHI_Pointer_Bool \_ -> (\p -> p=:StopPropagation) <$> f
SheetActivateHandler f -> SHI_Int_Int_Bool \r c -> f r c >>| pure True
TraverseHandler f -> SHI_Int_Int_Pointer_Pointer_Bool \oldrow oldcol newrowp newcolp ->
let newrow = readInt4S newrowp 0; newcol = readInt4S newcolp 0 in
@@ -35,3 +35,7 @@ where
appWorld (forceEval (writeInt4 newrowp 0 row)) >>|
appWorld (forceEval (writeInt4 newcolp 0 col)) >>|
pure True)
+
+instance tune w GtkSheetSignalHandler | gtkWidget w
+where
+ tune handler widget = installSignalHandler handler widget