You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(4) |
Jun
|
Jul
(68) |
Aug
(4) |
Sep
|
Oct
(23) |
Nov
(95) |
Dec
(9) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(3) |
Feb
|
Mar
|
Apr
(51) |
May
(81) |
Jun
(2) |
Jul
(86) |
Aug
(143) |
Sep
(3) |
Oct
(31) |
Nov
(63) |
Dec
(90) |
2005 |
Jan
(277) |
Feb
(157) |
Mar
(99) |
Apr
(195) |
May
(151) |
Jun
(148) |
Jul
(98) |
Aug
(123) |
Sep
(20) |
Oct
(174) |
Nov
(155) |
Dec
(26) |
2006 |
Jan
(51) |
Feb
(19) |
Mar
(16) |
Apr
(12) |
May
(5) |
Jun
|
Jul
(11) |
Aug
(7) |
Sep
(10) |
Oct
(31) |
Nov
(174) |
Dec
(56) |
2007 |
Jan
(45) |
Feb
(52) |
Mar
(10) |
Apr
(5) |
May
(47) |
Jun
(16) |
Jul
(80) |
Aug
(29) |
Sep
(14) |
Oct
(59) |
Nov
(46) |
Dec
(16) |
2008 |
Jan
(10) |
Feb
(1) |
Mar
|
Apr
|
May
(49) |
Jun
(26) |
Jul
(8) |
Aug
(4) |
Sep
(25) |
Oct
(53) |
Nov
(9) |
Dec
(1) |
2009 |
Jan
(66) |
Feb
(11) |
Mar
(1) |
Apr
(14) |
May
(8) |
Jun
(1) |
Jul
(2) |
Aug
(2) |
Sep
(9) |
Oct
(23) |
Nov
(35) |
Dec
|
2010 |
Jan
(7) |
Feb
(2) |
Mar
(39) |
Apr
(19) |
May
(161) |
Jun
(19) |
Jul
(32) |
Aug
(65) |
Sep
(113) |
Oct
(120) |
Nov
(2) |
Dec
|
2012 |
Jan
|
Feb
(5) |
Mar
(4) |
Apr
(7) |
May
(9) |
Jun
(14) |
Jul
(1) |
Aug
|
Sep
(1) |
Oct
(1) |
Nov
(12) |
Dec
(2) |
2013 |
Jan
(1) |
Feb
(17) |
Mar
(4) |
Apr
(4) |
May
(9) |
Jun
|
Jul
(8) |
Aug
|
Sep
(2) |
Oct
|
Nov
|
Dec
|
From: <du...@co...> - 2008-05-22 19:23:57
|
Sun Feb 17 20:11:20 EST 2008 Peter Gavin <pg...@gm...> * gstreamer: add StaticPadTemplate to M.S.G.Core.Types hunk ./gstreamer/Media/Streaming/GStreamer/Core/Types.chs 65 + StaticPadTemplate(..), + staticPadTemplateGet, hunk ./gstreamer/Media/Streaming/GStreamer/Core/Types.chs 311 +{# pointer *GstStaticPadTemplate as StaticPadTemplate #} +staticPadTemplateGet :: StaticPadTemplate + -> IO PadTemplate +staticPadTemplateGet = + {# call static_pad_template_get #} >=> takeObject + |
From: <du...@co...> - 2008-05-22 19:23:57
|
Sat May 17 15:11:40 EDT 2008 Peter Gavin <pg...@gm...> * Makefile.am: add docs/reference/haddock-util.js to htmldoc_DATA hunk ./Makefile.am 2203 + docs/reference/haddock-util.js \ |
From: Duncan C. <dun...@wo...> - 2008-02-01 15:46:19
|
Mon Jan 28 09:08:16 PST 2008 Duncan Coutts <du...@ha...> * Fix the get side of all container child attributes. It was accidentally calling 'set' rather than 'get'. doh! :-) hunk ./gtk/Graphics/UI/Gtk/Abstract/ContainerChildProperties.chs 86 - {# call container_child_set_property #} + {# call container_child_get_property #} |
From: Axel S. <A....@ke...> - 2008-01-11 20:04:42
|
Wed Jan 2 06:16:54 PST 2008 hth...@zo... * Tutorial-Port: Correction of typing errors. Eduardo Basterrechea has noted the typing errors he found during his translation to Spanish of the Gtk2Hs tutorial chapters 1 - 7. These and a few more are corrected here. hunk ./docs/tutorial/Tutorial_Port/chap4-2.xhtml 383 -The number of precision shown on the three scles will be managed with another +The number of precision shown on the three scales will be managed with another hunk ./docs/tutorial/Tutorial_Port/chap4-2.xhtml 392 -When the control adjustment changes the signal <code>onValueChanged</code> will +When the control adjustment changes, the signal <code>onValueChanged</code> will hunk ./docs/tutorial/Tutorial_Port/chap4-2.xhtml 412 -adjusting of the adjustment by a the <code>onValueChanged</code> signal from a +adjusting of the adjustment by a <code>onValueChanged</code> signal from a hunk ./docs/tutorial/Tutorial_Port/chap4-3.xhtml 102 -You can also make text in a lable selectable, so the user can copy and paste +You can also make text in a label selectable, so the user can copy and paste hunk ./docs/tutorial/Tutorial_Port/chap4-7.xhtml 119 -of decimal places (digits) to disply. +of decimal places (digits) to display. hunk ./docs/tutorial/Tutorial_Port/chap4-7.xhtml 188 -bottom repectively the top of the <code>Adjustment</code> range. +bottom, respectively the top, of the <code>Adjustment</code> range. hunk ./docs/tutorial/Tutorial_Port/chap4-7.xhtml 204 -case of <code>UpdateIfValid</code> the spin button only value gets changed if +case of <code>UpdateIfValid</code> the spin button value only gets changed if hunk ./docs/tutorial/Tutorial_Port/chap5-1.xhtml 20 - <h3>Calendar</h3> + <h3>5.1 Calendar</h3> hunk ./docs/tutorial/Tutorial_Port/chap5-1.xhtml 72 - <p>Note: there is no attribute for CalendarWeekStartMonday and + <p class="notebox"><strong>Note:</strong> there is no attribute for CalendarWeekStartMonday and hunk ./docs/tutorial/Tutorial_Port/chap5-1.xhtml 94 - <p>Note: the following are also mentioned in the API + <p class="notebox"><strong>Note:</strong> the following are also mentioned in the API hunk ./docs/tutorial/Tutorial_Port/chap5-2.xhtml 208 - <p>Note: With Gtk2Hs 0.9-12 and GHC 6.1 on FC 6, multiple file + <p class="notebox"><strong>Note:</strong> With Gtk2Hs 0.9-12 and GHC 6.1 on FC 6, multiple file hunk ./docs/tutorial/Tutorial_Port/chap5-2.xhtml 349 - <p>Note: When testing with Gtk2Hs 0.9-12 and GHC 6.1 on FC6, + <p class="notebox"><strong>Note:</strong> When testing with Gtk2Hs 0.9-12 and GHC 6.1 on FC6, hunk ./docs/tutorial/Tutorial_Port/chap5-2.xhtml 362 - <br />Calendar</span> + <br />5.1 Calendar</span> hunk ./docs/tutorial/Tutorial_Port/chap5-2.xhtml 368 - <br />Font Selection</span> + <br />5.3 Font Selection</span> hunk ./docs/tutorial/Tutorial_Port/chap5-3.xhtml 72 - <p>Whith a ColorButton use:</p> + <p>With a ColorButton use:</p> hunk ./docs/tutorial/Tutorial_Port/chap5-3.xhtml 170 - <a href="chap1.xhtml">Previous</a> + <a href="chap5-2.xhtml">Previous</a> hunk ./docs/tutorial/Tutorial_Port/chap5-3.xhtml 176 - <a href="chap3-1.xhtml">Next + <a href="chap5-4.xhtml">Next hunk ./docs/tutorial/Tutorial_Port/chap6-1.xhtml 37 - <pre class="codebox">scrolledWindowSetPolicy :: ScrolledWindowClass self => -self -> PolicyType -> PolicyType -> IO () + <pre class="codebox">scrolledWindowSetPolicy :: ScrolledWindowClass self => self -> PolicyType -> PolicyType -> IO () hunk ./docs/tutorial/Tutorial_Port/chap6-1.xhtml 52 - <pre class="codebox">scrolledWindowAddWithViewport :: (ScrolledWindowClass self, WidgetClass child) -=> self -> child -> IO () + <pre class="codebox">scrolledWindowAddWithViewport :: (ScrolledWindowClass self, WidgetClass child) => self -> child -> IO () hunk ./docs/tutorial/Tutorial_Port/chap6-1.xhtml 105 - <pre class="codebox">attachButton :: Table -> Button -> (Int,Int) -> IO () attachButton ta bu (x,y) = [_$_] - tableAttachDefaults ta bu y (y+1) x (x+1) + <pre class="codebox">attachButton :: Table -> Button -> (Int,Int) -> IO () attachButton ta bu (x,y) = tableAttachDefaults ta bu y (y+1) x (x+1) hunk ./docs/tutorial/Tutorial_Port/chap6-2.xhtml 119 - <pre class="codebox">buttonBoxSetChildSecondary :: (ButtonBoxClass self, WidgetClass child) -=> self -> child -> Bool -> IO () + <pre class="codebox">buttonBoxSetChildSecondary :: (ButtonBoxClass self, WidgetClass child) => self -> child -> Bool -> IO () hunk ./docs/tutorial/Tutorial_Port/chap6-2.xhtml 257 - <br />The Layout Container</span> + <br />6.3 The Layout Container</span> hunk ./docs/tutorial/Tutorial_Port/chap6-4.xhtml 119 - <br />7.1</span> + <br />7.1 Menus and Toolbars</span> hunk ./docs/tutorial/Tutorial_Port/chap7-1.xhtml 309 - <br />Popup Menus, Radio Actions and Toggle Actions</span> + <br />7.2 Popup Menus, Radio and Toggle Actions</span> hunk ./docs/tutorial/Tutorial_Port/chap7-2.xhtml 8 - <title>Gtk2Hs Tutorial: Menus and Toolbars</title> + <title>Gtk2Hs Tutorial: Popup Menus and Radio and Toggle Actions</title> hunk ./docs/tutorial/Tutorial_Port/index.xhtml 119 - <p>Copyright © 1998-2002 Tony Gale.</p> - <p>Copyright © 2007 Hans van Thiel and Alex Tarkovsky.</p> + <p>© 1998-2002 Tony Gale.</p> + <p>© 2007, 2008 Hans van Thiel and Alex Tarkovsky.</p> |
From: Axel S. <A....@ke...> - 2008-01-11 20:04:40
|
Tue Jan 1 08:57:58 PST 2008 hth...@zo... * Tutorial-Port Spanish Chapters 5, 6 and 7 (also corrected a previous typo) hunk ./docs/tutorial/Tutorial_Port/es-chap4-7.xhtml 1 -<!--<?xml version="1.0" encoding="UTF-8"?--> +<?xml version="1.0" encoding="UTF-8"?> addfile ./docs/tutorial/Tutorial_Port/es-chap5-1.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap5-1.xhtml 1 - +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es"><head> + [_$_] + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Calendario</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + <div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"><a href="es-chap4-7.xhtml">Previo</a></span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + </span> + <span class="nav-next"><a href="es-chap5-2.xhtml">Siguiente</a></span> + </div> + <h3>Calendario</h3> + <p>El widget Calendar es una buena manera de mostrar y recuperar + la información cronológica. Es un widget muy sencillo de crear y su + funcionamiento es muy simple. Debes usar:</p> + <pre class="codebox">calendarNew: IO Calendar +</pre> + <p>Por defecto se muestra el mes actual. Para recuperar la información de + un calendario emplea:</p> + <pre class="codebox">calendarGetDate :: CalendarClass self => self -> IO (Int, Int, Int) +</pre> + <p>donde la terna contendría la información (año, mes, día). (Enero es el 0). [_$_] + Los atributos relacionados son:</p> + <pre class="codebox">calendarYear :: CalendarClass self => Attr self Int +calendarMonth :: CalendarClass self => Attr self Int +calendarDay :: CalendarClass self => Attr self Int +</pre> + <p>El widget Calendar tiene algunas opciones que te permiten cambiar la apariencia y el modo de operación [_$_] + del widget. Para ello debes usar la función + <code>calendarSetDisplayOptions</code>. Para recuperar los valores usa: + <code>calendarGetDisplayOptions</code>.</p> + <pre class="codebox">calendarSetDisplayOptions :: CalendarClass self => self -> [CalendarDisplayOptions] -> IO () +calendarGetDisplayOptions :: CalendarClass self => self -> IO [CalendarDisplayOptions] +</pre> + <p> + <code>CalendarDisplayOptions</code> tiene los siguientes constructores:</p> + <ul> + <li>CalendarShowHeading: especifica el año y el mes a mostrar + por el calendario.</li> + <li>CalendarShowDayNames: indica que se debe poner una descripción de [_$_] + tres letras indicando el nombre del día de la semana (eg Lun,Mar, etc.).</li> + <li>CalendarNoMonthChange: señala que el usuario ni debe, ni puede, cambiar + el mes mostrado. Esto sirve en el caso de sólo necesites mostrar un mes [_$_] + concreto, como cuando creas 12 widgets mensuales para mostar un año completo.</li> + <li>CalendarShowWeekNumbers: esta opción indica que se debe mostrar el número de la semana [_$_] + en el lado izquierdo del calendario. (ej. Ene 1 = Semana 1,Dic 31 = Semana 52).</li> + <li>CalendarWeekStartMonday (fíjate en la nota de abajo): Esta opción indica que la semana + del calendario debe empezar en lunes en vez de en domingo (valor por defecto). Esto sólo + afecta al orden en que se muestran los días de izquierda a derecha.</li> + </ul> + <p>También puede obtenerse y cambiarse el valor de las opciones usando atributos + Booleanos mediante las funciones genéricas <code>get</code> y <code>set</code>.</p> + <p class="notebox">Nota: No hay atributo para CalendarWeekStartMonday y el uso de la función [_$_] + <code>calendarSetDisplay</code> origina un mensaje en tiempo de ejecución indicando que + el primer día de la semana se toma por defecto y se ignora GTK_CALENDAR_WEEK_START_MONDAY.</p> + <p>Por último, destacar que se pueden marcar algunos días del mes. Un día marcado [_$_] + se resalta en el calendario mostrado. Las siguientes funciones (sin atributos) sirven para manipular + los días marcados:</p> + <pre class="codebox">calendarMarkDay :: CalendarClass self => self -> Int -> IO Bool +calendarUnmarkDay :: CalendarClass self => self -> Int -> IO Bool +calendarClearMarks :: CalendarClass self => self -> IO () +</pre> + <p>El valor Booleano no se usa (siempre True). Las marcas se mantienen + en los cambios de mes y de año.</p> + <p>El widget Calendar puede generar señales que indican los cambios y la fecha [_$_] + seleccionada. Los nombres de esas señales son:</p> + <ul> + <li>onDaySelected</li> + <li>onDaySelectedDoubleClick</li> + </ul> + <p class="notebox">Nota: lo siguiente está mencionado en la documentación de la API, pero [_$_] + aparece implementado como onDaySelected. Mira el comentario en el código del ejemplo.</p> + <ul> + <li>onMonthChanged</li> + <li>onNextMonth</li> + <li>onNextYear</li> + <li>onPrevMonth</li> + <li>onPrevYear</li> + </ul> + <p>El siguiente ejemplo muestra el uso del widget Calendar:</p> + <p> + <img src="Images/GtkChap5-1.png" alt="GtkChap5-1.png" id="graphics1" /> + </p> + <pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Calendar", + windowDefaultWidth:= 200, + windowDefaultHeight:= 100] + mainbox <- vBoxNew True 0 + containerAdd window mainbox + + hbox1 <- hBoxNew True 0 + boxPackStart mainbox hbox1 PackGrow 0 + + cal <-calendarNew + boxPackStart hbox1 cal PackGrow 0 [_$_] + + vbox1 <- vBoxNew True 0 + frame1 <- frameNew + set frame1 [frameLabel := "Display Options", + containerBorderWidth := 10, + frameLabelYAlign := 0.5, [_$_] + frameLabelXAlign := 0.5, + containerChild := vbox1 ] + boxPackStart hbox1 frame1 PackGrow 0 + headingopt <- addDisplayOpt vbox1 "Show Heading" + daynameopt <- addDisplayOpt vbox1 "Show Day Names" + monchngopt <- addDisplayOpt vbox1 "No Month Change" + weeknumopt <- addDisplayOpt vbox1 "Show Week Numbers" + + set headingopt [toggleButtonActive := True] + set daynameopt [toggleButtonActive := True] + + reslabel <- labelNew Nothing + showMess cal reslabel "Nothing Done Yet" + frame2 <- frameNew + set frame2 [frameLabel := "Last Action:", + containerBorderWidth := 10, [_$_] + containerChild := reslabel] + boxPackStart mainbox frame2 PackGrow 0 [_$_] + + mySetOnToggled headingopt cal calendarShowHeading + mySetOnToggled daynameopt cal calendarShowDayNames + mySetOnToggled monchngopt cal calendarNoMonthChange + mySetOnToggled weeknumopt cal calendarShowWeekNumbers + + onDaySelected cal (showMess cal reslabel "Day Selected") + onDaySelectedDoubleClick cal [_$_] + (showMess cal reslabel "Double Click Day Selected") + + widgetShowAll window + onDestroy window mainQuit + mainGUI + + +addDisplayOpt :: VBox -> String -> IO CheckButton +addDisplayOpt box lbl = do + cb <- checkButtonNewWithLabel lbl + boxPackStart box cb PackGrow 5 + return cb + +mySetOnToggled :: CheckButton -> Calendar -> [_$_] + Attr Calendar Bool -> [_$_] + IO (ConnectId CheckButton) +mySetOnToggled cb cl att = onToggled cb $ do + cbstate <- get cb toggleButtonActive + set cl [att := cbstate] + +showMess :: Calendar -> Label -> String -> IO () +showMess cal lbl str = do [_$_] + (year, month, day) <- calendarGetDate cal + labelSetText lbl $ str ++ "\n" ++ "Date = " ++ + (show year) ++ "//" ++ [_$_] + (myshow (month +1)) -- month is 0 to 11 + ++ "//" ++ (myshow day) [_$_] + where myshow n | n <= 9 = '0':(show n) + | otherwise = show n + +{- Comentado para hacer una comprobación específica de la plataforma: +Estas señales parecen implementadas como onDaySelected. +La plataforma es: Gtk2Hs 0.9.12 en Fedora Core 6 + + onMonthChanged cal (showMess cal reslabel "Month Changed") + onNextMonth cal (showMess cal reslabel "Next Month Selected") + onNextYear cal (showMess cal reslabel "Next Year Selected") + onPrevMonth cal (showMess cal reslabel "Previous Month +Selected") + onPrevYear cal (showMess cal reslabel "Previous Year +Selected") +-} +</pre> + <div id="footer"> + <span class="nav-previous"><a href="es-chap4-7.xhtml">Previo</a><br />Botones aumentar/disminuir</span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + </span> + <span class="nav-next"><a href="es-chap5-2.xhtml">Siguiente</a><br />Selección de fichero</span> + </div> + [_$_] +</body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap5-2.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap5-2.xhtml 1 - +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="es"><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Selección de fichero</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + <div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"> + <a href="es-chap5-1.xhtml">Previo</a> + </span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + </span> + <span class="nav-next"> + <a href="es-chap5-3.xhtml">Siguiente</a> + </span> + </div> + <h2>5.2 Selección de fichero</h2> + <p>Los ficheros y los directorios (carpetas) son esenciales en cualquier + programa de ordenador y Gtk contiene diversos componentes para facilitar + su manejo. La selección de ficheros y directorios en Gtk2Hs se + implementa a través del interfaz <code>FileChooser</code>. Basicamente hay cuatro + modos, como se indica en el tipo <code>FileChooserAction</code>. Sus constructores son:</p> + <ul> + <li> + <code>FileChooserActionOpen</code> usado para que el usuario abra un fichero</li> + <li> + <code>FileChooserActionSave</code> usado para que el usuario guarde un fichero</li> + <li> + <code>FileChooserActionSelectFolder</code> usado para que el usuario seleccione un directorio</li> + <li> + <code>FileChooserActionCreateFolder</code> usado para que el usuario cree un directorio</li> + </ul> + <p>El interfaz [_$_] + <code>FileChooser</code> tiene atributos, métodos y señales, pero no es propiamente un widget. Hay tres + widgets que usan el interfaz de modo diferente, [_$_] + <code>FileChooserWidget</code> , [_$_] + <code>FileChooserButton</code> y [_$_] + <code>FileChooserDialog</code> . El widget a usar está restingido por la + <code>FileChooserActionType</code> permitida. Como verás en los ejemplos siguientes, + el widget para guardar un fichero o para seleccionar un directorio puede contener + también un botón que permita al usuario crear un directorio. Además, el constructor + FileActionCreateFolder probablemente nuncá será usado en ninguno de tus programas.</p> + <p>Es importante indicar que, a pesar de que los widgets no guardan ni abren ficheros por + sí mismos, le creación de los directorios (por el usuario) se implementa a través de widgets.</p> + <p>Nuestro primer ejemplo usará <code>FileChooserWidget</code> , que puede emplearse en el modo + Abrir y Salvar.</p> + <pre class="codebox">fileChooserWidgetNew :: FileChooserAction -> IO FileChooserWidget +</pre> + <p>Aquí usamos <code>FileChooserActionOpen</code>, y cuando el usuario elige definitivamente un fichero, ya sea + haciendo doble clic en él o pulsando la tecla Enter, la señal <code>onFileActived</code> se emite. Usamos:</p> [_$_] + <pre class="codebox">fileChooserGetFilename :: FileChooserClass self => self -> IO (Maybe FilePath) +</pre> + <p>Desde la ubicación del fichero, el programa puede abrir el fichero, o posiblemente hacer otra cosa. + El formato del filepath puede depender de la plataforma y está determinado por la variable de entorno [_$_] + G_FILENAME_ENCODING. Hay también funciones en <code>FileChooser</code> para formatos URI (Uniform Resource Identifier), + pero no las vamos a ver aquí.</p> + <p>Puedes permitir al usuario seleccionar múltiples ficheros con:</p> + <pre class="codebox">fileChooserSetselectMultiple :: FileChooserClass self => self -> Bool -> IO () +</pre> + <p>y, con el <code>FileChooserWidget</code> , puedes añadir fácilmente un botón check + para dejar al usuario determinarlo. La colocación de un widget de este tipo se hace de modo estándar + con:</p> + <pre class="codebox">fileChooserSetExtraWidget :: (FileChooserClass self, WidgetClass extraWidget) +=> self -> extraWidget -> IO () +</pre> + <p>Otra utilidad es el uso de filtros para mostrar sólo ficheros de un tipo, ya + sea especificando un tipo MIME, un pattern (plantilla) o un formato a medida. [_$_] + Los filtros de ficheros se documentan en Graphics.UI.Gtk.Selectors.FileFilter.</p> + <p>El siguiente trozo de código, parte del ejemplo siguiente, muestra los filtros. + La última línea simplemente añade el filtro al widget selector de fichero y, como ocurre con el widget extra, + el posicionamiento visual se hace automáticamente.</p> + <pre class="codebox"> hsfilt <- fileFilterNew + fileFilterAddPattern hsfilt "*.hs" + fileFilterSetName hsfilt "Haskell Source" [_$_] + fileChooserAddFilter fch hsfilt +</pre> + <p>Puedes también añadir un widget "preview" (previsualización) con:</p> + <pre class="codebox">fileChooserSetPreviewWidget :: (FileChooserClass self, WidgetClass +previewWidget) => self -> previewWidget -> IO () +</pre> + <p>En el ejemplo se usa para previsualizar ficheros gráficos. El ejemplo usa un widget [_$_] + <code>Image</code> (documentado en Graphics.UI.Gtk.Display.Image) como los usados antes en el + Capítulo 4.1. + Allí usamos <code>imageNewFromFile</code> para añadir gráficos a un botón; aquí construímos + un widget <code>Image</code> vacío.</p> + <p>Para actualizarlo cuando haya cambios, tenemos una señal <code>onUpdatePreview</code>, + que se emite cada vez que el usuario cambia la selección de fichero moviendo el ratón o con las teclas + de aceleración. Esta señal es más general que lo que su nombre sugiere, pero aquí se usa sólo para + previsualizar. El código es el siguiente:</p> + <pre class="codebox"> onUpdatePreview fch $ [_$_] + do file <- fileChooserGetPreviewFilename fch + case file of + Nothing -> putStrLn "No File Selected" + Just fpath -> imageSetFromFile img fpath +</pre> + <p>Hay funciones y atributos para controlar lo que se muestra, por ejemplo + lo que sucede cuando el fichero seleccionado no es un fichero gráfico, pero + no son estrictamente necesarios. En el resto del código los ficheros no gráficos [_$_] + se ignoran o se muestra un icono estándar. Así es como aparecen:</p> + <p> + <img src="Images/GtkChap5-2a.png" alt="File Selection examples" id="imgGtkChap5-2a" /> + </p> + <p>Fíjate en que el usuario también puede añadir y borrar bookmarks, y [_$_] + <code>FileChooser</code> tiene funciones para gestionar esto también. Sin + embargo, esta característica no se trata en el ejemplo <code>FileChooserWidget</code> , que + tiene el siguiente código fuente:</p> + <pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "File Chooser Widget", [_$_] + windowDefaultWidth := 500, + windowDefaultHeight := 400 ] + + fch <- fileChooserWidgetNew FileChooserActionOpen + containerAdd window fch [_$_] + + selopt <- checkButtonNewWithLabel "Multiple File Selection" + fileChooserSetExtraWidget fch selopt + + hsfilt <- fileFilterNew + fileFilterAddPattern hsfilt "*.hs" + fileFilterSetName hsfilt "Haskell Source" [_$_] + fileChooserAddFilter fch hsfilt + + nofilt <- fileFilterNew + fileFilterAddPattern nofilt "*.*" + fileFilterSetName nofilt "All Files" + fileChooserAddFilter fch nofilt + + img <- imageNew + fileChooserSetPreviewWidget fch img + + + onUpdatePreview fch $ [_$_] + do file <- fileChooserGetPreviewFilename fch + case file of + Nothing -> putStrLn "No File Selected" + Just fpath -> imageSetFromFile img fpath + + [_$_] + onFileActivated fch $ [_$_] + do dir <- fileChooserGetCurrentFolder fch + case dir of [_$_] + Just dpath -> putStrLn [_$_] + ("The current directory is: " ++ +dpath) + Nothing -> putStrLn "Nothing" [_$_] + mul <- fileChooserGetSelectMultiple fch [_$_] + if mul [_$_] + then do + fls <- fileChooserGetFilenames fch + putStrLn [_$_] + ("You selected " ++ (show (length fls)) ++ +"files:") + sequence_ (map putStrLn fls) + else do + file <- fileChooserGetFilename fch + case file of + Just fpath -> putStrLn ("You selected: " ++ +fpath) + Nothing -> putStrLn "Nothing" + + onToggled selopt $ do state <- toggleButtonGetActive selopt + fileChooserSetSelectMultiple fch state + + widgetShowAll window + onDestroy window mainQuit + mainGUI +</pre> + <p class="notebox">Nota: Con Gtk2Hs 0.9-12 y GHC 6.1 en Fedora Core 6, la selección múltiple [_$_] + de ficheros funciona visualmente (las teclas Ctrl y Shift funcionan como el usuario + supone), pero la lista de direcciones de fichero sólo contiene la dirección + del último fichero seleccionado.</p> + <p>El segundo modo de usar el interface <code>FileChooser</code> es a través de <code>FileChooserButton</code> .</p> + <pre class="codebox">fileChooserButtonNew :: String FileChooserAction -> String -> +IO FileChooserButton +</pre> + <p>El parámetro tipo <code>String</code> es el nombre de la ventana de diálogo que salta [_$_] + cuando el usuario selecciona la opción 'other...' después de pulsar el botón. En el ejemplo hemos + construido un botón de selección de fichero con FileChooserActionSelectFolder. Tras seleccionar el directorio + "Test", se vería así.</p> + <p> + <img src="Images/GtkChap5-2b1.png" alt="File Selection examples" id="imgGtkChap5-2b1" /> + </p> + <p>Así es como se vería la ventana de diálogo:</p> + <p> + <img src="Images/GtkChap5-2b2.png" alt="File Selection examples" id="imgGtkChap5-2b2" /> + </p> + <p>Como puedes ver, hay un botón "Create Folder" (Crea Carpeta) en la parte superior derecha de la ventana + de diálogo. La puedes usar para crear un directorio. Esto es lo que sucede si tratamos de crear una carpeta [_$_] + existente:</p> + <p> + <img src="Images/GtkChap5-2b3.png" alt="File Selection examples" id="imgGtkChap5-2b3" /> + </p> + <p>Crear o sobrescribir un directorio existente no tiene sentido y puede ser peligroso. Así + que Gtk2Hs automáticamente lo percibe y lo notifica al usuario. Cuando el usuario selecciona un [_$_] + directorio existente, la señal <code>onCurrentFolderChanged</code> se emite y el programa puede + tomar la acción apropiada. Al crear un directorio se selecciona automáticamente, así que, en ese caso, + la señal <code>onCurrentFolderChanged</code> también puede ser usada. Aquí está el código del ejemplo:</p> + <pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "File Chooser Button", +windowDefaultWidth := 250, windowDefaultHeight := 75 ] + fchd <- fileChooserButtonNew "Select Folder" +FileChooserActionSelectFolder + containerAdd window fchd + + onCurrentFolderChanged fchd $ + do dir <- fileChooserGetCurrentFolder fchd [_$_] + case dir of + Nothing -> putStrLn "Nothing" + Just dpath -> putStrLn ("You selected:\n" ++ +dpath) + + widgetShowAll window + onDestroy window mainQuit + mainGUI +</pre> + <p>La tercera manera de usar el interfaz <code>FileChooser</code> es a través de [_$_] + <code>FileChooserDialog</code> . Puede ser construido en modo abrir o salvar, y normalmente se aplica desde [_$_] + un menú o una barra de herramientas.</p> + <p> + <code>FileChooserDialog</code> implementa tanto [_$_] + <code>FileChooser</code> como [_$_] + <code>Dialog</code> . Recuerda del Capítulo 4.5 que un "diálogo" es un widget compuesto con botones, normalmente + implementados con <code>dialogRun</code>, que produce respuestas del tipo [_$_] + <code>ResponseId</code> . Un [_$_] + <code>FileChooserDialog</code> se construye con:</p> + <pre class="codebox">fileChooserDialogNew :: +Maybe String -- título del diálogo o "por defecto" +-> Maybe Window -- Ventana "padre" del diálogo o nada +-> FileChooserAction -- modo abrir o salvar +-> [(String, ResponseId)] -- lista de botones y sus códigos de respuesta +-> IO FileChooserDialog +</pre> + <p>Todo lo que tienes que hacer es indicar los nombres de los botones y sus respuestas en el cuarto + argumento, y serán automáticamente implementados.</p> + <p>El ejemplo usa [_$_] + <code>FileChooserActionSave</code> y la ventana de diálogo tiene tres botones. Así es como queda:</p> + <p> + <img src="Images/GtkChap5-2c.png" alt="File Selection examples" id="imgGtkChap5-2c" /> + </p> + <p>Como puedes ver aquí hay un botón en la parte superior derecha para crear una carpeta. Como en el ejemplo + anterior, intentar crear una carpeta ya existente genera un mensaje de error. [_$_] + Sobreescribir un fichero, sin embargo, tiene sentido y es admitido por defecto. + Puedes ahcer que el usuario confirme la sobreescritura de ficheros con:</p> + <pre class="codebox">fileChooserSetDoOverwriteconfirmation :: FileChooserClass self +=> self -> Bool -> IO () +</pre> + <p>Como ya mencioné, no se realizan escrituras o sobrescrituras de ficheros con el + widget <code>FileChooserDialog</code>; El programa simplemente obtiene el path del fichero.</p> + <p>Este es el código del tercer ejemplo:</p> + <pre class="codebox">import Graphics.UI.Gtk [_$_] + [_$_] +main :: IO () +main = do + initGUI + fchdal <- fileChooserDialogNew (Just "Save As...Dialog") +Nothing + FileChooserActionSave + [("Cancel", ResponseCancel), + ("Save", ResponseAccept), + ("Backup", ResponseUser 100)] + [_$_] + fileChooserSetDoOverwriteConfirmation fchdal True + widgetShow fchdal + response <- dialogRun fchdal + case response of + ResponseCancel -> putStrLn "You cancelled..." + ResponseAccept -> do nwf <- fileChooserGetFilename +fchdal + case nwf of + Nothing -> putStrLn +"Nothing" + Just path -> putStrLn ("New +file path is:\n" ++ path) + ResponseUser 100 -> putStrLn "You pressed the backup +button" + ResponseDeleteEvent -> putStrLn "You closed the dialog +window..." + + widgetDestroy fchdal + onDestroy fchdal mainQuit + mainGUI +</pre> + <p class="notebox">Nota: Al probarlo con Gtk2Hs 0.9-12 y GHC 6.1 en Fedora Core 6, + pulsar la tecla "Enter" para guardar el fichero no tiene ningún efecto. Cuando + se elige un fichero existente, pulsar la tecla "Save" no tiene efecto la primera vez, + pero si se pulsa de nuevo provoca la aparición de la ventana de confirmación. Mi + opinión es que esto tiene algo que ver con la señal <code>onConfirmOverwrite</code> y [_$_] + su segundo argumento de tipo <code>IO FileChooserConfirmation.</code> No entiendo bien su uso, + y quizá el error provenga de mi código.</p> + <div id="footer"> + <span class="nav-previous"> + <a href="es-chap5-1.xhtml">Previo</a> + <br />Calendario</span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + </span> + <span class="nav-next"> + <a href="es-chap5-3.xhtml">Siguiente</a> + <br />Seleción de Fuente (tipo de letra)</span> + </div></body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap5-3.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap5-3.xhtml 1 - +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="es"><head> + [_$_] + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Seleción de Fuente (tipo de letra)</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + <div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"> + <a href="es-chap5-2.xhtml">Previo</a> + </span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + </span> + <span class="nav-next"> + <a href="es-chap5-4.xhtml">Siguiente [_$_] + </a></span> + </div> + <h2>5.3 Seleción de Fuente (tipo de letra)</h2> + <p>La selección del color y del tipo de letra son muy parecidas + a la selección de ficheros. Hay tres maneras de implantarlas, como widgets, + como diálogos y como botones. Los valores seleccionados por el usuario se + obtienen a partir de atributos y funciones, como ya va resultando habitual. + Primero discutiremos la selección de tipo de letra (font). Puedes usar:</p> + <pre class="codebox">fontSelectionNew :: IO FontSelection +fontSelectionDialogNew :: String -> IO FontSelectionDialog +fontButtonNew :: IO FontButton +</pre> + <p>El parámetro [_$_] + <code>String</code> es el título de la ventana de diálogo. Hay un puñado de [_$_] + atributos y funciones para gestionar la presentación de estos widgets, todos bastante + sencillos. Con un diálogo debes usar los tipos <code>ResponseId</code> adecuados; con + el <code>FontButton</code> debes usar:</p> + <pre class="codebox">onFontSet:: FontButtonClass self => self -> IO () -> IO (ConnectId self) +</pre> + <p>Después puedes usar la siguiente función para conseguir el nombre de la fuente seleccionada [_$_] + por el usuario:</p> + <pre class="codebox">fontButtonGetFontName :: FontButtonClass self => self -> IO String +</pre> + <p>El nombre de la fuente debe ser algo así como "Courier Italic 10" o + "URW Gothic L Semi-Bold Oblique 16", dependiendo de lo que esté disponible en [_$_] + tu sistema. Como puedes ver en la imagen, el usuario puede seleccionar una familia, + un estilo y un tamaño.</p> + <p> + <img src="Images/GtkChap5-3a.png" alt="Font Select Window" id="imgGtkChap5-3a" /> + </p> + <p>La documentación sobre fonts está en Graphics.UI.Gtk.Pango.Font. Se soportan diversas [_$_] + características avanzadas, pero el usuario normal sólo necesita saber como conseguir una + <code>FontDescription</code> (descripción de fuente) a partir de un nombre de fuente.</p> + <pre class="codebox">fontDescriptionFromString :: String -> IO FontDescription +</pre> + <p>Una vez que tienes la <code>FontDescription</code> (descripción de una fuente), puedes [_$_] + usar:</p> + <pre class="codebox">widgetModifyFont:: WidgetClass self => self -> Maybe FontDescription -> IO () +</pre> + <p>La selección de color es parecida a la selección de fuentes. Tienes tres posibilidades: + </p> + <pre class="codebox">colorSelectionNew :: IO Color Selection +colorSelectionDialogNew: :: String -> IO ColorSelectionDialog +colorButtonNew :: IO Color Button +</pre> + <p>Con un ColorButton usa:</p> + <pre class="codebox">onColorSet :: ColorButtonClass self => self -> IO () -> IO (ConnectId self) +</pre> + <p>y después:</p> + <pre class="codebox">colorButtonGetColor :: ColorButtonClass self => self -> IO Color +</pre> + <p>También hay una función (y un atributo) para conseguir el valor Alpha (opacidad), + si esta característica ha sido activada.</p> + <p>La ventana de selección de color que aparece por defecto tiene esta forma:</p> + <p> + <img src="Images/GtkChap5-3b.png" alt="Color Selection Window" id="imgGtkChap5-3b" /> + </p> + <p>Color es un tipo de datos de tres <code>Ints</code> , en un rango de 0 A 65535, que + especifican los valores de los componentes rojo, verde y azul. Aquí hay funciones que [_$_] + permiten establecer los colores del foreground, background, texto y base de un widget, y + estas funciones usan un parámetro de tipo <code>StateType</code>. Estos son sus valores: [_$_] + <code>StateNormal, StateActive, StatePreLight, StateSelected + y StateInsensitive</code> y dependen de si el widget está activo, el puntero del ratón está + sobre un widget, se selecciona un widget y cosas así. Hay muchos parámetros que gobiernan la [_$_] + presentación de los widgets, por ejemplo, para cambiar el color de una etiqueta de texto + simplemente debes usar <code>StateNormal</code> y el <code>Color</code> que haya sido + seleccionado por el usuario.</p> + <pre class="codebox">widgetModifyFg :: WidgetClass self => self -> StateType -> Color -> IO () +</pre> + <p>Si tienes dudas sobre cual es el <code>StateType</code> que tiene el widget, puedes usar la siguiente [_$_] + función:</p> + <pre class="codebox">widgetGetState :: WidgetClass w => w -> IO StateType +</pre> + <p>Aquí hay un ejemplo de selección de fuente y color.</p> + <p> + <img src="Images/GtkChap5-3c.png" alt="FontButton and ColorButton Example" id="imgGtkChap5-3c" /> + </p> + <p>La ventana automáticamente cambia de tamaño para que quepa la fuente mayor.</p> + <p> + <img src="Images/GtkChap5-3d.png" alt="Window" id="imgGtkChap5-3d" /> + </p> + <pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "Font and Color Selection", +containerBorderWidth := 10 ] + vb <- vBoxNew False 0 + containerAdd window vb + + qtlab <- labelNew (Just "How poor are they that have not +patience!\nWhat wound did ever heal but by degrees?\nThou know'st +we work by wit, and not by witchcraft;\nAnd wit depends on dilatory +time.") + boxPackStart vb qtlab PackGrow 0 + + srclab <- labelNew (Just "From Othello (II, iii, 376-379)") + srcfont <- fontDescriptionFromString "Courier Italic 10" + widgetModifyFont srclab (Just srcfont) + miscSetAlignment srclab 1.0 0.5 + boxPackStart vb srclab PackNatural 10 + + sep <- hSeparatorNew + boxPackStart vb sep PackGrow 10 + [_$_] + fntb <- fontButtonNew + boxPackStart vb fntb PackGrow 0 + + colb <- colorButtonNew + boxPackStart vb colb PackGrow 0 + + onFontSet fntb $ do name <- fontButtonGetFontName fntb + fdesc <- fontDescriptionFromString name + widgetModifyFont qtlab (Just fdesc) + putStrLn name + + onColorSet colb $ do colour <- colorButtonGetColor colb + widgetModifyFg qtlab StateNormal colour + putStrLn (show colour) + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +instance Show Color where + show (Color r g b) = "Red: " ++ (show r) ++ [_$_] + " Green: " ++ (show g) ++ [_$_] + " Blue: " ++ (show b) +</pre> + <div id="footer"> + <span class="nav-previous"> + <a href="es-chap5-2.xhtml">Previo</a> + <br />5.2 Selección de fichero</span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + <br /> </span> + <span class="nav-next"> + <a href="es-chap5-4.xhtml">Siguiente [_$_] + </a> + <br />5.4 Bloc de notas</span> + </div> + </body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap5-4.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap5-4.xhtml 1 - +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="es"><head> + [_$_] + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Bloc de notas</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + <div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"> + <a href="es-chap5-3.html">Previo</a> + </span> + <span class="nav-home"> + <a href="es-index.html">Inicio</a> + </span> + <span class="nav-next"> + <a href="es-chap6-1.html">Siguiente</a> + </span> + </div> + <h2>5.4 Bloc de notas</h2> + <p>El widget [_$_] + <code>Notebook</code> (bloc de notas) es una colección de "páginas" que + se superponen. Cada página es diferente, y sólo una es visible en cada + momento. Las páginas contienen otros widgets que el programador suministra.</p> + <p>Para crear un nuevo widget Notebook:</p> + <pre class="codebox">NotebookNew :: IO Notebook +</pre> + <p>Una vez que el bloc de notas ha sido creado, dispones de funciones y atributos + para ajustarlo a tus necesidades o gustos. Los siguientes atributos determinan la [_$_] + posición de las pestañas (tabs), y si son visibles o no.</p> + <pre class="codebox">notebookTabPos :: NotebookClass self => Attr self PositionType +notebookShowTabs :: NotebookClass self => Attr self Bool +</pre> + <p>PositionType (tipo de posición) tiene los siguientes cosntructores : [_$_] + <code>PosLeft</code> , [_$_] + <code>PosRight</code> , [_$_] + <code>PosTop</code> (por defecto) y [_$_] + <code>PosBottom.</code> </p> + <p>A continuación echaremos un vistazo a la manera de añadir páginas + al notebook. Hay tres modos, append (añadir detrás), prepend (añadir delante) e insert (insertar).</p> + <pre class="codebox">noteBookAppendPage :: (NotebookClass self, WidgetClass child) +=> self +-> child -- El widget que tiene los contenidos de la página +-> String -- la etiqueta de texto +-> IO Int -- el índice (número de página) de la nueva página (empieza en 0) +</pre> + <p>La función [_$_] + <code>notebookPrependPage</code> tiene la misma signatura. + Y, por supuesto, devuelve 0 como valor del índice. La función [_$_] + <code>notebookInsertPage</code> toma el índice (lugar donde quieres insertar + la página) como un parámetro adicional. Se pueden eliminar páginas + con [_$_] + <code>notebookRemovePage.</code> </p> + <p>Un [_$_] + <code>Notebook</code> es un widget contenedor y puedes usar otros contenedores como + hijos, incluyendo cajas horizontales y verticales. Esto te permite crear páginas + bastante complejas, y establecer su distribución con las funciones de empaquetado + habituales.</p> + <p>Las funciones listadas para añadir, pre-añadir e insertar páginas, sólo sirven + con etiquetas de texto. Las tres tienen versiones que permiten que aparezca un menú + emergente (popup), y en los cuales puedes usar cualquier widget como etiqueta.</p> + <pre class="codebox">notebookAppendPageMenu :: +(NotebookClass self, WidgetClass child, WidgetClass tabLabel, WidgetClass menuLabel) +=> self +-> child -- el widget contenido en la página +-> tabLabel -- el widget para usar como etiqueta de la página +-> menuLabel -- el widget para usar como etiqueta del menú emergente +-> IO Int -- el índice (número de página) de la nueva página (empieza en 0) +</pre> + <p> + <code>notebookPrependPageMenu </code> y [_$_] + <code> notebookInsertPageMenu</code> colocarán la página en primer lugar o en + la posición indicada por el índice respectivamente.</p> + <p>Algunos atributos interesantes son: (consulta la docuemntación de la API (en inglés) [_$_] + para verlos todos):</p> + <pre class="codebox">notebookScrollable :: NotebookClass self => Attr self Bool +notebookCurrentPage :: NotebookClass self => Attr self Int +notebookEnablePopup :: NotebookClass self => Attr self Bool +</pre> + <p>Si hay muchas páginas puedes usar [_$_] + <code>notebookScrollable</code> . Usa [_$_] + <code>notebookCurrentPage</code> o la función [_$_] + <code>notebookSetCurrentPage</code> para abrir el notebook en una página diferente + que la primera (valor por defecto). El atributo [_$_] + <code>notebookEnablePopup</code> determina si la pulsación del botón derecho + del ratón en una pestaña mostrará un menú emergente de todas las páginas disponibles, [_$_] + siempre que las funciones de menú hayan sido definidas.</p> + <p>Un widget + <code>Notebook</code> tiene su propia función de manejo de la señal:</p> + <pre class="codebox">onSwitchPage :: NotebookClass nb => nb -> (Int -> IO ()) -> IO (ConnectId nb) +</pre> + <p>La función, que tú debes suministrar, emplea un índice de página devuelto por + <code>onSwitchPage</code> y debe realizar alguna salida.</p> + <p>Los ejemplos muestran un catálogo <code>StockItem</code> de conjuntos de iconos + de maneras diversas.</p> + <p> + <img src="Images/GtkChap5-4a.png" alt="Notebook Example 1" id="imgGtkChap5-4a" /> + </p> + <p>Vimos los Stock items en el capítulo 4.5. Recuerda + que un <code>StockItem</code> se conoce a partir de GTK+ (y Gtk2Hs). + La siguiente función produce una lista de todos los identificadores de Stock Items.</p> + <pre class="codebox">stockListIds :: IO [StockId] +</pre> + <p>Un [_$_] + <code>StockId</code> es una [_$_] + <code>String</code> y en Gtk2Hs tiene la forma: [_$_] + <code>stockCopy</code> , [_$_] + <code>stockDialogError</code> etc. En GTK+ la forma correspondiente + es: gtk-copy, gtk-dialog-error y así sucesivamente. El ejemplo + define una función tabName para convertir los identificadores GTK+ en + la lista de StockId a nombres para las solapas del notebook. La función + <code>myNewPage</code> usa [_$_] + <code>imageNewFromStock</code> para poner el icono en un widget [_$_] + <code>Image</code>, que será después añadido a la página. Devuelve + el índice de la página, pero no lo usa. Para conseguir una lista de todas las + páginas puedes usar <code>sequence</code> en vez de [_$_] + <code>sequence_</code> </p> + <p>Fíjate en que el tamaño del icono, en píxeles debe ser limitado. El + valor por defecto es 4, el valor usado aquí, 6, también está permitido + pero un tamaño de 8 produce un error de ejecución con GHCi.</p> + <pre class="codebox">import Graphics.UI.Gtk +import Data.Char (toUpper) + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Notebook Example 1", windowDefaultWidth := 300, + windowDefaultHeight := 200 ] + [_$_] + ntbk <- notebookNew + containerAdd window ntbk + set ntbk [notebookScrollable := True, notebookTabPos := PosBottom] + + stls <- stockListIds + sequence_ (map (myNewPage ntbk) stls) + + onSwitchPage ntbk (putStrLn . ((++)"Page: ") . show) + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +tabName :: StockId -> String +tabName st = (drop 3) (conv st) where + conv (x:[]) = x:[] + conv (x:y:ys) | x == '-' = (toUpper y):(conv ys) + | otherwise = x: (conv (y:ys)) + +myNewPage :: Notebook -> StockId -> IO Int +myNewPage noteb stk = [_$_] + do img <- imageNewFromStock stk 6 + pagenum <- notebookAppendPage noteb img (tabName stk) + return pagenum [_$_] +</pre> + <p>Otra manera de mostrar el catálogo es poner los iconos en las solapas + del notebook.</p> + <p> + <img src="Images/GtkChap5-4b.png" alt="Notebook Example 2" id="imgGtkChap5-4a" /> + </p> + <p>Para hacer esto necesitamos el estilo de menú para añadir páginas, y también [_$_] + hemos definido un menú de solapas que consta de la primera letra de la cadena + nombre. El resultado es un menú emergente de 98 letras, con desplazamiento. [_$_] + Esto puede ser inhabilitado de un modo sencillo + a través del atributo <code>notebookEnablePopup</code>. El contenido de cada + página es el identificador de icono de Gtk2Hs (mira + Graphics.UI.Gtk.General.StockItems).</p> + <pre class="codebox">import Graphics.UI.Gtk +import Data.Char (toUpper) + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Notebook Example 2", windowDefaultWidth := 300, + windowDefaultHeight := 200 ] + [_$_] + ntbk <- notebookNew + containerAdd window ntbk + set ntbk [notebookScrollable := True, notebookEnablePopup := True, + notebookTabPos := PosRight ] + + stls <- stockListIds + sequence_ (map (myNewPage ntbk) stls) + + onSwitchPage ntbk (putStrLn . ((++)"Page: ") . show) + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +tabName :: StockId -> String +tabName st = (drop 3) (conv st) where + conv (x:[]) = x:[] + conv (x:y:ys) | x == '-' = (toUpper y):(conv ys) + | otherwise = x: (conv (y:ys)) + +myNewPage :: Notebook -> StockId -> IO Int +myNewPage noteb stk = [_$_] + do img <- imageNewFromStock stk 4 + let nmstr = tabName stk + men <- labelNew (Just ((take 1) nmstr)) + cont <- labelNew (Just ("stock" ++ nmstr)) + pagenum <- notebookAppendPageMenu noteb cont img men + return pagenum [_$_] +</pre> + <div id="footer"> + <span class="nav-previous"> + <a href="es-chap5-3.html">Previo</a> + <br />5.3 Seleción de Fuente (tipo de letra)</span> + <span class="nav-home"> + <a href="es-index.html">Inicio</a> + </span> + <span class="nav-next"> + <a href="es-chap6-1.html">Siguiente</a> + <br />6.1 Ventanas con desplazamiento (scroll)</span> + </div> + [_$_] +</body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap6-1.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap6-1.xhtml 1 - +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="es"><head> + [_$_] + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Ventanas con desplazamiento (scroll)</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + <div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"> + <a href="es-chap5-4.xhtml">Previo</a> + </span> + <span class="nav-home"> + <a href="es-index.xhtml">Inicio</a> + </span> + <span class="nav-next"> + <a href="es-chap6-2.xhtml">Siguiente</a> + </span> + </div> + <h2>6.1 Ventanas con desplazamiento (scroll)</h2> + <p>Las ventanas con desplazamiento se usan para crear un área desplazable con otro + widget dentro de él. Puedes insertar cualquier tipo de widget en una ventana desplazable, + y será accesible, sin tener en cuenta su tamaño, mediante el uso de las barras de desplazamiento [_$_] + (scroll bars)</p> + <p>La siguiente función se usa para crear una nueva ventana desplazable.</p> + <pre class="codebox">scrolledWindowNew :: Maybe Adjustment -> Maybe Adjustment -> IO ScrolledWindow +</pre> + <p>El primer argumento es el ajuste de la dirección horizontal, y el segundo el de la dirección vertical. + Casi siempre se establecen a + <code>Nothing</code> (nada) .</p> + <pre class="codebox">scrolledWindowSetPolicy :: ScrolledWindowClass self => +self -> PolicyType -> PolicyType -> IO () +</pre> + <p>Este establece la política a usar con respecto a las barras de desplazamiento verticales y [_$_] + horizontales. El constructor <code>PolicyAlways</code> muestra siempre la barra de desplazamiento, + <code>PolicyNever</code> no la muestra nunca y [_$_] + <code>PolicyAutomatic</code> la muestra sólo si el tamaño de la página es mayor que la ventana. + Por defecto usa [_$_] + <code>PolicyAlways</code>.</p> + <p>A continuación puedes colocar tu objeto en la ventana con desplazamiento usando + <code>containerAdd</code> si el objeto tiene una ventana asociada con él. Si no lo tiene, + necesitarás un <code>Viewport</code> , aunque puedes añadir una automáticamente con:</p> + <pre class="codebox">scrolledWindowAddWithViewport :: (ScrolledWindowClass self, WidgetClass child) +=> self -> child -> IO () +</pre> + <p>Si te olvidas del <code>viewport</code>, GHCi produce un mensaje de [_$_] + error si usas <code>containerAdd</code> y no has debido hacerlo.</p> + <p>En el ejemplo empaquetamos una tabla con 100 botones toggle en + una ventana con desplazamiento. Implementa un programa de [_$_] + 'Yet Another Haskell Tutorial' (y otro tutorial de Haskell) de Hal Daumé III. [_$_] + Este tutorial está disponible en forma gratuita en el web de Haskell. [_$_] + En la página 43 hay un programita que permite adivinar un numero entre 1 y 100, seleccionado + al azar por la máquina, indicando si nuestra selección es menor, mayor o igual. + El número se genera con la función <code>randomRIO</code> del módulo System.Random.</p> + <p>Nuestro ejemplo lo implementa con un interfaz gráfico.</p> + <p><img src="Images/GtkChap6-1.png" alt="Scrolled Window" id="imgGtkChap6-1" /></p> [_$_] + [_$_] + <p>En la ventana principal usamos una caja vertical para empaquetar + una etiqueta (para información del usuario), un separador horizontal, una + ventana con desplazamiento, un separador horizontal y una caja + horizontal que contiene dos botones de stock. + La ventana con desplazamiento se empaqueta con <code>PackGrow</code>, [_$_] + lo que le permite adaptarse a los cambios de tamaño de la ventana principal. + Los botones nuevo (new) y salir (quit) se empaquetan en los extremos + opuestos de la caja horizontal.</p> + <p>Los 100 botones se crean con:</p> + <pre class="codebox"> buttonlist <- sequence (map numButton [1..100]) +</pre> + <p>donde la función [_$_] + <code>numButton</code> se define como:</p> + <pre class="codebox">numButton :: Int -> IO Button +numButton n = do + button <- buttonNewWithLabel (show n) + return button +</pre> + <p>Así, cada botón automáticamente obtiene el número apropiado + como etiqueta.</p> + <p>Dentro de la ventana con desplazamiento creamos una tabla + de 10 por 10 para los 100 botones. Para posicionar los botones + usamos la función <code>cross</code> , que se basa en <code>List monad</code>. [_$_] + Esta función, un modo sencillo de obtener un producto cartesiano + de dos o más listas, también está explicado en el tutorial ya citado.</p> + <pre class="codebox">cross :: [Int] -> [Int] -> [(Int,Int)] +cross row col = do [_$_] + x <- row + y <- col + return (x,y) +</pre> + <p>La función [_$_] + <code>attachButton</code> parte de una tabla, un botón y una + tupla de coordenadas para colocar un botón en la tabla. (Repasa el + capítulo 3.3 para más información sobre empaquetado de tablas.)</p> + <pre class="codebox">attachButton :: Table -> Button -> (Int,Int) -> IO () [_$_] +attachButton ta bu (x,y) = tableAttachDefaults ta bu y (y+1) x (x+1) +</pre> + <p>Ahora, el siguiente segmento de código empaqueta todos los botones en [_$_] + la tabla con <code>buttonlist</code> según se ha descrito.</p> + <pre class="codebox"> let places = cross [0..9] [0..9] + sequence_ (zipWith (attachButton table) buttonlist places) +</pre> + <p>Cada vez que el usuario pulsa el botón play se genera un + número aleatorio, que habrá que ir comparando con la elección [_$_] + del usuario. Pero el manejador de señales de Gtk2Hs <code>onClicked</code> [_$_] + emplea un botón y una función sin parámetros y tiene un valor de tipo + <code>IO ()</code> . Necesitamos algo así como una variable global, + y esta es aportada por el módulo Data.IORef. Ahora podemos usar los siguientes [_$_] + snippets, en diferentes funciones, para inicializar, escribir y leer el + número aleatorio.</p> + <pre class="codebox">snippet 1 -- randstore <- newIORef 50 [_$_] +snippet 2 -- writeIORef rst rand [_$_] +snippet 3 -- rand <- readIORef rst +</pre> + <p>El primero obtiene una variable de tipo <code>IORef Int</code> y la + inicializa al valor 50. La segunda se implementa con la función aleatoria [_$_] + <code>randomButton</code> :</p> + <pre class="codebox">randomButton :: ButtonClass b => Label -> IORef Int -> b -> IO (ConnectId b) +randomButton inf rst b = [_$_] + onClicked b $ do rand <- randomRIO (1::Int, 100) + writeIORef rst rand [_$_] + set inf [labelLabel := "Ready"] + widgetModifyFg inf StateNormal (Color 0 0 65535) +</pre> + <p>y después usa el siguiente snippet, donde <code>info</code> [_$_] + es la etiqueta que permite acceder a la información de usuario. + (Mira el capítulo 5.3 para los colores y como cambiarlos.)</p> + <p>De un modo parecido a la escritura del número aleatorio, la + función <code>actionButton</code> implementa la lectura de [_$_] + <code>randstore.</code> Entonces compara el número obtenido [_$_] + de la etiqueta del botón que ha sido pulsado, y muestra la + información en la etiqueta <code>info</code>. </p> + <p>Finalmente debemos monitorizar los 100 botones para saber cual ha + sido pulsado, si ha habido alguno.</p> + <pre class="codebox"> sequence_ (map (actionButton info randstore) buttonlist) +</pre> + <p>Lo anterior es análogo a las combinaciones de <code>sequence</code> _ y [_$_] + <code>map</code> que hemos usado, pero en este caso exactamente + uno de los 100 manejadores de señal será activado, en el momento en + que el usuario pulse un botón concreto.</p> + <p>A continuación tienes el código completo del ejemplo.</p> + <pre class="codebox">import Graphics.UI.Gtk +import Data.IORef [_$_] +import System.Random (randomRIO) + +main:: IO () +main= do + initGUI + window <- windowNew + set window [ windowTitle := "Guess a Number", [_$_] + windowDefaultWidth := 300, windowDefaultHeight := 250] + mb <- vBoxNew False 0 + containerAdd window mb + + info <- labelNew (Just "Press \"New\" for a random number") + boxPackStart mb info PackNatural 7 + sep1 <- hSeparatorNew + boxPackStart mb sep1 PackNatural 7 + [_$_] + scrwin <- scrolledWindowNew Nothing Nothing + boxPackStart mb scrwin PackGrow 0 + + table <- tableNew 10 10 True + scrolledWindowAddWithViewport scrwin table + + buttonlist <- sequence (map numButton [1..100]) + let places = cross [0..9] [0..9] + sequence_ (zipWith (attachButton table) buttonlist places) + + sep2 <- hSeparatorNew + boxPackStart mb sep2 PackNatural 7 + hb <- hBoxNew False 0 + boxPackStart mb hb PackNatural 0 + play <- buttonNewFromStock stockNew + quit <- buttonNewFromStock stockQuit + boxPackStart hb play PackNatural 0 + boxPackEnd hb quit PackNatural 0 + [_$_] + randstore <- newIORef 50 + randomButton info randstore play + + sequence_ (map (actionButton info randstore) buttonlist) [_$_] + + widgetShowAll window + onClicked quit (widgetDestroy window) + onDestroy window mainQuit + mainGUI + +numButton :: Int -> IO Button +numButton n = do + button <- buttonNewWithLabel (show n) + return button + +cross :: [Int] -> [Int] -> [(Int,Int)] +cross row col = do [_$_] + x <- row + y <- col + return (x,y) + +attachButton :: Table -> Button -> (Int,Int) -> IO () +attachButton ta bu (x... [truncated message content] |
From: Axel S. <A....@ke...> - 2008-01-11 20:04:39
|
Sat Dec 15 09:44:42 PST 2007 hth...@zo... * Tutorial-Port Spanish Translation Chapter 4 (1-7) addfile ./docs/tutorial/Tutorial_Port/es-chap4-1.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap4-1.xhtml 1 - +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Gtk2Hs Tutorial: The Button Widget</title> + <link href="default.css" type="text/css" rel="stylesheet" /> +</head> + +<body> + +<div id="header"> + <h1>Gtk2Hs Tutorial</h1> + <span class="nav-previous"><a href="es-chap3-3.xhtml">Previo</a></span> + <span class="nav-home"><a href="es-index.xhtml">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-2.xhtml">Siguiente</a></span> +</div> + +<h2>4.1 El Widget Button (Botón)</h2> + +<h3>Los botones normales</h3> + +<p> +Ya casi hemos visto todo lo que hay que ver del widget botón. Es muy sencillo. +Sin embargo hay más de una manera de crear un botón. Puedes usar las funciones +<code>buttonNewWithLabel</code> o <code>buttonNewWithMnemonic</code> para crear +un botón con una etiqueta, usar <code>buttonNewFromStock</code> para crear un botón +que contenga una imagen y un texto de un "stock item" o usar <code>buttonNew</code> +para crear un botón vacío.Es cosa tuya colocarle una etiqueta o un pixmap en este nuevo botón. +Para hacer esto, crea una nueva caja y empaqueta los objetos dentro de ella usando [_$_] +la función <code>boxPackStart</code> (o <code>boxPackEnd</code> +para empezar desde el final), que ya conoces, y después usa <code>containerAdd</code> para empaquetar +la caja en el botón. +</p> + +<p> +Las funciones <code>buttonNewWithMnemonic</code> y <code>buttonNewFromStock</code> tienen un +string como primer argumento. Usa el subrayado para marcar un caracter como el "mnemonico", que [_$_] +funcionará como un acelerador vía teclado. Pulsando <strong>Alt</strong> y esa tecla se activará dicho botón, sin +necesidad de pinchar con el ratón. En la segunda función, la cadena es un <code>stockId</code>, un identificador +de una lista de imágenes predefinidas con etiquetas. +</p> + +<p> +Aquí tenemos un ejemplo de uso de <code>buttonNew</code> para crear un botón con una imagen y una etiqueta. +</p> + +<p><img src="Images/GtkChap4-1a.png" alt="Button with image" id="imgGtkChap4-1a" /></p> + +<pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "Pix", + containerBorderWidth := 10] + button <- buttonNew + onClicked button (putStrLn "button clicked") + box <- labelBox "info.xpm" "cool button" + containerAdd button box + containerAdd window button + widgetShowAll window + onDestroy window mainQuit + mainGUI + +labelBox :: FilePath -> String -> IO HBox +labelBox fn txt = do + box <- hBoxNew False 0 + set box [containerBorderWidth := 2] + image <- imageNewFromFile fn + label <- labelNew (Just txt) + boxPackStart box image PackNatural 3 + boxPackStart box label PackNatural 3 + return box +</pre> + +<p> +La función <code>labelBox</code> se puede usar para meter imágenes y etiquetas en [_$_] +cualquier widget que sea simultáneamente un contenedor (container). La imagen procede de [_$_] +un fichero, usando <code>imageNewFromFile</code> y la etiqueta viene de <code>labelNew</code>, +que utiliza un <code>Maybe String</code> como argumento. <code>Nothing</code> +indica que no hay etiqueta. +</p> + +<p> +El widget <code>Button</code> tiene las siguientes señales básicas, que casi se autoexplican (si sabes inglés claro!): +</p> + +<ul> + <li> + <code>onPressed</code> - se emite cuando el ratón es pulsado dentro del widget <code>Button</code> + </li> + + <li> + <code>onReleased</code> - se emite cuando el ratón se deja de pulsar dentro del widget <code>Button</code> + </li> + + <li> + <code>onClicked</code> - se emite cuando el ratón se pulsa y se suelta dentro del widget <code>Button</code> + </li> + + <li> + <code>onEnter</code> - se emite cuando el ratón entra en el widget <code>Button</code> + </li> + + <li> + <code>onLeave</code> - se emite cuando el ratón sale del widget <code>Button</code> + </li> +</ul> + +<p> +Nota: Normalmente el dispositivo señalador es el ratón, por eso lo indico. Para cualquier [_$_] +dispositivo señalador, el funcionamiento sería el mismo, así ratón = dispositivo señalador. +</p> + + +<h3>Botones Toggle (Alternativos)</h3> + +<p> +Los botones Toggle se derivan de los botones normales y son muy parecidos. Su única +diferencia estriba en que siempre alternan entre dos estados. La alternancia se +produce al ser pulsados. [_$_] +</p> + +<p> +Los botones Toggle son la base de de los botones check y radio, por tanto muchas +de las llamadas usadas por los botones toggle son heredadas por los botones check y +radio. +Ya lo recordaremos cuando lleguemos a ellos. +</p> + +<p> +La creación de un boton toggle: +</p> + +<pre class="codebox">toggleButtonNew :: IO ToggleButton + +toggleButtonNewWithLabel :: String -> IO Togglebutton + +toggleButtonNewWithMnemonic :: String -> IO ToggleButton +</pre> + +<p> +Como puedes imaginar, funcionan exactamente igual que con los widget botón. +El primero crea un botón toggle vacío, y los dos últimos, un botón con un widget [_$_] +de tipo etiqueta(label) ya empaquetado con él. La variante "mnemonica" analiza la etiqueta +buscando el caracter prefijado con un "_". +</p> + +<p> +Para conocer el estado del botón toggle (pulsado o no pulsado), incluyendo los [_$_] +botones radio y check, se emplea: +</p> + +<pre class="codebox">toggleButtonGetActive :: ToggleButtonClass self => self -> IO Bool +</pre> + +<p> +Devuelve <var>True</var> si el botón toggle está pulsado y <var>False</var> si no lo está. +</p> + +<p> +Para forzar el estado de un botón toggle, o sus hijos, los botones radio y check, debes emplear: +</p> + +<pre class="codebox">toggleButtonSetActive :: ToggleButtonClass self => self -> Bool -> IO () +</pre> + +<p> +La llamada anterior se puede usar para establecer el estado del botón toggle, y sus +hijos los botones radio y check. Hay que pasarle el botón creado como primer argumento +y <var>True</var> o <var>False</var> como segundo argumento, para especificar el estado an el que [_$_] +queremos dejar el botón. El valor por defecto es "no pulsado" o <var>False</var>. +</p> + +<p> +Fíjate que cuando usas la función <code>toggleButtonSetActive</code>, y se cambia el +estado, origina que se emitan las señales <code>onClicked</code> y +<code>onToggled</code> del botón. +</p> + +<h3>Botones Check</h3> + +<p> +Los botones Check heredan muchas propiedades y funciones de los botones toggle, bero +su apariencia es diferente. Más que ser botones con un texto dentro de ellos, son pequeños +cuadrados con el texto a su derecha. A menudo se usan para marcar las opciones +de una aplicación como activadas o desactivadas. +</p> + +<p> +Las funciones de creación son las mismas que las de los botones normales. +</p> + +<pre class="codebox">checkButtonNew :: IO CheckButton + +checkButtonNewWithLabel :: String -> IO Checkbutton + +checkButtonNewWithMnemonic :: String -> IO CheckButton +</pre> + +<p> +La función <code>checkButtonNewWithLabel</code> crea un botón check con una etiqueta junto a él. +</p> + +<p> +<code>CheckButton</code> es una instancia de <code>ToggleButtonClass</code> y +la señal <code>onToggled</code> se usa cuando un <code>CheckButton</code> se marca +o se desmarca, como en el botón toggle.</p> + +<h3>Botones Radio</h3> + +<p> +Los botones Radio son parecidos a los botones check excepto que están agrupados de modo que sólo uno +puede seleccionarse en cada momento. Esto es útil para los lugares del programa donde se debe seleccionar +una opción de entre varias posibles. Para crear un boton radio utilizo una de estas funciones: +</p> + +<pre class="codebox">radioButtonNew :: IO RadioButton + +radioButtonNewWithLabel :: String -> IO RadioButton + +radioButtonNewWithMnemonic :: String -> IO RadioButton + +radioButtonNewFromWidget :: RadioButton -> IO RadioButton + +radioButtonNewWithLabelFromWidget :: RadioButton -> String -> IO RadioButton + +radioButtonNewWithMnemonicFromWidget :: RadioButton -> String -> IO RadioButton +</pre> + +<p> +Como has visto, las últimas tres funciones tienen un argumento extra. Se usa para +unir los botones nuevos a los ya construidos en un grupo. +</p> + +<p> +Es una buena opción seleccionar el botón que presenta el valor por defecto con: +</p> + +<pre class="codebox">toggleButtonSetActive :: ToggleButtonClass self => self -> Bool -> IO () +</pre> + +<p> +Esta función se describió en los botones toggle, y funciona exactamente del mismo modo. +Una vez que los botones radio se agrupan, sólo uno del grupo puede estar activo en un momento [_$_] +determinado. Si el usuario pulsa en uno de los botones, y después en otro, el primer botón [_$_] +radio emitirá en primer lugar una señal <code>onToggled</code> (para indicar el cambio a inactivo), y +después el segundo emitirá su señal <code>onToggled</code> (para indicar su cambio a activo). +</p> + +<p> +El siguiente ejemplo crea un grupo de botones radio con tres botones, y cuando +el usuario pulsa uno de los botones radio, el desactivado y el activado lo indicarán +a <code>stdout</code>, mediante <code>putStrLn</code> en la función <code>setRadioState</code> [_$_] +definida al final. +</p> + +<p><img src="Images/GtkChap4-1b.png" alt="Radio buttons" id="imgGtkChap4-1b" /></p> + +<pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "Radio Button", containerBorderWidth := 5, + windowDefaultWidth := 200, windowDefaultHeight := 150] + box1 <- vBoxNew False 0 + containerAdd window box1 + box2 <- vBoxNew False 10 + containerSetBorderWidth box2 10 + boxPackStart box1 box2 PackNatural 0 + button1 <- radioButtonNewWithLabel "button 1" + boxPackStart box2 button1 PackNatural 0 + button2 <- radioButtonNewWithLabelFromWidget button1 "button 2" + boxPackStart box2 button2 PackNatural 0 + button3 <- radioButtonNewWithLabelFromWidget button2 "button 3" + boxPackStart box2 button3 PackNatural 0 + toggleButtonSetActive button2 True + onToggled button1 (setRadioState button1) + onToggled button2 (setRadioState button2) + onToggled button3 (setRadioState button3) + sep <- hSeparatorNew + boxPackStart box1 sep PackNatural 0 + box3 <- vBoxNew False 10 + containerSetBorderWidth box3 10 + boxPackStart box1 box3 PackNatural 0 + closeb <- buttonNewWithLabel "close" + boxPackStart box3 closeb PackNatural 0 + onClicked closeb mainQuit + widgetShowAll window + onDestroy window mainQuit + mainGUI + +setRadioState :: RadioButton -> IO () +setRadioState b = do + state <- toggleButtonGetActive b + label <- get b buttonLabel + putStrLn ("State " ++ label ++ " now is " ++ (show state)) +</pre> + +<div id="footer"> + <span class="nav-previous"><a href="es-chap3-3.xhtml">Previo</a><br />3.3 Empaquetado Usando Tablas</span> + <span class="nav-home"><a href="es-index.xhtml">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-2.xhtml">Siguiente</a><br />4.2 Ajustes, escalado y rango</span> +</div> + + +</body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap4-2.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap4-2.xhtml 1 - +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es"><head><!-- +<?xml version="1.0" encoding="UTF-8"?> +--> + + + + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Ajustes, escalado y rango</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + +<div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"><a href="es-chap4-1.html">Previo</a></span> + <span class="nav-home"><a href="es-index.html">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-3.html">Siguiente</a></span> +</div> + +<h2>4.2 Ajustes, escalado y rango</h2> + +<p> +Gtk2Hs tiene varios widgets que pueden ser ajustados visualmente por el usuario +usando el ratón o el teclado, como los widgets rango, descritos en su sección. +También hay algunos widgets que muestran una porción de un área de datos mayor, +como el widget text y el widget viewport. Esta porción también puede ser ajustada [_$_] +por el usuario. +</p> + +<p> +Una aplicación necesita ser capaz de reaccionar a los cambios que hace el usuario +en el rango. Un modo de hacerlo podría ser haciendo que cada widget emitiera +su propio tipo de señal cuando cambiase su ajuste. Pero puede que quisieras enlazar +los ajustes de varios widgets juntos, de modo que al ajustar uno se ajustasen los otros. +El ejemplo más claro de esto es la conexión de un scrollbar (barra de deslizamiento) a un [_$_] +panning viewport (ventana de mostrar imágenes con una subpantalla) o a un área de texto con scroll. +</p> + +<p> +El objeto <code>Adjustment</code> (ajuste) se puede usar para almacenar los parámetros y valores de +configuración de los widgets de rango, como los scrollbars y controles de escalado. +Como <code>Adjustment</code> se deriva de <code>GObject</code> y +<code>Object</code>, los ajustes pueden emitir señales, que pueden ser usadas no sólo para +que tu programa reaccione a las entradas del usuario en los widgets ajustables, sino +también para propagar los valores de ajuste de un modo transparente entre widgets ajustables. +</p> + +<p> +Muchos de los widgets que usan objetos <code>Adjustment</code>, como <code>ScrolledWindow</code>, pueden crear +sus propios objetos <code>Adjustment</code>, pero tu mismo los puedes crear con: +</p> + +<pre class="codebox">adjustmentNew :: Double -- valor - El valor inicial del rango + -> Double -- mínimo - Valor mínimo del rango + -> Double -- máximo - Valor máximo del rango + -> Double -- incrementoPaso - El menor de dos posibles incrementos + -> Double -- incrementoPágina - El mayor de dos posibles incrementos + -> Double -- tamañoPágina - El tamaño del área visible + -> IO Adjustment +</pre> + +<p> +La función de creación necesita un valor para cada información contenida en el objeto: +<code>valor</code> Es el valor inicial y debe estar contenido entre el maximo y el mínimo. +<code>máximo</code> y <code>mínimo</code> fijan el margen del deslizador. Pulsando en las flechas +se incrementa el valor en <code>incrementPaso</code>. Pulsando en el deslizador (slider) avanza un [_$_] +<code>incrementoPágina</code>. El <code>tamañoPágina</code> se necesita para determinar si el final [_$_] +del deslizador se mantiene en el rango. Puedes conseguir y establecer todos los parámetros de un +<code>Adjustment</code> por métodos específicos o usando las funciones generales <code>set</code> y <code>get</code> [_$_] +en los atributos de <code>Adjustment</code>. +</p> + +<pre class="codebox">onValueChanged :: Adjustment -> IO () -> IO (ConnectId Adjustment) +</pre> + +<p> +es la señal emitida cuando el "valor" de un <code>Adjustment</code> cambia, y: +</p> + +<pre class="codebox">onAdjChanged :: Adjustment -> IO () -> IO (ConnectId Adjustment) +</pre> + +<p> +es la señal emitida cuando cambian uno o más de los otros atributos (diferentes de "valor") de un <code>Adjustment</code>. +</p> + +<h3>Widgets de escala y rango</h3> + +<p> +Los widgets de escalado se usan para permitir al usuario la selección visual +y la manipulación del valor dentro de un rango especificado usando un deslizador. [_$_] +Podrías querer usar un widget escalable, por ejemplo, para ajustar el nivel de +ampliación en una previsualización reducida de una imagen, o para controlar el +brillo de un color o para especificar el número de minutos de inactividad antes de [_$_] +que un salvapantallas se active.</p> + +<p> +Las siguientes funciones crean widgets de escalado vertical y horizontal respectivamente: +</p> + +<pre class="codebox">vScaleNew :: Adjustment -> IO VScale + +hScaleNew :: Adjustment -> IO Hscale +</pre> + +<p> +También hay dos constructores, que no utilizan el <code>Adjustment</code>: +</p> + +<pre class="codebox">vScaleNewWithRange :: Double ->. Double -> Double -> IO VScale + +hScaleNewWithRange :: Double ->. Double -> Double -> IO Hscale +</pre> + +<p> +Los parámetros de tipo <code>Double</code> se refieren a los valores máximo, mínimo y el +paso. El incremento del paso (preferiblemente en potencias de 10) es el valor en que se +mueve la escala cuando se usan las teclas de cursor (flechas). +</p> + +<p> +Las escalas horizontal y vertical son instancias de <code>ScaleClass</code> y [_$_] +su comportamiento común está definido en el módulo +<code>Graphics.UI.Gtk.Abstract.Scale</code>. +</p> + +<p> +Los widgets de escalado pueden mostrar su valor actual como un número junto al canal. [_$_] +(El área donde se mueve el deslizador) +El comportamiento por defecto es mostrar el valor, pero puedes modificarlo con la función: +</p> + +<pre class="codebox">scaleSetDrawValue :: ScaleClass self => self -> Bool -> IO () +</pre> + +<p> +El valor mostrado por un widget de escalado se redondea en un punto decimal +por defecto, igual que el ajuste del campo <var>valor</var>. Esto se puede cambiar con: +</p> + +<pre class="codebox">scaleSetDigits :: ScaleClass self => self -> Int -> IO () +</pre> + +<p> +Finalmente, el valor puede ser dibujado en diferentes posiciones relativas al canal: [_$_] +</p> + +<pre class="codebox">scaleSetValuePos :: ScaleClass self => self -> PositionType -> IO () +</pre> + +<p> +La <code>PositionType</code> (tipo de posición) se define como: +</p> + +<pre class="codebox">data PositionType = PosLeft | PosRight | PosTop | PosBottom +</pre> + +<p> +<code>Scale</code> hereda diferentes métodos de su clase base que es: <code>Range</code>. +</p> + +<h4>Estableciendo la política de actualizaciones</h4> + +<p> +La política de actualizaciones de un widget rango define los puntos a los que, durante +la interacción con el usuario, cambiará el campo <var>valor</var> de su +<code>Adjustment</code> y emitirá la señal <code>onRangeValueChanged</code> [_$_] +de su <code>Adjustment</code>. La política de actualizaciones esta definida por el +<code>UpdateType</code>, que tiene tres constructores: +</p> + +<dl> + <dt><code>UpdateContinuous</code> (Actualización continua )</dt> + <dd> + Es el valor por defecto. La señal <code>onRangeValueChanged</code> se emite continuamente, [_$_] + <em>p.ej.</em>, cuando el deslizador se mueve un valor mínimo. + </dd> + + <dt><code>UpdateDiscontinuous</code> (Actualización discontinua)</dt> + <dd> + La señal <code>onRangeValueChanged</code> sólo se emite cuando el deslizador se ha detenido + y el usuario ha levantado el botón del ratón. + </dd> + + <dt><code>UpdateDelayed</code> (Actualización retrasada)</dt> + <dd> + La señal <code>onRangeValueChanged</code> se emite cuando el usuario levanta el botón del + ratón o si el deslizador se para de mover durante un corto periodo de tiempo. + </dd> +</dl> + +<p> +La política de actualizaciones de un widget range se puede establecer por: +</p> + +<pre class="codebox">rangeSetUpdatePolicy :: RangeClass self => self -> UpdateType -> IO () +</pre> + +<h4>Obteniendo y estableciendo los ajustes</h4> + +<p> +La obtención y el ajuste de un widget rango se hace sobre la marcha con: +</p> + +<pre class="codebox">rangeGetAdjustment :: RangeClass self => self -> IO Adjustment + +rangeSetAdjustment :: RangeClass self => self -> Adjustment -> IO () +</pre> + +<p> +<code>rangeSetAdjustment</code> no hace nada si le pasas el objeto de <code>Adjustment</code> que ya está usando, [_$_] +independientemente de que alguno de los valores de sus atributos haya cambiado. [_$_] +Si le pasas un nuevo código de <code>Adjustment</code>, desconectará el antiguo, si existía +(posiblemente detruyéndolo), conectará las señales apropiadas al nuevo, y llamará a la función [_$_] +privada <code>gtk_range_adjustment_changed()</code>, que (o al menos se supone que...) recalculará +el tamaño y/o posición del deslizador y lo dibujará si fuera necesario. +Como se ha mencionado en la sección de ajustes, si quieres volver a usar el mismo <code>Adjustment</code>, [_$_] +cuando modificas sus valores directamente, deberías emitir la señal <code>changed</code> (cambiado) sobre él. +</p> + +<h3>Interacción con teclado y ratón </h3> + +<p> +Todos los widgets de rango de Gtk2Hs reaccionan a las pulsaciones de ratón más [_$_] +o menos de la misma manera. Pulsando del botón 1 del ratón en el canal originará [_$_] +que el ajuste de <code>incrementoPaso</code> se añada o sustraiga de su <var>valor</var>, +y el deslizador se mueva de acuerdo a ello. Pulsando el botón 2 del ratón en el canal +moverá el deslizador al punto en que se pulsó el botón. Pulsando el tercer botón en el [_$_] +canal o en las flechas del scroll causará que el <var>valor</var> del <code>Adjustment</code> [_$_] +cambie en el valor de <code>incrementoPaso</code>. +</p> + +<p class="notebox"> +<strong>Nota:</strong> Esto no funciona en Linux Fedora 6 con la configuración estándar del ratón. +</p> + +<p> +No se puede hacer que las barras de scroll tengan el foco, así que no disponen de atajos de teclado. +Para los otros widgets de rango, (que sólo están activos cuando el widget tiene el foco) <em>no</em> [_$_] +diferencian entre widgets de rango vertical u horizontal. +</p> + +<p> +Todos los widgets de rango se pueden usar con las flechas de izquierda, derecha, arriba y abajo, +así como con las teclas <strong>AvPág</strong> y <strong>RePág</strong>. Las flechas mueven el [_$_] +deslizador arriba y abajo en <code>incrementoPaso</code>, mientras <strong>AvPág</strong> y [_$_] +<strong>RePág</strong> lo mueven en <code>incrementoPágina</code>. <strong>Inicio</strong> y <strong>Fin</strong> [_$_] +lo mueven al principio y al final del canal. +</p> + + +<h3>Ejemplo</h3> + +<p> +Este ejemplo crea una ventana con tres widgets de rango conectados al mismo objeto <code>Adjustment</code>, +y un par de controles para ajustar algunos de los parámetros mencionados antes, de modo +que puedas ver como afecta al modo en que dichos widgets trabajan. +</p> + +<p><img src="Images/GtkChap4-2.png" alt="Range widgets example" id="imgGtkChap4-2" /></p> + +<p> +Las tres escalas se sitúan de modo que la barra vertical está junto a las dos +horizontales, una sobre la otra. Así que necesitamos una caja horizontal para la escala vertical +y una caja vertical junto a ella para las escalas horizontales. Las escalas y las cajas [_$_] +deben empaquetarse con <code>PackGrow</code> de modo que las escalas actualicen su tamaño con el de +la caja principal, que es una caja vertical en la ventana. +</p> + +<p> +Todas las escalas se construyen con el mismo <code>Adjustment</code>, estableciendo el valor inicial en 0.0, [_$_] +el valor mínimo en 0.0, el máximo en 101.0, el incremento del paso en 0.1, el incremento de +página en 1.0 y el tamaño de la página en 1.0. +</p> + +<pre class="codebox"> adj1 <- adjustmentNew 0.0 0.0 101.0 0.1 1.0 1.0 +</pre> + +<p> +El usuario puede controlar cuando se muestran los valores de escalado con un +<code>checkButton</code>. Esto se empaqueta en la caja principal y se establece +para estar activo inicialmente. Un botón check es un botón toggle, así que cuando [_$_] +el usuario lo marca o lo desmarca, se envía la señal <code>onToggled</code>. [_$_] +Esto origina que la función <code>toggleDisplay</code> [_$_] +se evalúe. La función <code>toggleDisplay</code> queda definida así: +</p> + +<pre class="codebox">toggleDisplay :: ScaleClass self => CheckButton -> [self] -> IO () +toggleDisplay b scls = sequence_ (map change scls) where + change sc = do st <- toggleButtonGetActive b + scaleSetDrawValue sc st +</pre> + +<p> +La función tiene un parámetro tipo <code>checkButton</code>, y una lista de instancias +de <code>ScaleClass</code>. Sin embargo, una lista sólo puede contener valores del mismo tipo, +y <code>vScale</code> y <code>hScale</code> son tipos diferentes. Por lo tanto, usamos la función +en listas de escalas horizontales o verticales, pero si la lista contuviera los dos tipos se originaría un [_$_] +error de tipado. +</p> + +<p> +El usuario puede elegir el <code>positionType</code> mediante un widget del que todavía no hemos hablado, [_$_] +un <code>ComboBox</code>. Esto permite una selección de elecciones como se muestra más abajo. El primero en +establecerse como activo se determina por un índice, 0 aquí (el primero). +</p> + +<pre class="codebox">makeOpt1 :: IO ComboBox +makeOpt1 = do + cb <- comboBoxNewText + comboBoxAppendText cb "TOP" + comboBoxAppendText cb "BOTTOM" + comboBoxAppendText cb "LEFT" + comboBoxAppendText cb "RIGHT" + comboBoxSetActive cb 0 + return cb +</pre> + +<p> +Un segundo <code>comboBox</code> permite que el usuario seleccione la política de actualizaciones, [_$_] +alguno de los tres constructores de <code>UpdateType</code>. +</p> + +<pre class="codebox">makeOpt2 :: IO ComboBox +makeOpt2 = do + cb <- comboBoxNewText + comboBoxAppendText cb "Continuous" + comboBoxAppendText cb "Discontinuous" + comboBoxAppendText cb "Delayed" + comboBoxSetActive cb 0 + return cb +</pre> + +<p> +Las cajas combo (Combo box) por si mismas sólo muestran texto. Para seleccionar +la posición, definimos: +</p> + +<pre class="codebox">setScalePos :: ScaleClass self => ComboBox -> self -> IO () +setScalePos cb sc = do + ntxt <- comboBoxGetActiveText cb + let pos = case ntxt of + (Just "TOP") -> PosTop + (Just "BOTTOM") -> PosBottom + (Just "LEFT") -> PosLeft + (Just "RIGHT") -> PosRight + Nothing -> error "setScalePos: no position set" + scaleSetValuePos sc pos + +setUpdatePol :: RangeClass self => ComboBox -> self -> IO () +setUpdatePol cb sc = do + ntxt <- comboBoxGetActiveText cb + let pol = case ntxt of + (Just "Continuous") -> UpdateContinuous + (Just "Discontinuous") -> UpdateDiscontinuous + (Just "Delayed") -> UpdateDelayed + Nothing -> error "setUpdatePol: no policy set" + rangeSetUpdatePolicy sc pol +</pre> + +<p> +Aquí no hemos usado listas para gestionar las escalas verticales y horizontales, así que +accedemos por separado a cada escala horizontal. +</p> + +<p> +El número de precisión mostrado por las tres escalas debe ser manejado con otra escala, +para la que usamos un nuevo objeto <code>Adjustment</code>. La precisión máxima es 5 y cada incremento es 1. +La precisión de la propia escala de control se establece a 1. +</p> + +<pre class="codebox"> adj2 <- adjustmentNew 1.0 0.0 5.0 1.0 1.0 0.0 +</pre> + +<p> +Cuando cambia el <code>Adjustment</code> de control, se emite la señal <code>onValueChanged</code> y se [_$_] +evalúa la función <code>setDigits</code>. +</p> + +<pre class="codebox">setDigits :: ScaleClass self => self -> Adjustment -> IO () +setDigits sc adj = do val <- get adj adjustmentValue + set sc [scaleDigits := (round val)] +</pre> + +<p> +Aquí usamos las funciones generales <code>set</code> y <code>get</code> sobre los +atributos; podríamos haber usado funciones específicas también. fíjate en que el +valor de tipo <code>Double</code> del <var>valor</var> de ajuste, se debe redondear a un valor de +tipo <code>Integral</code>. +</p> + +<p> +Usamos otra escala horizontal para gestionar el tamaño de página de las tres +escalas del ejemplo. Cuando lo ponemos a 0.0, las escalas pueden alcanzar su +máximo inicial de 100.0 y cuando lo ponemos a 100.0 las escalas quedan fijas [_$_] +en su menor valor. Esto implica el ajuste del [_$_] +<code>adjustment</code> por una señal de <code>onValueChanged</code> desde un tercer [_$_] +<code>adjustment</code> mediante este trozo de código: +</p> + +<pre class="codebox"> onValueChanged adj3 $ do val <- adjustmentGetValue adj3 + adjustmentSetPageSize adj1 val +</pre> + +<p> +La función main es: +</p> + +<pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "range controls", + windowDefaultWidth := 250] + mainbox <- vBoxNew False 10 + containerAdd window mainbox + containerSetBorderWidth mainbox 10 + + box1 <- hBoxNew False 0 + boxPackStart mainbox box1 PackGrow 0 + adj1 <- adjustmentNew 0.0 0.0 101.0 0.1 1.0 1.0 + vsc <- vScaleNew adj1 + boxPackStart box1 vsc PackGrow 0 + + box2 <- vBoxNew False 0 + boxPackStart box1 box2 PackGrow 0 + + hsc1 <- hScaleNew adj1 + boxPackStart box2 hsc1 PackGrow 0 + hsc2 <- hScaleNew adj1 + boxPackStart box2 hsc2 PackGrow 0 + + chb <- checkButtonNewWithLabel "Display Value on Scale Widgets" + boxPackStart mainbox chb PackNatural 10 + toggleButtonSetActive chb True + + box3 <- hBoxNew False 10 + boxPackStart mainbox box3 PackNatural 0 + label1 <- labelNew (Just "Scale Value Position:") + boxPackStart box3 label1 PackNatural 0 + opt1 <- makeOpt1 + boxPackStart box3 opt1 PackNatural 0 + + box4 <- hBoxNew False 10 + boxPackStart mainbox box4 PackNatural 0 + label2 <- labelNew (Just "Scale Update Policy:") + boxPackStart box4 label2 PackNatural 0 + opt2 <- makeOpt2 + boxPackStart box4 opt2 PackNatural 0 + + adj2 <- adjustmentNew 1.0 0.0 5.0 1.0 1.0 0.0 + + box5 <- hBoxNew False 0 + containerSetBorderWidth box5 10 + boxPackStart mainbox box5 PackGrow 0 + label3 <- labelNew (Just "Scale Digits:") + boxPackStart box5 label3 PackNatural 10 + dsc <- hScaleNew adj2 + boxPackStart box5 dsc PackGrow 0 + scaleSetDigits dsc 0 + + adj3 <- adjustmentNew 1.0 1.0 101.0 1.0 1.0 0.0 + + box6 <- hBoxNew False 0 + containerSetBorderWidth box6 10 + boxPackStart mainbox box6 PackGrow 0 + label4 <- labelNew (Just "Scrollbar Page Size:") + boxPackStart box6 label4 PackNatural 10 + psc <- hScaleNew adj3 + boxPackStart box6 psc PackGrow 0 + scaleSetDigits psc 0 + + onToggled chb $ do toggleDisplay chb [hsc1,hsc2] + toggleDisplay chb [vsc] + + onChanged opt1 $ do setScalePos opt1 hsc1 + setScalePos opt1 hsc2 + setScalePos opt1 vsc + + onChanged opt2 $ do setUpdatePol opt2 hsc1 + setUpdatePol opt2 hsc2 + setUpdatePol opt2 vsc + + onValueChanged adj2 $ do setDigits hsc1 adj2 + setDigits hsc2 adj2 + setDigits vsc adj2 + + onValueChanged adj3 $ do val <- adjustmentGetValue adj3 + adjustmentSetPageSize adj1 val + + widgetShowAll window + onDestroy window mainQuit + mainGUI +</pre> + +<p> +Las funciones no estándar usadas en el listado ya han sido listadas antes. +</p> + +<div id="footer"> + <span class="nav-previous"><a href="es-chap4-1.html">Previo</a><br />4.1 El widget botón</span> + <span class="nav-home"><a href="es-index.html">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-3.html">Siguiente</a><br />4.3 Etiquetas</span> +</div> + + +</body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap4-3.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap4-3.xhtml 1 - +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="es"><head><!-- +<?xml version="1.0" encoding="UTF-8"?> +--> + + + + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Etiquetas</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + +<div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"><a href="es-chap4-2.html">Previo</a></span> + <span class="nav-home"><a href="es-index.html">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-4.html">Siguiente</a></span> +</div> + +<h2>4.3 Etiquetas</h2> + +<p> +Las etiquetas se usan mucho en Gtk2Hs, y son relativamente sencillas. Las etiquetas +no emiten señales, ya que no tienen una X Window asociada. Si necesitas capturar +una señal o apilarlas con otros widgets, debes colocarla dentro de un widget <code>EventBox</code> (Caja de eventos), +Los <code>EventBox</code> te permiten capturar señales de widgets que no tienen su +propia ventana o botón. +</p> + +<p> +Para crear una nueva etiqueta, puedes usar: +</p> + +<pre class="codebox">labelNew :: Maybe String -> IO Label + +labelNewWithMnemonic :: String -> IO Label +</pre> + +<p> +Con la segunda función, si algún caracter de la cadena está precedido de un +guión bajo (o subrayado), se subraya al representarlo. Si necesitas un carácter [_$_] +guión bajo en una etiqueta, debes usar "__" (dos subrayados). El primer caracter subrayado +que aparece representa un atajo de teclado que denominamos mnemónico. Cuando se pulsa esa +tecla, el widget disponible que contiene esa etiqueta (un botón, por ejemplo) se activa. +El widget al que queremos asociar un nmemónico se puede establecer con +<code>labelSetMnemonicWidget</code>. +</p> + +<p> +Para cambiar el texto de la etiqueta después de haber sido creada, o para +conseguir el texto de la misma, puedes usar las funciones: +</p> + +<pre class="codebox">labelSetText :: LabelClass self => self -> String -> IO () + +labelGetLabel :: LabelClass self => self -> IO String +</pre> + +<p> +o, por supuesto, las funciones genéricas <code>set</code> o <code>get</code>. El [_$_] +espacio necesario para la nueva cadena (string) sería ajustado automáticamente si +fuera preciso. Se pueden producir etiquetas multilínea, colocando saltos de línea en +la cadena de la etiqueta. La justificación del texto en las etiquetas multilínea se realiza [_$_] +con la función: +</p> + +<pre class="codebox">labelSetJustify :: LabelClass self => self -> Justification -> IO () +</pre> + +<p> +donde el tipo <code>Justification</code> puede usar alguno de estos cuatro constructores: +</p> + +<ul> + <li><code>JustifyLeft</code> Izquierda</li> + <li><code>JustifyRight</code> Derecha</li> + <li><code>JustifyCenter</code> Centrado</li> + <li><code>JustifyFill</code> Ambos</li> +</ul> + +<p> +El widget etiqueta es también capaz de fijar los saltos de línea en el texto automáticamente. +Esto se puede activar usando: +</p> + +<pre class="codebox">labelSetLineWrap :: LabelClass self => self -> Bool -> IO () +</pre> + +<p> +Si quieres que la etiqueta esté subrayada, puedes establecer un patrón para la etiqueta: +</p> + +<pre class="codebox">labelSetPattern :: LabelClass self => self -> [Int] -> IO () +</pre> + +<p> +La lista de <code>Int</code>s (enteros) marca las partes del texto de la etiqueta que se subrayarán +alternando con los caracteres que no se subrayarán. Por ejemplo, <var>[3, 1, 3]</var> significa +que se subrayarán los tres primeros caracteres, el siguiente, no y los tres siguientes, sí. +</p> + +<p> +Puedes hacer, también, que se pueda seleccionar el texto de la etiqueta, de modo +que el usuario pueda copiarlo y pegarlo, además de usar algunas opciones de formateo. +</p> + +<p> +Abajo hay un ejemplo que ilustra algunas de estas funciones. Usa el widget <code>Frame</code> [_$_] +para demostrar mejor los estilos de la etiqueta. Un <code>Frame</code> no es más que un ornamento, [_$_] +igual que un <code>HSeparator</code> y un <code>VSeparator</code> pero en este caso rodea al widget y +es una instancia de <code>Container</code>. Por tanto, el widget que encuadra debe ser añadido +con <code>containerAdd</code>. Un <code>Frame</code> puede tener una etiqueta para transmitir [_$_] +información sobre su contenido. +</p> + +<p><img src="Images/GtkChap4-3.png" alt="Label examples" id="imgGtkChap4-3" /></p> + +<p> +Como todas las etiquetas del ejemplo tienen un <code>Frame</code>, se define +una función <code>myLabelWithFrameNew</code>, que devuelve una tupla. Gtk2Hs es 100% Haskell, [_$_] +por lo que puedes usar todos los tipos de datos y característas de Haskell. +Las justificaciones son obvias pero sólo se refieren a las líneas de dentro de la etiqueta. [_$_] +Así que, para justificar a la derecha <var>label2</var>, necesitas <code>miscSetAlignment</code> tal y +como se muestra más abajo. Los últimos dos widgets en la caja horizontal de la izquierda se [_$_] +empaquetan con <code>boxPackEnd</code> en vez del usual <code>boxPackStart</code>. La [_$_] +etiqueta botón demuestra el uso de un mnemónico como atajo. Pulsar <strong>Alt-C</strong> [_$_] +en el teclado provoca el mismo efecto que pulsar el botón con el ratón. +</p> + +<p class="notebox"> +<strong>Nota:</strong> Cuando se ha testeado en Fedora 6, pulsar <strong>Enter</strong> +o la barra espaciadora tiene el mismo efecto. Fíjate además en el efecto del carácter [_$_] +"y" en la colocación del subrayado. +</p> + +<pre class="codebox">import Graphics.UI.Gtk + +main:: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "Labels", containerBorderWidth := 10] + mainbox <- vBoxNew False 10 + containerAdd window mainbox + hbox <- hBoxNew True 5 + boxPackStart mainbox hbox PackNatural 0 + vbox1 <- vBoxNew False 10 + vbox2 <- vBoxNew False 0 + boxPackStart hbox vbox1 PackNatural 0 + boxPackStart hbox vbox2 PackNatural 0 + + (label1,frame1) <- myLabelWithFrameNew + boxPackStart vbox1 frame1 PackNatural 0 + labelSetText label1 "Penny Harter" + + (label2,frame2) <- myLabelWithFrameNew + boxPackStart vbox1 frame2 PackNatural 0 + labelSetText label2 "broken bowl\nthe pieces\nstill rocking" + miscSetAlignment label2 0.0 0.0 + hsep1 <- hSeparatorNew + boxPackStart vbox1 hsep1 PackNatural 10 + + (label3,frame3) <- myLabelWithFrameNew + boxPackStart vbox1 frame3 PackNatural 0 + labelSetText label3 "Gary Snyder" + + (label4,frame4) <- myLabelWithFrameNew + boxPackStart vbox1 frame4 PackNatural 0 + labelSetText label4 "After weeks of watching the roof leak\nI fixed it tonight\nby moving a single board" + labelSetJustify label4 JustifyCenter + + (label5,frame5) <- myLabelWithFrameNew + boxPackStart vbox2 frame5 PackNatural 0 + labelSetText label5 "Kobayashi Issa" + + (label7,frame7) <- myLabelWithFrameNew + boxPackEnd vbox2 frame7 PackNatural 0 + labelSetText label7 "only one guy and\nonly one fly trying to\nmake the guest room do" + labelSetJustify label7 JustifyRight + + (label6,frame6) <- myLabelWithFrameNew + boxPackEnd vbox2 frame6 PackNatural 10 + labelSetText label6 "One Guy" + frameSetLabel frame6 "Title:" + labelSetPattern label6 [3, 1, 3] + + button <- buttonNew + boxPackEnd mainbox button PackNatural 20 + buttonlabel <- labelNewWithMnemonic "Haiku _Clicked" + containerAdd button buttonlabel + + widgetShowAll window + onClicked button (putStrLn "button clicked...") + onDestroy window mainQuit + mainGUI + + +myLabelWithFrameNew :: IO (Label,Frame) +myLabelWithFrameNew = do + label <- labelNew Nothing + frame <- frameNew + containerAdd frame label + frameSetShadowType frame ShadowOut + return (label, frame) + + +-- Haikus quoted from X.J. Kennedy, Dana Gioia, Introduction to Poetry, Longman, 1997 +</pre> + +<div id="footer"> + <span class="nav-previous"><a href="es-chap4-2.html">Previo</a><br />4.2 Ajustes, escalado y rango</span> + <span class="nav-home"><a href="es-index.html">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-4.html">Siguiente</a><br />4.4 Flechas y Tooltips</span> +</div> + + +</body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap4-4.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap4-4.xhtml 1 - +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es"><head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2Hs: Flechas y Tooltips</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + +<div id="header"> + <h1>Tutorial de Gtk2Hs</h1> + <span class="nav-previous"><a href="es-chap4-3.xhtml">Previo</a></span> + <span class="nav-home"><a href="es-index.xhtml">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-5.xhtml">Siguiente</a></span> +</div> + +<h2>4.4 Flechas y Tooltips</h2> + +<p> +El widget <code>Arrow</code> (flecha) dibuja una cabeza de flecha, apuntando en una dirección y con un estilo [_$_] +seleccionable. Igual que el widget etiqueta, no emite señales. +</p> + +<p> +Sólo hay dos funciones para manipular un widget <code>Arrow</code>: +</p> + +<pre class="codebox">arrowNew :: ArrowType -> ShadowType -> IO Arrow + +arrowSet :: ArrowClass self => self -> ArrowType -> ShadowType -> IO () +</pre> + +<p> +El <code>ArrowType</code> tiene cinco constructores: +</p> + +<ul> + <li><code>ArrowUp</code> Arriba</li> + <li><code>ArrowDown</code> Abajo</li> + <li><code>ArrowLeft</code> Izquierda</li> + <li><code>ArrowRight</code> Derecha</li> + <li><code>ArrowNone</code> Ninguno</li> +</ul> + +<p> +El <code>ShadowType</code> (tipo de sombra) también tiene cinco constructores: +</p> + +<ul> + <li><code>ShadowIn</code> Dentro</li> + <li><code>ShadowOut</code> Fuera</li> + <li><code>ShadowEtchedIn</code> Grabado dentro</li> + <li><code>ShadowEtchedOut</code> Grabado fuera</li> + <li><code>ShadowNone</code> Sin sombra</li> +</ul> + +<p> +Los Tooltips son esas pequeñas frases que surgen cuando dejas el puntero sobre +un botón u otro widget durante unos segundos. +</p> + +<p> +Los widgets que no reciben eventos (los que no tienen su propia ventana) no funcionan +con los tooltips. +</p> + +<p> +Esta primera llamada creará un tooltip nuevo. Sólo necesitas llamarla una vez para crear +un conjunto de tooltips. +</p> + +<pre class="codebox">tooltipsNew :: IO Tooltips +</pre> + +<p> +Después, para cada widget, usa: +</p> + +<pre class="codebox">tooltipsSetTip :: (TooltipsClass self, WidgetClass widget) + => self -> widget -> String -> String -> IO () +</pre> + +<p> +El primer argumento es el tooltip que ya has creado, seguido por el widget +para el que quieres el tooltip y el texto que quieres que aparezca. El +último argumento es una cadena de texto que puede usarse como su identificador. +</p> + +<p> +Puedes activar o desactivar los mensajes asociados a un <code>Tooltips</code> mediante: +</p> + +<pre class="codebox">tooltipsEnable :: TooltipsClass self => self -> IO () +tooltipsDisable :: TooltipsClass self => self -> IO () +</pre> + +<p> +Aquí tienes un ejemplo que ilustra el uso de flechas y tooltips. +</p> + +<p><img src="Images/GtkChap4-4.png" alt="Arrow and tooltip example" id="imgGtkChap4-4" /></p> + +<p> +La ventana superior ha sido cambiada de tamaño, para mostrar como el empaquetado de +una tabla preserva el espacio de los botones con sus flechas. +</p> + +<p class="notebox"> +<strong>Nota:</strong> Los tooltips no funcionan con GHCi (en mi máquina) pero +sí lo hacen cuando se compila. Por supuesto, no los puedes ver en la imagen. +</p> + +<pre class="codebox">import Graphics.UI.Gtk + +main :: IO () +main = do + initGUI + window <- windowNew + set window [windowTitle := "Arrow Tips", + windowDefaultWidth := 200, + windowDefaultHeight := 200, containerBorderWidth := 20] + + table <- tableNew 5 5 True + containerAdd window table + + button1 <- buttonNew + button2 <- buttonNew + button3 <- buttonNew + button4 <- buttonNew + + tableAttachDefaults table button1 0 1 2 3 + tableAttachDefaults table button2 2 3 0 1 + tableAttachDefaults table button3 4 5 2 3 + tableAttachDefaults table button4 2 3 4 5 + + tlt <- tooltipsNew + + arrow1 <- arrowNew ArrowLeft ShadowEtchedIn + containerAdd button1 arrow1 + tooltipsSetTip tlt button1 "West" "T1" + + arrow2 <- arrowNew ArrowUp ShadowEtchedOut + containerAdd button2 arrow2 + tooltipsSetTip tlt button2 "North" "T2" + + arrow3 <- arrowNew ArrowRight ShadowEtchedIn + containerAdd button3 arrow3 + tooltipsSetTip tlt button3 "East" "T3" + + arrow4 <- arrowNew ArrowDown ShadowEtchedOut + containerAdd button4 arrow4 + tooltipsSetTip tlt button4 "South" "T4" + + tooltipsEnable tlt + widgetShowAll window + onDestroy window mainQuit + mainGUI +</pre> + +<div id="footer"> + <span class="nav-previous"><a href="es-chap4-3.xhtml">Previo</a><br />4.3 Etiquetas</span> + <span class="nav-home"><a href="es-index.xhtml">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-5.xhtml">Siguiente</a><br />4.5 Dialogos, Stock Items y barras de Progreso</span> +</div> + + +</body></html> addfile ./docs/tutorial/Tutorial_Port/es-chap4-5.xhtml hunk ./docs/tutorial/Tutorial_Port/es-chap4-5.xhtml 1 - +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="es"><head> + + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Tutorial de Gtk2hs: Diálogos, Stock Items y barras de Progreso</title> + [_$_] + <link href="default.css" type="text/css" rel="stylesheet" /></head><body> + +<div id="header"> + <h1>Tutorial de Gtk2hs</h1> + <span class="nav-previous"><a href="es-chap4-4.xhtml">Previo</a></span> + <span class="nav-home"><a href="es-index.xhtml">Inicio</a></span> + <span class="nav-next"><a href="es-chap4-6.xhtml">Siguiente</a></span> +</div> + +<h2>4.5 Diálogos, Stock Items y barras de Progreso</h2> + +<p> +Un diálogo es un ejemplo de widget compuesto. Consta de una ventana, una parte +superior que es una caja vertical, y un área de acción que es una caja horizontal que +suele constar de uno o varios botones. +Normalmente ambas partes están separadas por un separador horizontal. +</p> + +<p> +El widget <code>Dialog</code> puede usarse para mensajes pop-up (surgen de la aplicación) al usuario, u [_$_] +otras tareas similares. Las funciones básicas necesarias son: +</p> + +<pre class="codebox">dialogNew :: IO Dialog + +dialogRun :: DialogClass self => self -> IO ResponseID +</pre> + +<p> +Puedes añadir botones al area de acción con: +</p> + +<pre class="codebox">dialogAddButton :: DialogClass self => self -> String -> ResponseId -> IO Button +</pre> + +<p> +Cualquier widget puede ser añadido de un modo semejante con <code>dialogAddActionWidget</code>. +</p> + +<p> +El <code>String</code> en <code>dialogAddButton</code> puede ser el texto del botón, pero como los +diálogos se suelen usar en situaciones estándar, un <code>StockItem</code> suele ser más apropiado. +</p> + +<p> +Los <code>StockItem</code>s son recursos conocidos en Gtk2Hs, como los <code>IconSet</code>s estándar. [_$_] +Puedes definir los tuyos, pero hay muchos predefinidos en el módulo <code>Graphics.UI.Gtk.General.StockItems</code>. +Tienen un identificador, <code>StockId</code>, que es un tipo sinónimo de <code>String</code>. [_$_] +Con este identificador, un widget (normalemente un botón) con el texto y el icono apropiados se +selecciona automáticamente. +</p> + +<p> +Si usas un <code>StockId</code> al añadir un botón al diálogo, puedes usar un constructor <code>ResponseId</code> [_$_] +predefinido con los botones. +(<code>ResponseId</code> no es un <code>String</code>.) Las respuestas pueden construirse con <code>ResponseUser Int</code>. +</p> + +<p> +Siempre que se pulsa un botón de diálogo, su respuesta se pasa a la aplicación llamante +a través de <code>dialogRun</code>. Según la documentación de la API de Gtk2Hs, <code>dialogRun</code> [_$_] +se bloquea en un bucle recursivo hasta que al diálogo o bien emite la señal de respuesta, o es destruido. +El modo por defecto es modal, lo que indica que el usuario no puede acceder a ninguna otra +ventana (de esta aplicación) mientras <code>dialogRun</code> esté esperando una respuesta. +</p> + +<p> +Las barras de progreso se emplean para mostrar el estado de una operación en curso. +</p> + +<pre class="codebox">progressBarNew :: IO ProgressBar +</pre> + +<p> +A pesar de que sólo hay un tipo, hay dos modos diferentes de usar una barra de [_$_] +progreso. Si se conoce la cantidad de tarea realizada, la fracción (entre 0.0 y 1.0 incluido) [_$_] +se puede establecer con: +</p> + +<pre class="codebox">progressBarSetFraction :: ProgressBarClass self => self -> Double -> IO () +</pre> + +<p> +Esto origina que la barra de progreso se "llene" con la cantidad indicada (entre +0.0 y 1.0). Para marcar el progreso, esta función se debe llamar cada cierto tiempo durante la operación. +</p> + +<p> +Si no se conoce la parte de la operación completada, la barra puede moverse de atrás [_$_] +hacia adelante con: +</p> + +<pre class="codebox">progressBarPulse :: ProgressBarClass self => self -> IO () +</pre> + +<p> +También esta función debe ser llamada repetidamente, para mostrar que la actividad +sigue en marcha. Hay otras muchas funciones para controlar la presentación de +una barra de progreso, como la orientación, texto adicional, etc.; Son muy sencillas. +</p> + +<p> +La aplicación, sin embargo, no es trivial debido a que las barras de progreso se +aplican normalmente con temporizadores u otras funciones para dar la ilusión de multitarea. +Con Haskell concurrente puedes usar hilos(threads) y comunicación entre hilos. +</p> + +<p> +En el siguiente ejemplo simulamos una actividad usando <code>timeoutAdd</code>, [_$_] +que ejecuta una función repetidamente con el intervalo especificado en milisegundos. +La función se pasa a <code>timeoutAdd</code> y debe devolver un valor del tipo <code>IO Bool</code>. [_$_] +Cuando el valor es true, el temporizador se vuelve a activar, cuando es falso, se para. +La prioridad de <code>timeoutAdd</code> es <code>priorityDefault</code> de tipo <code>Priority</code>. +</p> + +<pre class="codebox">timeoutAdd :: IO Bool -> Int -> IO HandlerId +</pre> + +<p> +En el ejemplo, definimos una función <code>showPulse</code>, que causa que la barra +de progreso que compruebe y que siempre devuelva <code>IO True</code>. El paso, +la cantidad que se moverá el indicador por la barra, se establece a 1.0 con +<code>progressBarSetPulseStep</code>. +</p> + +<p><img src="Images/GtkChap4-5.png" alt="Progress bar pulsing" id="imgGtkChap4-5" /></p> + +<p> +El ejemplo es un poco atípico en el uso del diálogo, ya que lo usamos para +mostrar el progreso tras la pulsación del botón "aplicar". Para cerrar la aplicación, [_$_] +el diálogo debe ser destruido, destruyendo la ventana. Los botones de cerrar +y cancelar no funcionan después de que "aplicar" haya sido seleccionada. +Si han sido seleccionados antes de "aplicar", la aplicación se cierra. Esto se realiza +comprobando la respuesta de <code>dialogRun</code>. +</p> + +<p> +Si el widget de diálogo se destruye, se llama a <code>mainQuit</code>. Como mencioné +arriba, un <code>Dialog</code> consta de una ventana y dos cajas. Se debe acceder a las cajas [_$_] +a través de funciones especiales, y la barra de progreso se empaqueta en la parte superior con + <code>dialogGetUpper</code>. Los botones en un diálogo son visibles por defecto, pero los widgets + de la parte superior, no. Un <code>Dialog</code> es una instancia de la <code>WindowClass</code... [truncated message content] |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:20
|
Thu Jan 3 13:01:49 PST 2008 A....@ke... * Do not show this internal module in the docs. hunk ./gtk/Graphics/UI/Gtk/ModelView/Sequence.hs.pp 1 +-- #hide |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:11
|
Thu Jan 3 10:55:45 PST 2008 A....@ke... * Add some bogus function that can be used to implement the sortable interface in our CustomStore. hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 14 +static void gtk2hs_store_tree_sortable_init (GtkTreeSortableIface *iface); hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 51 -/* The TreeSortable interface is currently not implemented and may never be. -static gbooelan gtk2hs_store_get_sort_column_id (GtkTreeSortable *sortable, - gint sort_column_id, +/* The TreeSortable interface is currently not implemented and may never be. */ +static gboolean gtk2hs_store_get_sort_column_id (GtkTreeSortable *sortable, + gint *sort_column_id, hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 68 -*/ + + hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 123 -/* The TreeSortable interface is currently not implemented. +/* The TreeSortable interface is currently not implemented. */ hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 130 -*/ + hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 149 - g_type_add_interface_static (gtk2hs_store_type, - GTK_TYPE_TREE_MODEL, - &tree_model_info); - [_$_] -/* The TreeSortable interface is currently not implemented. - g_type_add_interface_static (gtk2hs_store_type, + g_type_add_interface_static (gtk2hs_store_type, GTK_TYPE_TREE_MODEL, + &tree_model_info); + [_$_] + /* The TreeSortable interface is currently not implemented. Uncomment to + add it. */ +/* g_type_add_interface_static (gtk2hs_store_type, hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 157 -*/ - [_$_] +*/ [_$_] hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 226 -/* The TreeSortable interface is currently not implemented. +/* The TreeSortable interface is currently not implemented. */ hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 228 -gtk2hs_store_tree_sortable_init (GtkTreeModelIface *iface) +gtk2hs_store_tree_sortable_init (GtkTreeSortableIface *iface) hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 237 -*/ hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 627 +static gboolean +gtk2hs_store_get_sort_column_id (GtkTreeSortable *sortable, + gint *sort_column_id, + GtkSortType *order) +{ + WHEN_DEBUG(g_debug("calling gtk2hs_store_get_sort_column_id\t\t(%p)\n", sortable)); + return 0; +} + [_$_] +static void +gtk2hs_store_set_sort_column_id (GtkTreeSortable *sortable, + gint sort_column_id, + GtkSortType order) +{ + WHEN_DEBUG(g_debug("calling gtk2hs_store_set_sort_column_id\t\t(%p)\n", sortable)); + return; +} + +static void +gtk2hs_store_set_sort_func (GtkTreeSortable *sortable, + gint sort_column_id, + GtkTreeIterCompareFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + WHEN_DEBUG(g_debug("calling gtk2hs_store_set_sort_func\t\t(%p)\n", sortable)); + return; [_$_] +} + +static void +gtk2hs_store_set_default_sort_func (GtkTreeSortable *sortable, + GtkTreeIterCompareFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + WHEN_DEBUG(g_debug("calling gtk2hs_store_set_default_sort_func\t\t(%p)\n", sortable)); + return; +} + +static gboolean +gtk2hs_store_has_default_sort_func (GtkTreeSortable *sortable) +{ + WHEN_DEBUG(g_debug("calling gtk2hs_store_has_default_sort_func\t\t(%p)\n", sortable)); + return 0; +} + hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 780 + g_return_val_if_fail(GTK2HS_IS_STORE(store), NULL); hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 786 + g_return_val_if_fail(GTK2HS_IS_STORE(store), NULL); hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 793 + g_return_val_if_fail(GTK2HS_IS_STORE(store), 0); hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 800 + g_return_if_fail(GTK2HS_IS_STORE(store)); hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.h 6 +#include <gtk/gtktreesortable.h> |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:11
|
Thu Jan 3 10:50:21 PST 2008 A....@ke... * Allow a more general function to set CellRenderer attributes. The function cellLayoutSetAttributes was rather specific in that it only allowed setting attributes of the given CellRenderer from the given model. Allow a more general variant which is necessary when using proxy models like TreeModelSort or TreeModelFilter. hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 61 + cellLayoutSetAttributeFunc, hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 145 --- | Insert a 'CellRenderer' @cell@ into the layout and specify how a --- row of the @store@ defines the attributes of this renderer. +-- | Specify how a row of the @model@ defines the +-- attributes of the 'CellRenderer' @cell@. This is a convenience wrapper +-- around 'cellLayoutSetAttributeFunc' which sets the cells of the @cell@ with +-- the data retrieved from the model. hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 159 -cellLayoutSetAttributes self cell model attributes = do +cellLayoutSetAttributes self cell model attributes = [_$_] + cellLayoutSetAttributeFunc self cell model $ \iter -> do + row <- treeModelGetRow model iter + set cell (attributes row) + +-- | Install a function that looks up a row in the model and sets the +-- attributes of the 'CellRenderer' @cell@ using the row's content. +-- +cellLayoutSetAttributeFunc :: (CellLayoutClass self, + CellRendererClass cell, + TreeModelClass model) + => self + -> cell -- ^ @cell@ - A 'CellRenderer'. + -> model -- ^ @model@ - A model from which to draw data. + -> (TreeIter -> IO ()) -- ^ Function to set attributes on the cell renderer. + -> IO () +cellLayoutSetAttributeFunc self cell model func = do hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 182 - error ("cellLayoutSetAttributes: attempt to set attributes of "++ + error ("cellLayoutSetAttributeFunc: attempt to set attributes of "++ hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 184 - else do - row <- treeModelGetRow model iter - set cell (attributes row) + else func iter |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:11
|
Thu Jan 3 11:24:29 PST 2008 A....@ke... * Add a demo on the TreeModelSort proxy. hunk ./demo/treeList/Makefile 2 -PROGS = listdemo treedemo listtest treetest dirlist -SOURCES = ListDemo.hs TreeDemo.hs ListTest.hs TreeTest.hs DirList.hs +PROGS = listdemo treedemo listtest treetest dirlist treesort +SOURCES = ListDemo.hs TreeDemo.hs ListTest.hs TreeTest.hs DirList.hs TreeSort.hs hunk ./demo/treeList/Makefile 21 + +treesort : TreeSort.hs + $(HC_RULE) addfile ./demo/treeList/TreeSort.hs hunk ./demo/treeList/TreeSort.hs 1 +import Graphics.UI.Gtk +import Graphics.UI.Gtk.ModelView as New +import Data.Tree + +main = do + initGUI + win <- windowNew + -- Create a tree model with some unsorted data. + rawmodel <- New.treeStoreNew [_$_] + [Node ("zoo",8) [], Node ("foo",5) [], + Node ("bar",20) [], Node ("baz",2) []] + + -- Create a sorting proxy model, that is, a model that permutates the + -- rows of a different model such that they appear to be sorted. + model <- New.treeModelSortNewWithModel rawmodel + [_$_] + -- Define two sorting functions, one being the default sorting function and + -- the other one being the sorting function for the 'SortColumnId' 2. + -- 'SortColumnId's are arbitrary positive numbers, i.e., we could have chosen + -- any other unique number. + New.treeSortableSetDefaultSortFunc model $ \iter1 iter2 -> do + (t1,_) <- New.treeModelGetRow rawmodel iter1 + (t2,_) <- New.treeModelGetRow rawmodel iter2 + return (compare t1 t2) + New.treeSortableSetSortFunc model 2 $ \iter1 iter2 -> do + (_,n1) <- New.treeModelGetRow rawmodel iter1 + (_,n2) <- New.treeModelGetRow rawmodel iter2 + return (compare n1 n2) + + -- Create the view. + view <- New.treeViewNewWithModel model + + -- Create and insert two columns, one with the heading Name, one with the + -- heading Number. Associate the 'SortColumnId' 2 with the latter column such + -- that clicking on the Number header will sort the rows by the numbers. + col <- New.treeViewColumnNew + New.treeViewColumnSetTitle col "Name" + rend <- New.cellRendererTextNew + New.cellLayoutPackStart col rend True + New.cellLayoutSetAttributeFunc col rend model $ \iter -> do + cIter <- New.treeModelSortConvertIterToChildIter model iter + (n,_) <- New.treeModelGetRow rawmodel cIter + set rend [New.cellText := n] + New.treeViewAppendColumn view col + + col' <- New.treeViewColumnNew + New.treeViewColumnSetTitle col' "Number" + rend <- New.cellRendererTextNew + New.cellLayoutPackStart col' rend True + New.cellLayoutSetAttributeFunc col' rend model $ \iter -> do + cIter <- New.treeModelSortConvertIterToChildIter model iter + (_,c) <- New.treeModelGetRow rawmodel cIter + set rend [New.cellText := show c] + New.treeViewAppendColumn view col' + New.treeViewColumnSetSortColumnId col' 2 + + -- Create a button that shows information on the current state of the sorting + -- settings. + button <- buttonNewWithLabel "Dump Info" + button `onClicked` do + sId <- New.treeViewColumnGetSortColumnId col + putStrLn ("tvc1 sort id is "++show sId) + sId <- New.treeViewColumnGetSortColumnId col' + putStrLn ("tvc2 sort id is "++show sId) + sId <- New.treeSortableGetSortColumnId model + putStrLn ("sort id is "++show sId) + -- Show all entries of the proxy model + let recurse Nothing = return () + recurse (Just iter) = do + cIter <- New.treeModelSortConvertIterToChildIter model iter + row <- New.treeModelGetRow rawmodel cIter + putStrLn ("iter "++show cIter++": "++show row) + mIter <- New.treeModelIterNext model iter + recurse mIter + mIter <- New.treeModelGetIterFirst model + recurse mIter + + -- Put it all together. [_$_] + vBox <- vBoxNew False 3 + boxPackStartDefaults vBox view + boxPackEnd vBox button PackNatural 0 + containerAdd win vBox + widgetShowAll win + win `onDestroy` mainQuit + mainGUI |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:11
|
Thu Jan 3 10:56:41 PST 2008 A....@ke... * Update the TreeModelSort proxy to work with the new Haskell-land stores. This patch makes the TreeModelSort proxy fully functional. TreeModelSort encapsulates any model and provides a sorted view of it. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 32 --- child model and proxies its data. It has identical column types to this +-- child model and proxies its data. It has identical rows to its hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 34 --- purpose of this model is to provide a way to sort a different model without +-- purpose of this model is to provide a way to sort a model without hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 50 + TypedTreeModelSort, + hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 79 --------------------- --- Interfaces - ---instance TreeModelClass TreeModelSort ---TODO: this is only commented out because the old version also defines this --- instance. When we delete the old api, re-enable this instance. (That is --- if we keep this module at all) +instance TreeModelClass (TypedTreeModelSort a) +instance TreeModelSortClass (TypedTreeModelSort a) +instance GObjectClass (TypedTreeModelSort a) where + toGObject (TypedTreeModelSort tm) = mkGObject (castForeignPtr tm) + unsafeCastGObject = TypedTreeModelSort . castForeignPtr . unGObject +instance TreeSortableClass TreeModelSort +instance TreeSortableClass (TypedTreeModelSort row) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 93 -treeModelSortNewWithModel :: TreeModelClass childModel => childModel -> IO TreeModelSort -treeModelSortNewWithModel childModel = +treeModelSortNewWithModel :: (TreeModelClass (childModel row), + TypedTreeModelClass childModel) => + childModel row -> IO (TypedTreeModelSort row) +treeModelSortNewWithModel childModel = liftM unsafeTreeModelSortToGeneric $ hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 140 - {# call unsafe tree_model_sort_convert_path_to_child_path #} + {# call tree_model_sort_convert_path_to_child_path #} hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 169 - {# call unsafe tree_model_sort_convert_iter_to_child_iter #} + {# call tree_model_sort_convert_iter_to_child_iter #} hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 175 --- | This resets the default sort function to be in the \'unsorted\' state. That --- is, it is in the same order as the child model. It will re-sort the model to --- be in the same order as the child model only if the 'TreeModelSort' is in [_$_] --- \'unsorted\' state. +-- | This resets the default sort function. As a consequence, the order of +-- this model will be the same order as that of the child model. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 22 --- treeViewMoveColumnAfter and treeViewMoveColumnFirst are not dealt with in --- Mogul --- hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 139 - treeViewGetSearchColumn, - treeViewSetSearchColumn, hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 181 - treeViewSearchColumn, hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 979 --- using the \"start-interactive-search\" key binding. +-- using the \"start-interactive-search\" key binding. In any case, +-- a predicate that compares a row of the model with the text the user +-- has typed must be set using 'treeViewSetSearchEqualFunc'. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 989 --- | Gets the column searched on by the interactive search. --- -treeViewGetSearchColumn :: TreeViewClass self => self - -> IO Int -treeViewGetSearchColumn self = - liftM fromIntegral $ - {# call unsafe tree_view_get_search_column #} - (toTreeView self) - --- | Sets @column@ as the column where the interactive search code should --- search in. --- --- If the sort column is set, users can use the \"start-interactive-search\" --- key binding to bring up search popup. The enable-search property controls --- whether simply typing text will also start an interactive search. --- --- Note that @column@ refers to a column of the model. --- -treeViewSetSearchColumn :: TreeViewClass self => self - -> Int -- ^ @column@ - the column of the model to search in, or -1 to - -- disable searching - -> IO () -treeViewSetSearchColumn self column = - {# call tree_view_set_search_column #} - (toTreeView self) - (fromIntegral column) - hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 991 --- * The default function assumes that the column @col@ has contains --- 'Attribute' @cr@ @String@. It conducts a --- case insensitive comparison of the text typed by the user and the --- text in the tree model. This function can be used to override this [_$_] --- behaviour. The predicate returns @True@ if the entries should --- be considered to match. The parameters are the column number, the text --- the user typed in and a 'TreeIter' which points to the cell --- to be compared. +-- * The predicate must returns @True@ if the text entered by the user +-- and the row of the model match. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 995 - -> (Int -> String -> TreeIter -> IO Bool) + -> Maybe (String -> TreeIter -> IO Bool) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 997 -treeViewSetSearchEqualFunc self pred = do - fPtr <- mkTreeViewSearchEqualFunc (\_ col keyPtr iterPtr _ -> do +treeViewSetSearchEqualFunc self (Just pred) = do + fPtr <- mkTreeViewSearchEqualFunc (\_ _ keyPtr iterPtr _ -> do hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 1001 - liftM (fromBool.not) $ pred (fromIntegral col) key iter) + liftM (fromBool . not) $ pred key iter) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 1005 + {# call tree_view_set_search_column #} (toTreeView self) 0 +treeViewSetSearchEqualFunc self Nothing = do + {# call tree_view_set_search_equal_func #} (toTreeView self) + nullFunPtr nullPtr nullFunPtr + {# call tree_view_set_search_column #} (toTreeView self) (-1) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 1412 --- | Model column to search through when searching through code. --- --- Allowed values: >= -1 --- --- Default value: -1 --- -treeViewSearchColumn :: TreeViewClass self => Attr self Int -treeViewSearchColumn = newAttr - treeViewGetSearchColumn - treeViewSetSearchColumn - hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 20 --- NOTES --- --- tree_view_column_new_with_attributes and tree_view_column_set_attributes [_$_] --- are variadic and the funcitonality can be achieved through other [_$_] --- functions. --- --- tree_view_column_set_cell_data and tree_view_column_cell_get_size are not --- bound because I am not sure what they do and when they are useful --- --- TODO --- --- treeViewColumnSetCellData is not bound. With this function the user has --- control over how data in the store is mapped to the attributes of a --- cell renderer. This functin should be bound in the future to allow the --- user to insert Haskell data types into the store and convert these --- values to attributes of cell renderers. --- hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 35 --- Please refer to the tree widget conceptual overview for an overview of --- all the objects and data types related to the tree widget and how they work --- together. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 92 +#if GTK_CHECK_VERSION(2,4,0) + treeViewColumnSetExpand, + treeViewColumnGetExpand, +#endif + treeViewColumnCellIsVisible, +#if GTK_CHECK_VERSION(2,2,0) + treeViewColumnFocusCell, +#if GTK_CHECK_VERSION(2,8,0) + treeViewColumnQueueResize, +#endif +#endif hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 114 + treeViewColumnExpand, hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 140 +import Graphics.UI.Gtk.General.Structs (SortColumnId) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 437 --- will be clickable after this call. Logical refers to the column in --- the 'TreeModel'. +-- will be clickable after this call. Logical refers to the [_$_] +-- 'Graphics.UI.Gtk.ModelView.TreeSortable.SortColumnId' for which +-- a comparison function was set. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 441 -treeViewColumnSetSortColumnId :: TreeViewColumn -> Int -> IO () +treeViewColumnSetSortColumnId :: TreeViewColumn -> SortColumnId -> IO () hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 449 --- * Retrieves the logical @columnId@ that the model sorts on when --- this column is selected for sorting. +-- * Retrieves the logical @columnId@ that the model sorts on when this column +-- is selected for sorting. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 452 --- * Returns -1 if this column can't be used for sorting. +-- * Returns +-- 'Graphics.UI.Gtk.ModelView.TreeSortable.treeSortableDefaultSortColumnId' +-- if this tree view column has no +-- 'Graphics.UI.Gtk.ModelView.TreeSortable.SortColumnId' associated with it. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 457 -treeViewColumnGetSortColumnId :: TreeViewColumn -> IO Int +treeViewColumnGetSortColumnId :: TreeViewColumn -> IO SortColumnId hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 501 +#if GTK_CHECK_VERSION(2,4,0) +-- %hash c:7808 d:942b +-- | Sets the column to take available extra space. This space is shared +-- equally amongst all columns that have the expand set to @True@. If no column +-- has this option set, then the last column gets all extra space. By default, +-- every column is created with this @False@. +-- +-- * Available since Gtk+ version 2.4 +-- +treeViewColumnSetExpand :: TreeViewColumn + -> Bool -- ^ @expand@ - @True@ if the column should take available extra + -- space, @False@ if not + -> IO () +treeViewColumnSetExpand self expand = + {# call gtk_tree_view_column_set_expand #} + self + (fromBool expand) + +-- %hash c:ee41 d:f16b +-- | Return @True@ if the column expands to take any available space. +-- +-- * Available since Gtk+ version 2.4 +-- +treeViewColumnGetExpand :: TreeViewColumn + -> IO Bool -- ^ returns @True@, if the column expands +treeViewColumnGetExpand self = + liftM toBool $ + {# call gtk_tree_view_column_get_expand #} + self +#endif + +-- %hash c:77e0 d:e1c7 +-- | Returns @True@ if any of the cells packed into the @treeColumn@ are +-- visible. For this to be meaningful, you must first initialize the cells with +-- 'treeViewColumnCellSetCellData' +-- +treeViewColumnCellIsVisible :: TreeViewColumn + -> IO Bool -- ^ returns @True@, if any of the cells packed into the + -- @treeColumn@ are currently visible +treeViewColumnCellIsVisible self = + liftM toBool $ + {# call gtk_tree_view_column_cell_is_visible #} + self + +#if GTK_CHECK_VERSION(2,2,0) +-- %hash c:a202 d:1401 +-- | Sets the current keyboard focus to be at @cell@, if the column contains 2 +-- or more editable and activatable cells. +-- +-- * Available since Gtk+ version 2.2 +-- +treeViewColumnFocusCell :: CellRendererClass cell => TreeViewColumn + -> cell -- ^ @cell@ - A 'CellRenderer' + -> IO () +treeViewColumnFocusCell self cell = + {# call gtk_tree_view_column_focus_cell #} + self + (toCellRenderer cell) + +#if GTK_CHECK_VERSION(2,8,0) +-- %hash c:4420 d:bfde +-- | Flags the column, and the cell renderers added to this column, to have +-- their sizes renegotiated. +-- +-- * Available since Gtk+ version 2.8 +-- +treeViewColumnQueueResize :: TreeViewColumn -> IO () +treeViewColumnQueueResize self = + {# call gtk_tree_view_column_queue_resize #} + self +#endif +#endif + hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 666 +-- %hash c:800 d:eb1a +-- | Column gets share of extra width allocated to the widget. +-- +-- Default value: @False@ +-- +treeViewColumnExpand :: Attr TreeViewColumn Bool +treeViewColumnExpand = newAttrFromBoolProperty "expand" + hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeViewColumn.chs.pp 731 -treeViewColumnSortColumnId :: Attr TreeViewColumn Int +treeViewColumnSortColumnId :: Attr TreeViewColumn SortColumnId hunk ./gtk/Graphics/UI/Gtk/ModelView/Types.chs 35 + TypedTreeModelSort(..), + unsafeTreeModelSortToGeneric, + [_$_] hunk ./gtk/Graphics/UI/Gtk/ModelView/Types.chs 57 -{#import Graphics.UI.Gtk.Types#} (TreeModel) +{#import Graphics.UI.Gtk.Types#} (TreeModel, TreeModelSort) hunk ./gtk/Graphics/UI/Gtk/ModelView/Types.chs 67 + dummy _ = error "not used" hunk ./gtk/Graphics/UI/Gtk/ModelView/Types.chs 79 +newtype TypedTreeModelSort row = TypedTreeModelSort (ForeignPtr (TypedTreeModelSort row)) + +unsafeTreeModelSortToGeneric :: TreeModelSort -> TypedTreeModelSort row +unsafeTreeModelSortToGeneric = unsafeCoerce# + +instance TypedTreeModelClass TypedTreeModelSort + hunk ./gtk/Graphics/UI/Gtk/ModelView.hs 49 + module Graphics.UI.Gtk.ModelView.TreeSortable, hunk ./gtk/Graphics/UI/Gtk/ModelView.hs 73 +import Graphics.UI.Gtk.ModelView.TreeSortable |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:11
|
Thu Jan 3 11:00:26 PST 2008 A....@ke... * Add the TreeSortable interface. This interface allows a view to sort the underlying model. Since our CustomStore does not implement this interface, the only object that actually does implement it is the TreeModelSort proxy which takes a child model and sorts its rows on-the-fly. hunk ./Makefile.am 562 + gtk/Graphics/UI/Gtk/ModelView/TreeSortable.chs.pp \ hunk ./Makefile.am 642 + gtk/Graphics/UI/Gtk/ModelView/TreeSortable_stub.o \ hunk ./gtk/Graphics/UI/Gtk/General/Structs.hsc 92 - dragContextSetAction + dragContextSetAction, + SortColumnId, + treeSortableDefaultSortColumnId hunk ./gtk/Graphics/UI/Gtk/General/Structs.hsc 939 +-- | ID number of a sort column. +-- +-- * A 'SortColumnId' is a logical number to which a sorting function can +-- be associated. The number does not have to coincide with any column +-- number. +type SortColumnId = Int + +-- | A special 'SortColumnId' to indicated that the default sorting function is used. +-- +treeSortableDefaultSortColumnId :: SortColumnId +treeSortableDefaultSortColumnId = #{const GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID} + addfile ./gtk/Graphics/UI/Gtk/ModelView/TreeSortable.chs.pp hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeSortable.chs.pp 1 +-- -*-haskell-*- +-- GIMP Toolkit (GTK) Interface TreeSortable +-- +-- Author : Axel Simon +-- +-- Created: 8 Mar 2007 +-- +-- Copyright (C) 1999-2007 Duncan Coutts, 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. +-- +-- Note: there is a constant called GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID +-- which is only used in the C implementation of list store and tree store. +-- The TreeModelSort proxy only uses the default column constant. Hence, we do +-- not expose or tell the user about the UNSORTED constant since it can only +-- be confusing. +-- +-- | +-- Maintainer : gtk...@li... Stability : provisional +-- Portability : portable (depends on GHC) +-- +-- The interface for sortable models used by 'TreeView' +-- +module Graphics.UI.Gtk.ModelView.TreeSortable ( + +-- * Detail +-- +-- | 'TreeSortable' is an interface to be implemented by tree models which +-- support sorting. The 'TreeView' uses the methods provided by this interface +-- to sort the model. As of now, only the +-- 'Graphics.UI.Gtk.ModelView.TreeModelSort.TreeModelSort' proxy supports the +-- sortable interface. Thus, in order to enable sortable columns in a +-- 'TreeView', it is necessary to wrap a +-- 'Graphics.UI.Gtk.ModelView.ListStore.ListStore' or +-- 'Graphics.UI.Gtk.ModelView.TreeStore.TreeStore' model in a +-- 'Graphics.UI.Gtk.ModelView.TreeModelSort.TreeModelSort'. +-- [_$_] +-- A 'Graphics.UI.Gtk.ModelView.TreeViewColumn' can be sorted by the user +-- though clicking into the column's header. The rows in the view will then be +-- sorted by the sorting function set for that column. Specifically, a set of +-- sorting functions must be set using the interface provided in this module. +-- Each sorting function is associated with a 'SortColumnId', which is some +-- positive number. A tree view column is then associated with the sorting +-- function by passing the 'SortColumnId' to +-- 'Graphics.UI.Gtk.ModelView.TreeViewColumn.treeViewColumnSetSortColumnId'. +-- There exists one special 'SortColumnId', namely +-- 'treeSortableDefaultSortColumnId' for which a default sorting function can +-- be set. If no such function is set, the order of the rows is the order in +-- which they are stored in the model. + +-- * Class Hierarchy +-- +-- | +-- @ +-- | 'GInterface' +-- | +----TreeSortable +-- @ + +-- * Types + TreeSortable, + TreeSortableClass, + castToTreeSortable, + toTreeSortable, + SortColumnId, + +-- * Constants + treeSortableDefaultSortColumnId, + +-- * Methods + treeSortableGetSortColumnId, + treeSortableSetSortColumnId, + treeSortableSetSortFunc, + treeSortableSetDefaultSortFunc, + treeSortableHasDefaultSortFunc, + treeSortableSortColumnChanged, + +-- * Signals + sortColumnChanged + ) where + +import Control.Monad (liftM, when) + +import System.Glib.FFI +import System.Glib.Flags (Flags, toFlags) +import System.Glib.UTFString +import System.Glib.GObject (mkFunPtrDestroyNotify) +{#import Graphics.UI.Gtk.Types#} +{#import Graphics.UI.Gtk.General.Enums#} (SortType(..)) +{#import Graphics.UI.Gtk.Signals#} +{#import Graphics.UI.Gtk.ModelView.Types#} +import Graphics.UI.Gtk.General.Structs (SortColumnId, + treeSortableDefaultSortColumnId ) + +{# context lib="gtk" prefix="gtk" #} + +-------------------- +-- Methods + +-- %hash c:a53 d:e0d2 +-- | Query the sort column id that is currently in use. The return value may +-- be the special constant 'treeSortableDefaultSortColumnId' in which case +-- the returned Boolean flag is @False@. +-- +treeSortableGetSortColumnId :: TreeSortableClass self => self + -> IO (SortType, Bool, SortColumnId) -- ^ @(type, columnSet, sortColumnId)@ [_$_] + -- returns @True@ in @columnSet@ if @sortColumnId@ is not + -- 'treeSortableDefaultSortColumnId'. The @type@ value indicates increasing + -- or decreasing ordering. +treeSortableGetSortColumnId self = + alloca $ \orderPtr -> alloca $ \sortColumnIdPtr -> do + columnSet <- liftM toBool $ {# call unsafe tree_sortable_get_sort_column_id #} + (toTreeSortable self) + sortColumnIdPtr + orderPtr + order <- peek orderPtr + sortColumnId <- peek sortColumnIdPtr + return (toEnum (fromIntegral order), columnSet, fromIntegral sortColumnId) + +-- %hash c:8951 d:33ab +-- | Sets the current sort column to be @sortColumnId@. The @sortable@ will +-- resort itself to reflect this change, after emitting a 'sortColumnChanged' +-- signal. If @sortColumnId@ is 'treeSortableDefaultSortColumnId', then the +-- default sort function will be used, if it is set. Note that this function +-- is mainly used by the view and that the user program should simply set the +-- 'SortColumnId' of the 'TreeViewColumn's. +-- +treeSortableSetSortColumnId :: TreeSortableClass self => self + -> SortColumnId -- ^ @sortColumnId@ - the sort column id to set + -> SortType -- ^ @order@ - The sort order of the column + -> IO () +treeSortableSetSortColumnId self sortColumnId order = + {# call tree_sortable_set_sort_column_id #} + (toTreeSortable self) + (fromIntegral sortColumnId) + ((fromIntegral . fromEnum) order) + + +-- %hash c:9048 d:c49d +-- | Sets the comparison function used when sorting to be @sortFunc@. If the +-- current sort column id of @self@ is the same as @sortColumnId@, then the +-- model will sort using this function. +-- +treeSortableSetSortFunc :: TreeSortableClass self => self + -> SortColumnId -- ^ @sortColumnId@ - the sort column id to set + -- the function for + -> (TreeIter -> TreeIter -> IO Ordering) + -- ^ @sortFunc@ - The comparison function + -> IO () +treeSortableSetSortFunc self sortColumnId sortFunc = do + fPtr <- mkTreeIterCompareFunc (\_ iter1Ptr iter2Ptr _ -> do + iter1 <- peek iter1Ptr + iter2 <- peek iter2Ptr + liftM orderToGInt $ sortFunc iter1 iter2) + dPtr <- mkFunPtrDestroyNotify fPtr + {# call tree_sortable_set_sort_func #} + (toTreeSortable self) + (fromIntegral sortColumnId) + fPtr nullPtr dPtr + +orderToGInt :: Ordering -> {#type gint#} +orderToGInt LT = -1 +orderToGInt EQ = 0 +orderToGInt GT = 1 + +{#pointer TreeIterCompareFunc#} + +foreign import ccall "wrapper" mkTreeIterCompareFunc :: + (Ptr TreeModel -> Ptr TreeIter -> Ptr TreeIter -> Ptr () -> IO {#type gint#}) -> + IO TreeIterCompareFunc + +-- %hash c:221e d:7c9 +-- | Sets the default comparison function used when sorting to be @sortFunc@. +-- If the current sort column id of @self@ is +-- 'treeSortableDefaultSortColumnId' then the model will sort using +-- this function. +-- +treeSortableSetDefaultSortFunc :: TreeSortableClass self => self + -> (TreeIter -> TreeIter -> IO Ordering) + -- ^ @sortFunc@ - The comparison function + -> IO () +treeSortableSetDefaultSortFunc self sortFunc = do + fPtr <- mkTreeIterCompareFunc (\_ iter1Ptr iter2Ptr _ -> do + iter1 <- peek iter1Ptr + iter2 <- peek iter2Ptr + liftM orderToGInt $ sortFunc iter1 iter2) + dPtr <- mkFunPtrDestroyNotify fPtr + {# call tree_sortable_set_default_sort_func #} + (toTreeSortable self) + fPtr nullPtr dPtr + +-- %hash c:78ec d:d949 +-- | Emits a 'sortColumnChanged' signal on the model. +-- +treeSortableSortColumnChanged :: TreeSortableClass self => self -> IO () +treeSortableSortColumnChanged self = + {# call gtk_tree_sortable_sort_column_changed #} + (toTreeSortable self) + +-- %hash c:4a10 d:f107 +-- | Returns @True@ if the model has a default sort function. This is used +-- primarily by 'Graphics.UI.Gtk.ModelView.TreeViewColumn's in order to +-- determine if a model has a default ordering or if the entries are +-- retrieved in the sequence in which they are stored in the model. +-- +treeSortableHasDefaultSortFunc :: TreeSortableClass self => self + -> IO Bool -- ^ returns @True@, if the model has a default sort function +treeSortableHasDefaultSortFunc self = + liftM toBool $ + {# call gtk_tree_sortable_has_default_sort_func #} + (toTreeSortable self) + +-------------------- +-- Signals + +-- %hash c:c461 d:af3f +-- | +-- +sortColumnChanged :: TreeSortableClass self => Signal self (IO ()) +sortColumnChanged = Signal (connect_NONE__NONE "sort_column_changed") hunk ./tools/hierarchyGen/hierarchy.list 171 -# This is actually an interface, but all objects that implement it are at +# These are actually interfaces, but all objects that implement it are at hunk ./tools/hierarchyGen/hierarchy.list 174 + GtkTreeSortable if gtk-2.4 |
From: Axel S. <A....@ke...> - 2008-01-06 09:31:11
|
Thu Jan 3 10:21:05 PST 2008 A....@ke... * Add Show instances to enumerations. hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 90 -{#enum AccelFlags {underscoreToCase} deriving(Eq, Bounded)#} +{#enum AccelFlags {underscoreToCase} deriving(Bounded,Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 96 -{#enum ArrowType {underscoreToCase} deriving (Eq)#} +{#enum ArrowType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 100 -{#enum AttachOptions {underscoreToCase} deriving(Eq, Bounded)#} +{#enum AttachOptions {underscoreToCase} deriving(Bounded,Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 124 -{#enum ButtonBoxStyle {underscoreToCase} deriving (Eq)#} +{#enum ButtonBoxStyle {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 128 -{#enum CalendarDisplayOptions {underscoreToCase} deriving(Eq, Bounded)#} +{#enum CalendarDisplayOptions {underscoreToCase} deriving(Bounded,Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 142 -{#enum CornerType {underscoreToCase} deriving (Eq)#} +{#enum CornerType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 146 -{#enum DeleteType {underscoreToCase} deriving (Eq)#} +{#enum DeleteType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 168 -{#enum DestDefaults {underscoreToCase} deriving (Bounded,Eq)#} +{#enum DestDefaults {underscoreToCase} deriving (Bounded,Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 174 -{#enum DirectionType {underscoreToCase} deriving (Eq)#} +{#enum DirectionType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 178 -{#enum Justification {underscoreToCase} deriving (Eq)#} +{#enum Justification {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 183 -{#enum MatchType {underscoreToCase} deriving (Eq)#} +{#enum MatchType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 188 -{#enum MenuDirectionType {underscoreToCase} deriving (Eq)#} +{#enum MenuDirectionType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 192 -{#enum MetricType {underscoreToCase} deriving (Eq)#} +{#enum MetricType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 196 -{#enum MovementStep {underscoreToCase} deriving (Eq)#} +{#enum MovementStep {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 200 -{#enum Orientation {underscoreToCase} deriving (Eq)#} +{#enum Orientation {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 226 - deriving (Enum,Eq) + deriving (Enum,Eq,Show) hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 243 -{#enum PackType {underscoreToCase} deriving (Eq)#} +{#enum PackType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 247 -{#enum PathPriorityType {underscoreToCase} deriving (Eq)#} +{#enum PathPriorityType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 251 -{#enum PathType {underscoreToCase} deriving (Eq)#} +{#enum PathType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 255 -{#enum PolicyType {underscoreToCase} deriving (Eq)#} +{#enum PolicyType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 260 -{#enum PositionType {underscoreToCase} deriving (Eq)#} +{#enum PositionType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 265 -{#enum ProgressBarOrientation {underscoreToCase} deriving (Eq)#} +{#enum ProgressBarOrientation {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 269 -{#enum ReliefStyle {underscoreToCase} deriving (Eq)#} +{#enum ReliefStyle {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 279 -{#enum ResizeMode {underscoreToCase} deriving (Eq)#} +{#enum ResizeMode {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 283 -{#enum ScrollType {underscoreToCase} deriving (Eq)#} +{#enum ScrollType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 294 - deriving (Enum, Eq) --- {#enum SelectionMode {underscoreToCase} deriving (Eq)#} + deriving (Enum,Eq,Show) +-- {#enum SelectionMode {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 299 -{#enum ShadowType {underscoreToCase} deriving (Eq)#} +{#enum ShadowType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 304 -{#enum SortType {underscoreToCase} deriving (Eq)#} +{#enum SortType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 308 -{#enum StateType {underscoreToCase} deriving (Eq)#} +{#enum StateType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 313 -{#enum SubmenuDirection {underscoreToCase} deriving (Eq)#} +{#enum SubmenuDirection {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 317 -{#enum SubmenuPlacement {underscoreToCase} deriving (Eq)#} +{#enum SubmenuPlacement {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 322 -{#enum SpinButtonUpdatePolicy {underscoreToCase} deriving (Eq)#} +{#enum SpinButtonUpdatePolicy {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 326 -{#enum SpinType {underscoreToCase} deriving (Eq)#} +{#enum SpinType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 338 -{#enum TargetFlags {underscoreToCase} deriving(Bounded) #} +{#enum TargetFlags {underscoreToCase} deriving(Bounded,Eq,Show) #} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 344 -{#enum TextDirection {underscoreToCase} deriving (Eq)#} +{#enum TextDirection {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 349 -{#enum TextSearchFlags {underscoreToCase} deriving(Eq, Bounded)#} +{#enum TextSearchFlags {underscoreToCase} deriving(Bounded,Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 355 -{#enum TextWindowType {underscoreToCase} deriving (Eq)#} +{#enum TextWindowType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 359 -{#enum ToolbarStyle {underscoreToCase} deriving (Eq)#} +{#enum ToolbarStyle {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 363 -{#enum TreeViewColumnSizing {underscoreToCase} deriving (Eq)#} +{#enum TreeViewColumnSizing {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 366 ---{#enum TroughType {underscoreToCase} deriving (Eq)#} +--{#enum TroughType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 372 -{#enum UpdateType {underscoreToCase} deriving (Eq)#} +{#enum UpdateType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 376 -{#enum Visibility {underscoreToCase} deriving (Eq)#} +{#enum Visibility {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 380 -{#enum WindowPosition {underscoreToCase} deriving (Eq)#} +{#enum WindowPosition {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 384 -{#enum WindowType {underscoreToCase} deriving (Eq)#} +{#enum WindowType {underscoreToCase} deriving (Eq,Show)#} hunk ./gtk/Graphics/UI/Gtk/General/Enums.chs.pp 388 -{#enum WrapMode {underscoreToCase} deriving (Eq)#} +{#enum WrapMode {underscoreToCase} deriving (Eq,Show)#} |
From: Axel S. <A....@ke...> - 2007-12-13 14:31:34
|
Thu Dec 13 06:28:56 PST 2007 A....@ke... * Make treeModelSortNewWithModel safe. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeModelSort.chs.pp 95 - {# call unsafe tree_model_sort_new_with_model #} + {# call tree_model_sort_new_with_model #} |
From: Duncan C. <dun...@wo...> - 2007-12-11 16:32:30
|
Mon Dec 10 06:14:35 PST 2007 A....@ke... * Correct CellLayout to compiler with Gtk 2.4. hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 78 +#if GTK_CHECK_VERSION(2,6,0) hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 80 +instance CellLayoutClass IconView +#endif + hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 86 -instance CellLayoutClass IconView |
From: Axel S. <A....@ke...> - 2007-12-10 14:15:45
|
Mon Dec 10 06:14:35 PST 2007 A....@ke... * Correct CellLayout to compiler with Gtk 2.4. hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 77 +#if GTK_CHECK_VERSION(2,6,0) hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 79 +instance CellLayoutClass IconView +#endif + hunk ./gtk/Graphics/UI/Gtk/ModelView/CellLayout.chs.pp 85 -instance CellLayoutClass IconView |
From: Duncan C. <dun...@wo...> - 2007-12-10 03:40:15
|
Sun Dec 9 19:36:36 PST 2007 Duncan Coutts <du...@ha...> * Fix PixbufData's MArray instance for ghc-6.8 The MArray class gained a getNumElements method in ghc 6.8 Also take the opportunity to tidy things up a bit. hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 124 -import Graphics.UI.Gtk.Gdk.PixbufData ( PixbufData(PixbufData), - insertBounds ) +import Graphics.UI.Gtk.Gdk.PixbufData ( PixbufData, mkPixbufData ) hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 126 -{# context lib="gdk-pixbuf" prefix="gdk" #} +{# context prefix="gdk" #} hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 201 -pixbufGetPixels :: (Ix i, Num i, Storable e) => Pixbuf -> IO (PixbufData i e) +pixbufGetPixels :: Storable e => Pixbuf -> IO (PixbufData Int e) hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 211 - return (insertBounds bytes (PixbufData pb pixPtr undefined)) + return (mkPixbufData pb pixPtr bytes) hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 30 - PixbufData(PixbufData), - insertBounds + PixbufData, + mkPixbufData hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 44 +#if __GLASGOW_HASKELL__ >= 608 + ,getNumElements +#endif hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 53 -data Ix i => PixbufData i e = PixbufData Pixbuf (Ptr e) (i,i) +data Ix i => PixbufData i e = PixbufData !Pixbuf + {-# UNPACK #-} !(Ptr e) + !(i,i) + {-# UNPACK #-} !Int + +mkPixbufData :: Storable e => Pixbuf -> Ptr e -> Int -> PixbufData Int e +mkPixbufData pb (ptr :: Ptr e) size = + PixbufData pb ptr (0, count) count + where count = fromIntegral (size `div` sizeOf (undefined :: e)) hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 73 - unsafeRead (PixbufData (Pixbuf pb) pixPtr _) idx = do + unsafeRead (PixbufData (Pixbuf pb) pixPtr _ _) idx = do hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 78 - unsafeWrite (PixbufData (Pixbuf pb) pixPtr _) idx elem = do + unsafeWrite (PixbufData (Pixbuf pb) pixPtr _ _) idx elem = do hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 83 - getBounds (PixbufData pb ptr bd) = return bd + getBounds (PixbufData _ _ bd _) = return bd +#endif +#if __GLASGOW_HASKELL__ >= 608 + {-# INLINE getNumElements #-} + getNumElements (PixbufData _ _ _ count) = return count hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 89 - --- Insert bounds into a PixbufData. -insertBounds :: (Num i, Ix i, Storable e) => Int -> [_$_] - PixbufData i e -> PixbufData i e -insertBounds size ((PixbufData pb ptr _) :: PixbufData i e) = - PixbufData pb ptr (0, fromIntegral (size `div` sizeOf (undefined :: e))) |
From: Duncan C. <dun...@wo...> - 2007-12-10 03:39:21
|
Sun Dec 9 19:36:36 PST 2007 Duncan Coutts <du...@ha...> * Fix PixbufData's MArray instance for ghc-6.8 The MArray class gained a getNumElements method in ghc 6.8 Also take the opportunity to tidy things up a bit. hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 124 -import Graphics.UI.Gtk.Gdk.PixbufData ( PixbufData(PixbufData), - insertBounds ) +import Graphics.UI.Gtk.Gdk.PixbufData ( PixbufData, mkPixbufData ) hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 126 -{# context lib="gdk-pixbuf" prefix="gdk" #} +{# context prefix="gdk" #} hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 201 -pixbufGetPixels :: (Ix i, Num i, Storable e) => Pixbuf -> IO (PixbufData i e) +pixbufGetPixels :: Storable e => Pixbuf -> IO (PixbufData Int e) hunk ./gtk/Graphics/UI/Gtk/Gdk/Pixbuf.chs.pp 211 - return (insertBounds bytes (PixbufData pb pixPtr undefined)) + return (mkPixbufData pb pixPtr bytes) hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 30 - PixbufData(PixbufData), - insertBounds + PixbufData, + mkPixbufData hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 44 +#if __GLASGOW_HASKELL__ >= 608 + ,getNumElements +#endif hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 53 -data Ix i => PixbufData i e = PixbufData Pixbuf (Ptr e) (i,i) +data Ix i => PixbufData i e = PixbufData !Pixbuf + {-# UNPACK #-} !(Ptr e) + !(i,i) + {-# UNPACK #-} !Int + +mkPixbufData :: Storable e => Pixbuf -> Ptr e -> Int -> PixbufData Int e +mkPixbufData pb (ptr :: Ptr e) size = + PixbufData pb ptr (0, count) count + where count = fromIntegral (size `div` sizeOf (undefined :: e)) hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 73 - unsafeRead (PixbufData (Pixbuf pb) pixPtr _) idx = do + unsafeRead (PixbufData (Pixbuf pb) pixPtr _ _) idx = do hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 78 - unsafeWrite (PixbufData (Pixbuf pb) pixPtr _) idx elem = do + unsafeWrite (PixbufData (Pixbuf pb) pixPtr _ _) idx elem = do hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 83 - getBounds (PixbufData pb ptr bd) = return bd + getBounds (PixbufData _ _ bd _) = return bd +#endif +#if __GLASGOW_HASKELL__ >= 608 + {-# INLINE getNumElements #-} + getNumElements (PixbufData _ _ _ count) = return count hunk ./gtk/Graphics/UI/Gtk/Gdk/PixbufData.hs.pp 89 - --- Insert bounds into a PixbufData. -insertBounds :: (Num i, Ix i, Storable e) => Int -> [_$_] - PixbufData i e -> PixbufData i e -insertBounds size ((PixbufData pb ptr _) :: PixbufData i e) = - PixbufData pb ptr (0, fromIntegral (size `div` sizeOf (undefined :: e))) |
From: Axel S. <A....@ke...> - 2007-12-09 08:13:20
|
Sun Dec 9 00:11:48 PST 2007 A....@ke... * Forgot to add the file with helper functions for tree DND. addfile ./gtk/Graphics/UI/Gtk/ModelView/TreeDrag.chs hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeDrag.chs 1 +-- -*-haskell-*- +-- GIMP Toolkit (GTK) Interface DragSource and DragDest +-- +-- Author : Axel Simon +-- +-- Created: 24 July 2007 +-- +-- Copyright (C) 2007 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 : gtk...@li... +-- Stability : provisional +-- Portability : portable (depends on GHC) +-- +-- Interfaces for drag-and-drop support in 'Graphics.UI.Gtk.ModelView.TreeView'. +-- +module Graphics.UI.Gtk.ModelView.TreeDrag ( + +-- * Detail +-- +-- | 'Graphics.UI.Gtk.ModelView.TreeView's provide special support for +-- Drag-and-Drop such as hover-to-open-rows or autoscrolling. This module +-- implements two utility functions that set and get a path and a model in a +-- 'Graphics.UI.Gtk.General.Selection.Selection' structure. These functions +-- are thus useful to implement drag-and-drop functionality in a +-- 'Graphics.UI.Gtk.ModelView.TreeModel'. In fact, they are used as part of +-- the default drag-and-drop interfaces of +-- 'Graphics.UI.Gtk.ModelView.ListStore' and +-- 'Graphics.UI.Gtk.ModelView.TreeStore' that allows to permute rows and move +-- them between hierarchy levels. + +-- * Utility functions + treeModelEqual, + treeGetRowDragData, + treeSetRowDragData + + ) where + +-- I've decided not to bind the DragSource and DragDest interfaces. They seem +-- to be useful if you (a) write your own 'TreeView' widget or (b) if you +-- can't be bothered to implement a special variant of these interfaces in +-- ListStore and TreeStore. In the latter case the interfaces are useful to +-- "simulate" a drag-and-drop that looks like a row-permutation which is the +-- interface that Gtk's ListStore and TreeStore support by default. Since +-- overriding or augmenting the dnd interfaces for ListStore and TreeStore is +-- so easy in Gtk2Hs, I think we can do without the cheat way. + +import System.Glib.FFI +import System.Glib.GObject +{#import Graphics.UI.Gtk.Types#} +{#import Graphics.UI.Gtk.ModelView.Types#} (TreePath, fromTreePath, withTreePath, + NativeTreePath(..)) +import Graphics.UI.Gtk.General.DNDTypes (SelectionDataM, SelectionData) +import Control.Monad (liftM) +import Control.Monad.Trans (liftIO) +import Control.Monad.Reader (ask) + +{# context lib="gtk" prefix="gtk" #} + +-- | Compare two tree model for equality. +treeModelEqual :: (TreeModelClass tm1, TreeModelClass tm2) => tm1 -> tm2 -> Bool +treeModelEqual tm1 tm2 = unTreeModel (toTreeModel tm1) == unTreeModel (toTreeModel tm2) + +-- %hash c:8dcb d:af3f +-- | Obtains a 'TreeModel' and a path from 'SelectionDataM' whenever the target name is +-- "GTK_TREE_MODEL_ROW". Normally called from a 'treeDragDestDragDataReceived' handler. +-- +treeGetRowDragData :: SelectionDataM (Maybe (TreeModel, TreePath)) +treeGetRowDragData = ask >>= \selPtr -> liftIO $ alloca $ \tmPtrPtr -> alloca $ \pathPtrPtr -> do + isValid <- liftM toBool $ + {# call unsafe gtk_tree_get_row_drag_data #} selPtr (castPtr tmPtrPtr) (castPtr pathPtrPtr) + if isValid then do + tmPtr <- peek tmPtrPtr + pathPtr <- peek pathPtrPtr + tm <- makeNewGObject mkTreeModel (return tmPtr) + path <- fromTreePath pathPtr + return (Just (tm, path)) + else return Nothing + +-- %hash c:e3e3 d:af3f +-- | Sets selection data with the target name "GTK_TREE_MODEL_ROW", consisting +-- of a 'TreeModel' and a 'TreePath'. Normally used in a +-- 'treeDragSourceDragDataGet' handler. +-- +-- * Returns @True@ if setting the data was successful. +-- +treeSetRowDragData :: TreeModelClass treeModel => treeModel -> TreePath -> SelectionDataM Bool +treeSetRowDragData treeModel path = do + selPtr <- ask + liftM toBool $ liftIO $ withTreePath path $ \path -> + {# call unsafe gtk_tree_set_row_drag_data #} selPtr [_$_] + (toTreeModel treeModel) + path |
From: Duncan C. <dun...@wo...> - 2007-12-08 17:07:08
|
Mon Nov 26 18:11:50 PST 2007 Duncan Coutts <du...@ha...> * Export DialogFlags which is used as an arg of several MessageDialog functions hunk ./gtk/Graphics/UI/Gtk/Windows/MessageDialog.chs.pp 61 + DialogFlags(..), |
From: Axel S. <A....@ke...> - 2007-12-04 21:36:24
|
Tue Dec 4 13:26:16 PST 2007 A....@ke... * Fix stamp problems in tree implementation. The story of TreeIter stamps is as follows: ListStore doesn't use them since the iterators remain valid throughout. TreeStore needs to invalidate the iterators each time a node is inserted since a new node might mean that it can't be indexed anymore with the available number of bits at that level. The function that inserts nodes correctly invalidated the tree iterators. However, this function also calls methods in TreeModel, passing in order to notify itself and the view. The passed in TreeIters have no stamp set, thus a warning is raised as soon as these tree iters get back to the model, usually in a form of ref'ing the node. This was slightly confusing as setting the stamp was so far automatically done in the C interface Gtk2HsStore.c. The stamp is now set explicity in the TreeIters before they are passed to the functions in the model. hunk ./gtk/Graphics/UI/Gtk/ModelView/CustomStore.chs 43 + customTreeModelGetStamp, hunk ./gtk/Graphics/UI/Gtk/ModelView/Gtk2HsStore.c 589 + if (result) iter->stamp = store->stamp; hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeStore.hs 475 + stamp <- customTreeModelGetStamp model hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeStore.hs 478 - in treeModelRowInserted model p' iter + in treeModelRowInserted model p' (treeIterSetStamp iter stamp) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeStore.hs 482 - when toggle $ treeModelRowHasChildToggled model path iter + when toggle $ treeModelRowHasChildToggled model path + (treeIterSetStamp iter stamp) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeStore.hs 629 - when found $ treeModelRowChanged model path iter + stamp <- customTreeModelGetStamp model + when found $ treeModelRowChanged model path (treeIterSetStamp iter stamp) hunk ./gtk/Graphics/UI/Gtk/ModelView/Types.chs 39 + treeIterSetStamp, hunk ./gtk/Graphics/UI/Gtk/ModelView/Types.chs 132 +-- update the stamp of a tree iter +treeIterSetStamp :: TreeIter -> CInt -> TreeIter +treeIterSetStamp (TreeIter _ a b c) s = (TreeIter s a b c) + |
From: Axel S. <A....@ke...> - 2007-12-04 21:36:23
|
Tue Dec 4 13:35:15 PST 2007 A....@ke... * Add DND functions to IconView. hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 93 -{- iconViewGetItemAtPos, + iconViewGetItemAtPos, hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 104 - iconViewSetDragDestItem, - iconViewGetDragDestItem, - iconViewGetDestItemAtPos, - -} iconViewCreateDragIcon, hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 135 -{#import System.Glib.GList#} +import System.Glib.GList (fromGList) +import System.Glib.Flags hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 139 +import Graphics.UI.Gtk.Gdk.Enums (DragAction(..)) +import Graphics.UI.Gtk.Gdk.Events (Modifier(..)) hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 147 +{#import Graphics.UI.Gtk.General.DNDTypes#} (TargetList(..)) hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 730 -{- hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 736 - -> [ModifierType] -- ^ @startButtonMask@ - Mask of allowed buttons - -- to start drag - -> {-const-GtkTargetEntry*-} -- ^ @targets@ - the table of targets that the - -- drag will support - -> Int -- ^ @nTargets@ - the number of items in - -- @targets@ - -> [DragAction] -- ^ @actions@ - the bitmask of possible actions - -- for a drag from this widget - -> IO () -iconViewEnableModelDragSource self startButtonMask targets nTargets actions = + -> [Modifier] -- ^ @startButtonMask@ - Mask of allowed buttons + -- to start drag + -> TargetList -- ^ @targets@ - the list of targets that the + -- the view will support + -> [DragAction] -- ^ @actions@ - flags denoting the possible actions + -- for a drag from this widget + -> IO () +iconViewEnableModelDragSource self startButtonMask targets actions = + alloca $ \nTargetsPtr -> do + tlPtr <- {#call unsafe gtk_target_table_new_from_list#} targets nTargetsPtr + nTargets <- peek nTargetsPtr hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 750 - {-targets-} - (fromIntegral nTargets) + tlPtr + nTargets hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 753 + {#call unsafe gtk_target_table_free#} tlPtr nTargets hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 761 - -> {-const-GtkTargetEntry*-} -- ^ @targets@ - the table of targets that the - -- drag will support - -> Int -- ^ @nTargets@ - the number of items in - -- @targets@ - -> [DragAction] -- ^ @actions@ - the bitmask of possible actions - -- for a drag to this widget - -> IO () -iconViewEnableModelDragDest self targets nTargets actions = + -> TargetList -- ^ @targets@ - the list of targets that the + -- the view will support + -> [DragAction] -- ^ @actions@ - flags denoting the possible actions + -- for a drop into this widget + -> IO () +iconViewEnableModelDragDest self targets actions = + alloca $ \nTargetsPtr -> do + tlPtr <- {#call unsafe gtk_target_table_new_from_list#} targets nTargetsPtr + nTargets <- peek nTargetsPtr hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 772 - {-targets-} - (fromIntegral nTargets) + tlPtr + nTargets hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 785 --} hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 797 --- | This function is a convenience function to allow you to reorder models --- that support the {GtkTreeDragSourceIface, FIXME: unknown type\/value} and --- the {GtkTreeDragDestIface, FIXME: unknown type\/value}. Both 'TreeStore' and --- 'ListStore' support these. If @reorderable@ is @True@, then the user can --- reorder the model by dragging and dropping rows. The developer can listen to --- these changes by connecting to the model's row_inserted and row_deleted --- signals. +-- | Check if icons can be moved around. hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 799 --- This function does not give you any degree of control over the order -- --- any reordering is allowed. If more control is needed, you should probably --- handle drag and drop manually. +-- * Set whether the user can use drag and drop (DND) to reorder the rows in +-- the store. This works on both 'TreeStore' and 'ListStore' models. If @ro@ +-- is @True@, then the user can reorder the model by dragging and dropping +-- rows. The developer can listen to these changes by connecting to the +-- model's signals. If you need to control which rows may be dragged or +-- where rows may be dropped, you can override the +-- 'Graphics.UI.Gtk.ModelView.CustomStore.treeDragSourceRowDraggable' +-- function in the default DND implementation of the model. hunk ./gtk/Graphics/UI/Gtk/ModelView/IconView.chs.pp 831 -{- --- %hash c:9574 d:34ea --- | Sets the item that is highlighted for feedback. --- --- * Available since Gtk+ version 2.8 --- -iconViewSetDragDestItem :: IconViewClass self => self - -> TreePath -- ^ @path@ - The path of the item to highlight, or - -- {@NULL@, FIXME: this should probably be converted - -- to a Maybe data type}. - -> IconViewDropPosition -- ^ @pos@ - Specifies where to drop, relative to the - -- item - -> IO () -iconViewSetDragDestItem self path pos = - withTreePath path $ \path -> - {# call gtk_icon_view_set_drag_dest_item #} - (toIconView self) - path - ((fromIntegral . fromEnum) pos) - --- %hash c:92a7 d:8b3f --- | Gets information about the item that is highlighted for feedback. --- --- * Available since Gtk+ version 2.8 --- -iconViewGetDragDestItem :: IconViewClass self => self - -> {-GtkTreePath**-} -- ^ @path@ - Return location for the path of - -- the highlighted item, or {@NULL@, FIXME: - -- this should probably be converted to a - -- Maybe data type}. - -> {-GtkIconViewDropPosition*-} -- ^ @pos@ - Return location for the drop - -- position, or {@NULL@, FIXME: this should - -- probably be converted to a Maybe data type} - -> IO () -iconViewGetDragDestItem self path pos = - {# call gtk_icon_view_get_drag_dest_item #} - (toIconView self) - {-path-} - {-pos-} - --- %hash c:28ff d:dcf9 --- | Determines the destination item for a given position. --- --- * Available since Gtk+ version 2.8 --- -iconViewGetDestItemAtPos :: IconViewClass self => self - -> Int -- ^ @dragX@ - the position to determine the - -- destination item for - -> Int -- ^ @dragY@ - the position to determine the - -- destination item for - -> {-GtkTreePath**-} -- ^ @path@ - Return location for the path of - -- the item, or {@NULL@, FIXME: this should - -- probably be converted to a Maybe data - -- type}. - -> {-GtkIconViewDropPosition*-} -- ^ @pos@ - Return location for the drop - -- position, or {@NULL@, FIXME: this should - -- probably be converted to a Maybe data type} - -> IO Bool -- ^ returns whether there is an item at the - -- given position. -iconViewGetDestItemAtPos self dragX dragY path pos = - liftM toBool $ - {# call gtk_icon_view_get_dest_item_at_pos #} - (toIconView self) - (fromIntegral dragX) - (fromIntegral dragY) - {-path-} - {-pos-} - --} - --- %hash c:e65a d:3e9 --- | Creates a 'Pixmap' representation of the item at @path@. This image is --- used for a drag icon. --- --- * Available since Gtk+ version 2.8 --- -iconViewCreateDragIcon :: IconViewClass self => self - -> TreePath -- ^ @path@ - a 'TreePath' in @iconView@ - -> IO Pixmap -- ^ returns a pixmap of the drag icon. -iconViewCreateDragIcon self path = - constructNewGObject mkPixmap $ - withTreePath path $ \path -> - {# call gtk_icon_view_create_drag_icon #} - (toIconView self) - path |
From: Axel S. <A....@ke...> - 2007-12-04 21:36:23
|
Tue Dec 4 13:34:21 PST 2007 A....@ke... * Docu fixes. hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 224 -import Graphics.UI.Gtk.Gdk.Events (Modifier(..))[_^I_][_^I_][_^I_][_^I_][_^I_] [_$_] +import Graphics.UI.Gtk.Gdk.Events (Modifier(..)) hunk ./gtk/Graphics/UI/Gtk/ModelView/TreeView.chs.pp 779 --- * Set whether the user can use drag and drop (DND) to reorder the --- rows in the store. This works on both 'TreeStore' and --- 'ListStore' models. If @ro@ is @True@, then the --- user can reorder the model by dragging and dropping rows. The --- developer can listen to these changes by connecting to the model's --- signals. This function does not give you any degree of control over --- the order -- any reorderering is allowed. If more control is needed, --- you should probably handle drag and drop manually. +-- * Set whether the user can use drag and drop (DND) to reorder the rows in +-- the store. This works on both 'TreeStore' and 'ListStore' models. If @ro@ +-- is @True@, then the user can reorder the model by dragging and dropping +-- rows. The developer can listen to these changes by connecting to the +-- model's signals. If you need to control which rows may be dragged or +-- where rows may be dropped, you can override the +-- 'Graphics.UI.Gtk.ModelView.CustomStore.treeDragSourceRowDraggable' +-- function in the default DND implementation of the model. |
From: Axel S. <A....@ke...> - 2007-12-02 21:47:23
|
Fri Nov 30 09:56:03 PST 2007 hth...@zo... * Tutorial-Port Introduction (Chapter 1) addfile ./docs/tutorial/Tutorial_Port/chap1.xhtml hunk ./docs/tutorial/Tutorial_Port/chap1.xhtml 1 - +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Gtk2Hs Tutorial: Introduction</title> + <link href="default.css" type="text/css" rel="stylesheet" /> +</head> + +<body> + +<div id="header"> + <h1>Gtk2Hs Tutorial</h1> + <span class="nav-previous"><!-- a href="chap1.xhtml" --><br /> </span> + <span class="nav-home"><a href="index.xhtml">Home</a></span> + <span class="nav-next"><a href="chap2.xhtml">Next</a></span> +</div> + +<h2>1. Introduction</h2> +<p>From the Gtk2Hs web site: Gtk2Hs is a GUI library for Haskell based on Gtk+. [_$_] +Gtk+ is an extensive and mature multi-platform toolkit for creating graphical user interfaces.</p> +<p>This tutorial is aimed at the intermediate level Haskell programmer, and covers what is +needed to write the most common GUI interfaces. This is summed up by the table of contents of this +tutorial. For advanced users, however, the Gtk2Hs API documentation contains much more.</p> +<p>Gtk+ is largely a library of components called 'widgets', which are organized in an object +oriented hierarchy. In Gtk2Hs this is implemented by giving each widget both a Haskell type and a Haskell [_$_] +type class. Thus the Haskell type system is rigorously preserved, and the programmer has all [_$_] +the advantages of Haskell type checking by the Glasgow Haskell compiler and interpreter. Gtk2Hs also [_$_] +has many functions for type casting.</p> +<p>Widgets have attributes which control their behavior and appearance. There are two general functions +to get and to set attributes. </p> +<p>To set one or more attributes of a widget use:</p> +<pre class="codebox">set widget [widgetAttr1 := foo, widgetAttr2 := fie, widgetAttr3 := bar]</pre> +<p>To get an attribute of a widget use:</p> +<pre class="codebox">x <- get widget widgetAttr1</pre> +<p>Almost always there are specific functions to set and get widget attributes too, but in future +these will be deprecated. For now, however, use of the functions is more common.</p> +<p>What happens in a Gtk2Hs application is determined by user actions, like mouse clicks, button +presses, selection of radio buttons and so on. These are called events and may result in signals + being emitted. Information about events, for example whether the user clicked a right or left + mouse button, may be captured in data fields that can be queried by the Gtk2Hs programmer. + Signals are usually handled by specific functions for that type of widget. They are listed + in the <strong>Signals</strong> section of the API documentation for that widget. [_$_] + Most take a function of type <code>IO ()</code> as parameter, but many have some result. + The Gtk2Hs programmer, of course, must write these parameter functions, which determine the response + to the user action.</p> + <p>Finally, setting up a widget tree for your application and determining the visual + layout (packing) can be done visually with the Glade interface designer. Gtk2Hs fully + supports Glade and there is an introductory tutorial on the Gtk2Hs web site. Using Glade + is actually recommended over the programmatic approach which is described in this tutorial.</p> +<div id="footer"> + <span class="nav-previous"><!-- a href="chap1.xhtml" --><br /> </span> + <span class="nav-home"><a href="index.xhtml">Home</a><br /> </span> + <span class="nav-next"><a href="chap2.xhtml">Next</a><br />2. Getting Started</span> +</div> + +</body> +</html> hunk ./docs/tutorial/Tutorial_Port/chap2.xhtml 14 - <span class="nav-previous"><!-- a href="chap1.xhtml" -->Previous<!-- /a --></span> + <span class="nav-previous"><a href="chap1.xhtml">Previous</a> </span> hunk ./docs/tutorial/Tutorial_Port/chap2.xhtml 183 - <span class="nav-previous"><!-- a href="chap1.xhtml" -->Previous<!-- /a --><br />1. Introduction</span> + <span class="nav-previous"><a href="chap1.xhtml">Previous</a><br />1. Introduction</span> hunk ./docs/tutorial/Tutorial_Port/chap7-2.xhtml 21 - <a href="chap8-1.xhtml">Next</a> + <!--a href="chap8-1.xhtml">Next</a--> hunk ./docs/tutorial/Tutorial_Port/chap7-2.xhtml 333 - <a href="chap8-1.xhtml">Next</a> - <br />8.1</span> + <!--a href="chap8-1.xhtml">Next</a--> + <br />The End</span> hunk ./docs/tutorial/Tutorial_Port/index.xhtml 29 - <a href="chap1.xhtml"></a>1. Introduction [_$_] - <em>— Not Available Yet</em></li> + <a href="chap1.xhtml">1. Introduction</a> [_$_] + </li> hunk ./docs/tutorial/Tutorial_Port/index.xhtml 151 - <!-- a href="chap1.xhtml" -->Next [_$_] - <!-- /a --> + <a href="chap1.xhtml">Next</a > |
From: Axel S. <A....@ke...> - 2007-12-02 21:39:09
|
Wed Nov 28 08:50:52 PST 2007 hth...@zo... * Tutorial-Port Popup, Radio and Toggle Actions (Chapter7.2) addfile ./docs/tutorial/Tutorial_Port/Example_Code/GtkChap7-2a.hs hunk ./docs/tutorial/Tutorial_Port/Example_Code/GtkChap7-2a.hs 1 +import Graphics.UI.Gtk + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Click Right Popup", + windowDefaultWidth := 250, + windowDefaultHeight := 150 ] + + eda <- actionNew "EDA" "Edit" Nothing Nothing + pra <- actionNew "PRA" "Process" Nothing Nothing + rma <- actionNew "RMA" "Remove" Nothing Nothing + saa <- actionNew "SAA" "Save" Nothing Nothing + + agr <- actionGroupNew "AGR1" [_$_] + mapM_ (actionGroupAddAction agr) [eda,pra,rma,saa] + + uiman <- uiManagerNew + uiManagerAddUiFromString uiman uiDecl + uiManagerInsertActionGroup uiman agr 0 + + maybePopup <- uiManagerGetWidget uiman "/ui/popup" + let pop = case maybePopup of [_$_] + (Just x) -> x + Nothing -> error "Cannot get popup from string" + + onButtonPress window (\x -> if (eventButton x) == RightButton + then do menuPopup (castToMenu pop) Nothing + return (eventSent x) + else return (eventSent x)) + + mapM_ prAct [eda,pra,rma,saa] + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +uiDecl = "<ui> \ +\ <popup>\ +\ <menuitem action=\"EDA\" />\ +\ <menuitem action=\"PRA\" />\ +\ <menuitem action=\"RMA\" />\ +\ <separator />\ +\ <menuitem action=\"SAA\" />\ +\ </popup>\ +\ </ui>" + +prAct :: ActionClass self => self -> IO (ConnectId self) +prAct a = onActionActivate a $ do name <- actionGetName a + putStrLn ("Action Name: " ++ name) addfile ./docs/tutorial/Tutorial_Port/Example_Code/GtkChap7-2b.hs hunk ./docs/tutorial/Tutorial_Port/Example_Code/GtkChap7-2b.hs 1 +import Graphics.UI.Gtk + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Radio and Toggle Actions", + windowDefaultWidth := 400, + windowDefaultHeight := 200 ] + [_$_] + mhma <- actionNew "MHMA" "Highlight\nMode" Nothing Nothing + msma <- actionNew "MSMA" "Source" Nothing Nothing + mmma <- actionNew "MMMA" "Markup" Nothing Nothing [_$_] + + agr1 <- actionGroupNew "AGR1" + mapM_ (actionGroupAddAction agr1) [mhma,msma,mmma] + actionGroupAddRadioActions agr1 hlmods 0 myOnChange + + vima <- actionNew "VIMA" "View" Nothing Nothing [_$_] + + agr2 <- actionGroupNew "AGR2" + actionGroupAddAction agr2 vima + actionGroupAddToggleActions agr2 togls + + uiman <- uiManagerNew + uiManagerAddUiFromString uiman uiDef1 + uiManagerInsertActionGroup uiman agr1 0 + + uiManagerAddUiFromString uiman uiDef2 + uiManagerInsertActionGroup uiman agr2 1 + + + mayMenubar <- uiManagerGetWidget uiman "/ui/menubar" + let mb = case mayMenubar of [_$_] + (Just x) -> x + Nothing -> error "Cannot get menu bar." + + mayToolbar <- uiManagerGetWidget uiman "/ui/toolbar" + let tb = case mayToolbar of [_$_] + (Just x) -> x + Nothing -> error "Cannot get tool bar." + + box <- vBoxNew False 0 + containerAdd window box + boxPackStart box mb PackNatural 0 + boxPackStart box tb PackNatural 0 + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +hlmods :: [RadioActionEntry] +hlmods = [ + RadioActionEntry "NOA" "None" Nothing Nothing Nothing 0, [_$_] + RadioActionEntry "SHA" "Haskell" (Just stockHome) Nothing Nothing 1, [_$_] + RadioActionEntry "SCA" "C" Nothing Nothing Nothing 2, + RadioActionEntry "SJA" "Java" Nothing Nothing Nothing 3, + RadioActionEntry "MHA" "HTML" Nothing Nothing Nothing 4, + RadioActionEntry "MXA" "XML" Nothing Nothing Nothing 5] + +myOnChange :: RadioAction -> IO () +myOnChange ra = do val <- radioActionGetCurrentValue ra + putStrLn ("RadioAction " ++ (show val) ++ " now active.") + +uiDef1 = " <ui> \ +\ <menubar>\ +\ <menu action=\"MHMA\">\ +\ <menuitem action=\"NOA\" />\ +\ <separator />\ +\ <menu action=\"MSMA\">\ +\ <menuitem action= \"SHA\" /> \ +\ <menuitem action= \"SCA\" /> \ +\ <menuitem action= \"SJA\" /> \ +\ </menu>\ +\ <menu action=\"MMMA\">\ +\ <menuitem action= \"MHA\" /> \ +\ <menuitem action= \"MXA\" /> \ +\ </menu>\ +\ </menu>\ +\ </menubar>\ +\ <toolbar>\ +\ <toolitem action=\"SHA\" />\ +\ </toolbar>\ +\ </ui> " + [_$_] + +togls :: [ToggleActionEntry] +togls = let mste = ToggleActionEntry "MST" "Messages" Nothing Nothing Nothing + (myTog mste) False [_$_] + ttte = ToggleActionEntry "ATT" "Attributes" Nothing Nothing Nothing + (myTog ttte) False [_$_] + erte = ToggleActionEntry "ERT" "Errors" (Just stockInfo) Nothing Nothing + (myTog erte) True [_$_] + in [mste,ttte,erte] + +myTog :: ToggleActionEntry -> IO () +myTog te = putStrLn ("The state of " ++ (toggleActionName te) [_$_] + ++ " (" ++ (toggleActionLabel te) ++ ") " [_$_] + ++ " is now " ++ (show $ not (toggleActionIsActive te))) + +uiDef2 = "<ui>\ +\ <menubar>\ +\ <menu action=\"VIMA\">\ +\ <menuitem action=\"MST\" />\ +\ <menuitem action=\"ATT\" />\ +\ <menuitem action=\"ERT\" />\ +\ </menu>\ +\ </menubar>\ +\ <toolbar>\ +\ <toolitem action=\"MST\" />\ +\ <toolitem action=\"ERT\" />\ +\ </toolbar>\ +\ </ui>" addfile ./docs/tutorial/Tutorial_Port/Images/GtkChap7-2.png binary ./docs/tutorial/Tutorial_Port/Images/GtkChap7-2.png hunk ./docs/tutorial/Tutorial_Port/chap7-1.xhtml 309 - <br />7.2</span> + <br />Popup Menus, Radio Actions and Toggle Actions</span> addfile ./docs/tutorial/Tutorial_Port/chap7-2.xhtml hunk ./docs/tutorial/Tutorial_Port/chap7-2.xhtml 1 +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <meta http-equiv="Content-Type" + content="text/html; charset=utf-8" /> + <title>Gtk2Hs Tutorial: Menus and Toolbars</title> + <link href="default.css" type="text/css" rel="stylesheet" /> + </head> + <body> + <div id="header"> + <h1>Gtk2Hs Tutorial</h1> + <span class="nav-previous"> + <a href="chap7-1.xhtml">Previous</a> + </span> + <span class="nav-home"> + <a href="index.xhtml">Home</a> + </span> + <span class="nav-next"> + <a href="chap8-1.xhtml">Next</a> + </span> + </div> + <h2>7.2 Popup Menus, Radio Actions and Toggle Actions</h2> + <p>Menus are normally just added to a window, but they can also + be displayed temporarily as the result of a mouse button click. + For instance, a context menu might be displayed when the user + clicks their right mouse button.</p> + <p>The UI layout for a popup menu should use the [_$_] + <code>popup</code> node. For instance:</p> + <pre class="codebox">uiDecl = "<ui> \ +\ <popup>\ +\ <menuitem action=\"EDA\" />\ +\ <menuitem action=\"PRA\" />\ +\ <menuitem action=\"RMA\" />\ +\ <separator />\ +\ <menuitem action=\"SAA\" />\ +\ </popup>\ +\ </ui>" [_$_] +</pre> + <p>Constructing a popup menu takes the same steps as a menu or + a toolbar (but also see below). Once you've created the actions [_$_] + and put them into one or more groups you create the ui manager, [_$_] + add the XML string and add the groups. Then you extract the widget(s). + In the pop up example we've created the 4 actions with the names + listed above. The popup menu doesn't show in a screen shot, so + we've omitted the picture.</p> + <p>Because it's a popup we don't pack the widget. To show it we + need the function:</p> + <pre class="codebox">menuPopup :: MenuClass self => self -> Maybe (MouseButton,TimeStamp) +</pre> + <p>This is documented in Graphics.UI.Gtk.MenuComboToolbar.Menu + in the API documentation. In the example we pop up the menu by + clicking the right mouse button, and the second argument can be [_$_] + <code>Nothing</code>. The function is the same as with the + event box in Chapter 6.2. Here, however, we can use the + window itself instead of an event box.</p> + <pre class="codebox">onButtonPress window (\x -> if (eventButton x) == RightButton + then do menuPopup (castToMenu pop) Nothing + return (eventSent x) + else return (eventSent x)) +</pre> + <p>The only hitch is that the widget returned by the ui manager + is of type <code>Widget</code>and the [_$_] + <code>menuPopup</code>function takes an argument of a type + which is an instance of <code>MenuClass</code>. So we have to use:</p> + <pre class="codebox">castToMenu :: GObjectClass obj => obj -> Menu +</pre> + <p>This function is also documented in the Graphics.UI.Gtk.MenuComboToolbar.Menu + section. The complete listing of the example is:</p> + <pre class="codebox"> +import Graphics.UI.Gtk + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Click Right Popup", + windowDefaultWidth := 250, + windowDefaultHeight := 150 ] + + eda <- actionNew "EDA" "Edit" Nothing Nothing + pra <- actionNew "PRA" "Process" Nothing Nothing + rma <- actionNew "RMA" "Remove" Nothing Nothing + saa <- actionNew "SAA" "Save" Nothing Nothing + + agr <- actionGroupNew "AGR1" [_$_] + mapM_ (actionGroupAddAction agr) [eda,pra,rma,saa] + + uiman <- uiManagerNew + uiManagerAddUiFromString uiman uiDecl + uiManagerInsertActionGroup uiman agr 0 + + maybePopup <- uiManagerGetWidget uiman "/ui/popup" + let pop = case maybePopup of [_$_] + (Just x) -> x + Nothing -> error "Cannot get popup from string" + + onButtonPress window (\x -> if (eventButton x) == RightButton + then do menuPopup (castToMenu pop) Nothing + return (eventSent x) + else return (eventSent x)) + + mapM_ prAct [eda,pra,rma,saa] + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +uiDecl = "<ui> \ +\ <popup>\ +\ <menuitem action=\"EDA\" />\ +\ <menuitem action=\"PRA\" />\ +\ <menuitem action=\"RMA\" />\ +\ <separator />\ +\ <menuitem action=\"SAA\" />\ +\ </popup>\ +\ </ui>" [_$_] + +prAct :: ActionClass self => self -> IO (ConnectId self) +prAct a = onActionActivate a $ do name <- actionGetName a + putStrLn ("Action Name: " ++ name) +</pre> + <p>There is another way to use actions, without explicitly + creating them, through the <code>ActionEntry</code> datatype:</p> + <pre class="codebox">data ActionEntry = ActionEntry { +actionEntryName :: String +actionEntryLabel :: String +actionEntryStockId :: (Maybe String) +actionEntryAccelerator :: (Maybe String) +actionEntryTooltip :: (Maybe String) +actionEntryCallback :: (IO ()) +} +</pre> + <p>The use of these fields is as their names indicate and as + has been described above and in Chapter 7.1. The [_$_] + <code>actionEntryCallback</code> function must be supplied by + the programmer, and will be executed when that particular + action is activated.</p> + <p>Add a list of entries to an action group with:</p> + <pre class="codebox">actionGroupAddActions :: ActionGroup -> [ActionEntry] -> IO () +</pre> + <p>The group then is inserted using [_$_] + <code>uiManagerInsertActionGroup</code> as before. </p> + <p>Similar functions exist for <code>RadioAction</code> and <code>ToggleAction</code> . + Radio actions let the user choose from a number of + possibilities, of which only one can be active. Because of this it makes sense [_$_] + to define them all together. The definition is:</p> + <pre class="codebox">data RadioActionEntry = RadioActionEntry { +radioActionName :: String +radioActionLabel :: String +radioActionStockId :: (Maybe String) +radioActionAccelerator :: (Maybe String) +radioActionTooltip :: (Maybe String) +radioActionValue :: Int +} +</pre> + <p>The first 5 fields are again used as expected. The [_$_] + <code>radioActionValue</code> identifies each of the possible + selections. Addition to a group is done with:</p> + <pre class="codebox">actionGroupAddRadioActions :: [_$_] + ActionGroup -> [RadioActionEntry] -> Int -> (RadioAction -> IO ()) -> IO () +</pre> + <p>The [_$_] + <code>Int</code> parameter is the value of the action to + activate initially, or -1 for none.</p> + <p class="notebox"> + <strong>Note:</strong> In the example below this appeared to + have no effect; the last action is always selected + initially.</p> + <p>The function of type [_$_] + <code>(RadioAction -> IO ())</code>is executed whenever that + action is activated.</p> + <p>Toggle actions have a [_$_] + <code>Bool</code> value and each may be set or not. The [_$_] + <code>ToggleActionEntry</code> is defined as:</p> + <pre class="codebox">data ToggleActionEntry = ToggleActionEntry { +toggleActionName :: String +toggleActionLabel :: String +toggleActionStockId :: (Maybe String) +toggleActionAccelerator :: (Maybe String) +toggleActionTooltip :: (Maybe String) +toggleActionCallback :: (IO ()) +toggleActionIsActive :: Bool +} +</pre> + <p>The example below demonstrates the use of toggle + actions as well as radio actions.</p> + <p class="notebox"> + <strong>Note:</strong> The [_$_] + <code>toggleActionCallback</code> function has the wrong + value on my platform; the workaround is, of course, to use the + <code>not</code> function.</p> + <img src="Images/GtkChap7-2.png" + alt="RadioAction and ToggleAction" id="imgGtkChap7-2" /> + <p>The radio buttons could control a highlight mode, as in the + gedit text editor, from which this was copied. The first menu + has one button and two sub menus which contain the remaining + items. Furthermore, one of the radio buttons is an item in a + tool bar. This layout is controlled completely by the first XML + definition.</p> + <p>The toggle actions are items in another menu, and two of + those are also placed in a toolbar. This layout is determined by + the second XML definition.</p> + <p>The interesting thing is that the [_$_] + <code>uiManager</code> can merge these ui definitions just by + adding them, as shown below. So you can define your menus in separate modules + and easily combine them later in the main module. According to + the documentation the ui manager is quite smart at this, and of + course you can also use names in the XML definitions to + distinguish paths. But recall that the [_$_] + <code>String</code> denoting an action name must be unique for each action.</p> + <p>It is also possible to unmerge menus and toolbars, using the [_$_] + <code>MergeId</code> and the <code>uiManagerRemoveUi</code> function. [_$_] + In this way you can manage menus and toolbars dynamically.</p> + <pre class="codebox"> +import Graphics.UI.Gtk + +main :: IO () +main= do + initGUI + window <- windowNew + set window [windowTitle := "Radio and Toggle Actions", + windowDefaultWidth := 400, + windowDefaultHeight := 200 ] + [_$_] + mhma <- actionNew "MHMA" "Highlight\nMode" Nothing Nothing + msma <- actionNew "MSMA" "Source" Nothing Nothing + mmma <- actionNew "MMMA" "Markup" Nothing Nothing [_$_] + + agr1 <- actionGroupNew "AGR1" + mapM_ (actionGroupAddAction agr1) [mhma,msma,mmma] + actionGroupAddRadioActions agr1 hlmods 0 myOnChange + + vima <- actionNew "VIMA" "View" Nothing Nothing [_$_] + + agr2 <- actionGroupNew "AGR2" + actionGroupAddAction agr2 vima + actionGroupAddToggleActions agr2 togls + + uiman <- uiManagerNew + uiManagerAddUiFromString uiman uiDef1 + uiManagerInsertActionGroup uiman agr1 0 + + uiManagerAddUiFromString uiman uiDef2 + uiManagerInsertActionGroup uiman agr2 1 + + mayMenubar <- uiManagerGetWidget uiman "/ui/menubar" + let mb = case mayMenubar of [_$_] + (Just x) -> x + Nothing -> error "Cannot get menu bar." + + mayToolbar <- uiManagerGetWidget uiman "/ui/toolbar" + let tb = case mayToolbar of [_$_] + (Just x) -> x + Nothing -> error "Cannot get tool bar." + + box <- vBoxNew False 0 + containerAdd window box + boxPackStart box mb PackNatural 0 + boxPackStart box tb PackNatural 0 + + widgetShowAll window + onDestroy window mainQuit + mainGUI + +hlmods :: [RadioActionEntry] +hlmods = [ + RadioActionEntry "NOA" "None" Nothing Nothing Nothing 0, [_$_] + RadioActionEntry "SHA" "Haskell" (Just stockHome) Nothing Nothing 1, [_$_] + RadioActionEntry "SCA" "C" Nothing Nothing Nothing 2, + RadioActionEntry "SJA" "Java" Nothing Nothing Nothing 3, + RadioActionEntry "MHA" "HTML" Nothing Nothing Nothing 4, + RadioActionEntry "MXA" "XML" Nothing Nothing Nothing 5] + +myOnChange :: RadioAction -> IO () +myOnChange ra = do val <- radioActionGetCurrentValue ra + putStrLn ("RadioAction " ++ (show val) ++ " now active.") + +uiDef1 = " <ui> \ +\ <menubar>\ +\ <menu action=\"MHMA\">\ +\ <menuitem action=\"NOA\" />\ +\ <separator />\ +\ <menu action=\"MSMA\">\ +\ <menuitem action= \"SHA\" /> \ +\ <menuitem action= \"SCA\" /> \ +\ <menuitem action= \"SJA\" /> \ +\ </menu>\ +\ <menu action=\"MMMA\">\ +\ <menuitem action= \"MHA\" /> \ +\ <menuitem action= \"MXA\" /> \ +\ </menu>\ +\ </menu>\ +\ </menubar>\ +\ <toolbar>\ +\ <toolitem action=\"SHA\" />\ +\ </toolbar>\ +\ </ui> " [_$_] + +togls :: [ToggleActionEntry] +togls = let mste = ToggleActionEntry "MST" "Messages" Nothing Nothing Nothing (myTog mste) False [_$_] + ttte = ToggleActionEntry "ATT" "Attributes" Nothing Nothing Nothing (myTog ttte) False [_$_] + erte = ToggleActionEntry "ERT" "Errors" (Just stockInfo) Nothing Nothing (myTog erte) True [_$_] + in [mste,ttte,erte] + +myTog :: ToggleActionEntry -> IO () +myTog te = putStrLn ("The state of " ++ (toggleActionName te) [_$_] + ++ " (" ++ (toggleActionLabel te) ++ ") " [_$_] + ++ " is now " ++ (show $ not (toggleActionIsActive te))) +uiDef2 = "<ui>\ +\ <menubar>\ +\ <menu action=\"VIMA\">\ +\ <menuitem action=\"MST\" />\ +\ <menuitem action=\"ATT\" />\ +\ <menuitem action=\"ERT\" />\ +\ </menu>\ +\ </menubar>\ +\ <toolbar>\ +\ <toolitem action=\"MST\" />\ +\ <toolitem action=\"ERT\" />\ +\ </toolbar>\ +\ </ui>" +</pre> + <div id="footer"> + <span class="nav-previous"> + <a href="chap7-1.xhtml">Previous</a> + <br />7.1 Menus and Toolbars</span> + <span class="nav-home"> + <a href="index.xhtml">Home</a> + </span> + <span class="nav-next"> + <a href="chap8-1.xhtml">Next</a> + <br />8.1</span> + </div> + </body> +</html> hunk ./docs/tutorial/Tutorial_Port/index.xhtml 109 + </li> + <li> + <a href="chap7-2.xhtml">7.2 Popup Menus, Radio Actions and Toggle Actions</a> |