summaryrefslogtreecommitdiff
path: root/src/Gtk/Widgets.icl
blob: c63eabf0ff02660e46e7502898b6e44d81354b55 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
implementation module Gtk.Widgets

import StdEnv
import StdMaybe

import Control.Monad
import Data.Functor
import Data.Tuple
import System.FilePath
import System._Pointer
from Text import class Text(split), instance Text String
import qualified Text

import Gtk
import Gtk.Internal

:: GtkActionBar :== Pointer

instance gtkWidget GtkActionBar where gtkWidget ab = ab

newActionBar :: GtkM GtkActionBar
newActionBar = toStateR gtk_action_bar_new >>= show

packActionBar :: !GtkActionBar !GtkDirection !w -> GtkM w | gtkWidget w
packActionBar bar dir widget =
	toState
		(if dir=:StartToEnd gtk_action_bar_pack_start gtk_action_bar_pack_end
			bar
			(gtkWidget widget)) >>|
	pure widget

:: GtkBox :== Pointer

instance gtkWidget GtkBox where gtkWidget b = b
instance gtkContainer GtkBox where gtkContainer b = b
instance gtkOrientable GtkBox where gtkOrientable b = b

newBox :: !GtkOrientation !Int -> GtkM GtkBox
newBox orientation spacing =
	toStateR (gtk_box_new orientation=:Vertical spacing) >>=
	show

packBox :: !GtkBox !GtkDirection !GtkExpand !w -> GtkM w | gtkWidget w
packBox box direction expand widget =
	toState (if direction=:StartToEnd gtk_box_pack_start gtk_box_pack_end
		box (gtkWidget widget) expand=:Expand True 0) >>|
	pure widget

instance tune GtkBox GtkSpacing
where
	tune (Spacing s) box = toState (gtk_box_set_spacing box s) >>| pure box

:: GtkButton :== Pointer

instance gtkWidget GtkButton where gtkWidget b = b
instance ptr GtkButton
where
	toPtr   b = b
	fromPtr b = b

newButtonFromIconName :: !String -> GtkM GtkButton
newButtonFromIconName icon =
	toStateR (gtk_button_new_from_icon_name icon (toInt ButtonIconSize)) >>=
	show

:: GtkContainer :== Pointer

instance gtkWidget GtkContainer where gtkWidget c = c
instance gtkContainer GtkContainer where gtkContainer c = c

instance ptr GtkContainer
where
	toPtr   c = c
	fromPtr c = c

addToContainer :: !c !w -> GtkM w | gtkWidget w & gtkContainer c
addToContainer container widget =
	toState (gtk_container_add (gtkContainer container) (gtkWidget widget)) >>|
	pure widget

:: GtkDialog :== Pointer

instance gtkWidget GtkDialog where gtkWidget d = d
instance gtkContainer GtkDialog where gtkContainer d = d
instance gtkWindow GtkDialog where gtkWindow w = w
instance gtkDialog GtkDialog where gtkDialog d = d

instance ptr GtkDialog
where
	toPtr   d = d
	fromPtr d = d

instance tune d GtkModal | gtkDialog d
where
	tune setting dialog =
		toState (gtk_dialog_set_modal (gtkDialog dialog) setting=:Modal) >>|
		pure dialog

newDialog :: !GtkWindow -> GtkM GtkDialog
newDialog window =
	toStateR gtk_dialog_new >>= \dialog ->
	toState (gtk_window_set_transient_for dialog window) >>|
	pure dialog

runDialog :: !d -> GtkM GtkResponse | gtkDialog d
runDialog dialog = fromInt <$> toStateR (gtk_dialog_run (gtkDialog dialog))

getContentArea :: !d -> GtkBox | gtkDialog d
getContentArea dialog = gtk_dialog_get_content_area (gtkDialog dialog)

newMessageDialog :: !GtkWindow !GtkMessageType !GtkButtonsType !String -> GtkM GtkDialog
newMessageDialog window type buttons text =
	toStateR (gtk_message_dialog_new_with_markup
		window
		1 /* DESTROY_WITH_PARENT */
		(toInt type)
		(toInt buttons)
		text)

getFileWithDialog :: !GtkWindow !GtkFileChooserAction !(Maybe String) -> GtkM (Maybe FilePath)
getFileWithDialog window action title =
	toStateR (gtk_file_chooser_dialog_new title window (toInt action) buttons) >>= \dialog ->
	toState (gtk_dialog_set_default_response dialog (toInt ResponseAccept)) >>|
	run dialog
where
	buttons = map (\(s,r) -> (s,toInt r)) case action of
		OpenAction         -> [("Cancel", ResponseCancel), ("Open",   ResponseAccept)]
		SaveAction         -> [("Cancel", ResponseCancel), ("Save",   ResponseAccept)]
		SelectFolderAction -> [("Cancel", ResponseCancel), ("Select", ResponseAccept)]
		CreateFolderAction -> [("Cancel", ResponseCancel), ("Create", ResponseAccept)]

	run dialog =
		runDialog dialog >>= \response -> case response of
			ResponseAccept ->
				toStateR (gtk_file_chooser_get_filename dialog) >>= \file_name -> case file_name of
					Just _  -> destroy dialog >>| pure file_name
					Nothing -> run dialog
			_ ->
				destroy dialog >>|
				pure Nothing

:: GtkFrame :== Pointer

instance gtkWidget GtkFrame where gtkWidget f = f
instance gtkContainer GtkFrame where gtkContainer f = f
instance ptr GtkFrame
where
	toPtr   f = f
	fromPtr f = f

newFrame :: !GtkTitle !w -> GtkM GtkFrame | gtkWidget w
newFrame (Title title) widget =
	toStateR (gtk_frame_new (case title of "" -> Nothing; _ -> Just title)) >>= \frame ->
	(case title of
		"" -> pure ()
		_  -> toState (gtk_frame_set_label_align frame 0.02 0.5)) >>|
	addToContainer frame widget >>|
	show frame

framed :: !GtkTitle !(GtkM w) -> GtkM (w, GtkFrame) | gtkWidget w
framed title widgetf =
	widgetf >>= \widget ->
	tuple widget <$> newFrame title widget

:: GtkGrid :== Pointer

instance gtkWidget GtkGrid where gtkWidget g = g

newGrid :: GtkM GtkGrid
newGrid = toStateR gtk_grid_new >>= show

attachGrid :: !GtkGrid !(!Int,!Int) !(!Int,!Int) !w -> GtkM w | gtkWidget w
attachGrid grid (left,top) (width,height) widget =
	toState (gtk_grid_attach grid (gtkWidget widget) left top width height) >>|
	pure widget

:: GtkLabel :== Pointer

instance gtkWidget GtkLabel where gtkWidget l = l

newLabel :: GtkM GtkLabel
newLabel = toStateR gtk_label_new >>= show

instance tune GtkLabel GtkText
where
	tune (Text text) label =
		toState (gtk_label_set_markup label text) >>|
		pure label

:: GtkListStore :== Pointer

newListStore :: ![GType] -> GtkM GtkListStore
newListStore types = toStateR (gtk_list_store_newv {toInt t \\ t <- types})

clearListStore :: !GtkListStore -> GtkM GtkListStore
clearListStore store =
	toState (gtk_list_store_clear store) >>|
	pure store

appendToListStore :: ![GValue] !GtkListStore -> GtkM GtkListStore
appendToListStore values store =
	set 0 values (gtk_list_store_append store) >>|
	pure store
where
	set :: !Int ![GValue] !.{#Int} -> GtkM ()
	set col [v:vs] iter = set` >>| set (col+1) vs iter
	where
		set` = case v of
			GValueBool b   -> toState (gtk_list_store_set_bool   store iter col b)
			GValueChar c   -> toState (gtk_list_store_set_char   store iter col c)
			GValueInt i    -> toState (gtk_list_store_set_int    store iter col i)
			GValueReal r   -> toState (gtk_list_store_set_real   store iter col r)
			GValueString s -> toState (gtk_list_store_set_string store iter col s)
	set _ [] _ = pure ()

swapItems :: !Int !Int !GtkListStore -> GtkM Bool
swapItems a b store =
	let
		(ok_a,iter_a) = gtk_tree_model_get_iter_from_string store (toString a)
		(ok_b,iter_b) = gtk_tree_model_get_iter_from_string store (toString b)
	in
	if (ok_a && ok_b)
		(toState (gtk_list_store_swap store iter_a iter_b) >>| pure True)
		(pure False)

:: GtkMenu :== Pointer

instance gtkWidget GtkMenu where gtkWidget m = m

newMenu :: GtkM GtkMenu
newMenu = toStateR gtk_menu_new >>= show

:: GtkMenuBar :== Pointer

instance gtkWidget GtkMenuBar where gtkWidget mb = mb

newMenuBar :: GtkM GtkMenuBar
newMenuBar = toStateR gtk_menu_bar_new >>= show

:: GtkMenuItem :== Pointer

instance gtkWidget GtkMenuItem where gtkWidget mi = mi
instance gtkMenuItem GtkMenuItem where gtkMenuItem mi = mi

newMenuItem :: !String -> GtkM GtkMenuItem
newMenuItem label =
	toStateR gtk_menu_item_new >>= \item ->
	toState (gtk_menu_item_set_label item label) >>|
	toState (gtk_menu_item_set_use_underline item True) >>|
	show item

setSubMenu :: !mi !GtkMenu -> GtkM GtkMenu | gtkMenuItem mi
setSubMenu item menu =
	toState (gtk_menu_item_set_submenu (gtkMenuItem item) menu) >>|
	pure menu

:: GtkCheckMenuItem :== Pointer

instance gtkWidget GtkCheckMenuItem where gtkWidget cmi = cmi
instance gtkMenuItem GtkCheckMenuItem where gtkMenuItem cmi = cmi
instance ptr GtkCheckMenuItem
where
	toPtr   cmi = cmi
	fromPtr cmi = cmi

newCheckMenuItem :: !String -> GtkM GtkCheckMenuItem
newCheckMenuItem label =
	toStateR gtk_check_menu_item_new >>= \item ->
	toState (gtk_menu_item_set_label item label) >>|
	toState (gtk_menu_item_set_use_underline item True) >>|
	show item

isActive :: !GtkCheckMenuItem -> GtkM Bool
isActive item = toStateR (gtk_check_menu_item_get_active item)

setActive :: !Bool !GtkCheckMenuItem -> GtkM GtkCheckMenuItem
setActive active item =
	toState (gtk_check_menu_item_set_active item active) >>|
	pure item

:: GtkMenuShell :== Pointer

instance gtkWidget GtkMenuShell where gtkWidget ms = ms

instance gtkMenuShell GtkMenu where gtkMenuShell m = m
instance gtkMenuShell GtkMenuBar where gtkMenuShell mb = mb
instance gtkMenuShell GtkMenuShell where gtkMenuShell ms = ms

appendToMenuShell :: !s !mi -> GtkM mi | gtkMenuShell s & gtkMenuItem mi
appendToMenuShell shell item =
	toState (gtk_menu_shell_append (gtkMenuShell shell) (gtkMenuItem item)) >>|
	pure item

:: GtkOrientable :== Pointer

instance tune o GtkOrientation | gtkOrientable o
where
	tune orientation orientable =
		toState (gtk_orientable_set_orientation (gtkOrientable orientable) orientation=:Vertical) >>|
		pure orientable

:: GtkPaned :== Pointer

instance gtkWidget GtkPaned where gtkWidget p = p
instance gtkContainer GtkPaned where gtkContainer p = p

newPaned :: !GtkOrientation !GtkPanedHandleWidth -> GtkM GtkPaned
newPaned orientation handle_width =
	toStateR (gtk_paned_new orientation=:Vertical) >>= \paned ->
	toState (gtk_paned_set_wide_handle paned handle_width=:WideHandle) >>|
	show paned

packPane1 :: !GtkPaned !GtkResize !GtkShrink !w -> GtkM w | gtkWidget w
packPane1 paned resize shrink widget =
	toState (gtk_paned_pack1 paned (gtkWidget widget) resize=:Resize shrink=:Shrink) >>|
	pure widget

packPane2 :: !GtkPaned !GtkResize !GtkShrink !w -> GtkM w | gtkWidget w
packPane2 paned resize shrink widget =
	toState (gtk_paned_pack2 paned (gtkWidget widget) resize=:Resize shrink=:Shrink) >>|
	pure widget

:: GtkScrolledWindow :== Pointer

instance gtkWidget GtkScrolledWindow where gtkWidget sw = sw
instance gtkContainer GtkScrolledWindow where gtkContainer sw = sw

newScrolledWindow :: GtkM GtkScrolledWindow
newScrolledWindow = toStateR (gtk_scrolled_window_new 0 0) >>= show

instance tune GtkScrolledWindow (GtkScrollbarPolicy, GtkScrollbarPolicy)
where
	tune (hp,vp) window =
		toState (gtk_scrolled_window_set_policy window (toInt hp) (toInt vp)) >>|
		pure window

:: GtkSeparator :== Pointer

instance gtkWidget GtkSeparator where gtkWidget s = s
instance ptr GtkSeparator
where
	toPtr   s = s
	fromPtr s = s

newSeparator :: !GtkOrientation -> GtkM GtkSeparator
newSeparator orientation = toStateR (gtk_separator_new orientation=:Vertical) >>= show

:: GtkSpinner :== Pointer

instance gtkWidget GtkSpinner where gtkWidget s = s
instance ptr GtkSpinner
where
	toPtr   s = s
	fromPtr s = s

newSpinner :: GtkM GtkSpinner
newSpinner = toStateR gtk_spinner_new >>= show

startSpinner :: !GtkSpinner -> GtkM GtkSpinner
startSpinner spinner = toState (gtk_spinner_start spinner) >>| pure spinner

stopSpinner :: !GtkSpinner -> GtkM GtkSpinner
stopSpinner spinner = toState (gtk_spinner_stop spinner) >>| pure spinner

:: GtkTextBuffer :== Pointer

instance ptr GtkTextBuffer
where
	toPtr   b = b
	fromPtr b = b

setText :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
setText s buffer =
	toState (gtk_text_buffer_set_text buffer s (size s)) >>|
	pure buffer

setMarkup :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
setMarkup s buffer =
	toStateR (gtk_text_buffer_get_start_iter buffer) >>= \start ->
	toStateR (gtk_text_buffer_get_end_iter buffer) >>= \end ->
	toState (gtk_text_buffer_delete buffer start end) >>|
	toStateR (gtk_text_buffer_get_start_iter buffer) >>= \start ->
	toState (gtk_text_buffer_insert_markup buffer start s) >>|
	pure buffer

insertAtCursor :: !String !GtkTextBuffer -> GtkM GtkTextBuffer
insertAtCursor s buffer =
	toState (gtk_text_buffer_insert_at_cursor buffer s (size s)) >>|
	pure buffer

:: GtkTextView :== Pointer

instance gtkWidget GtkTextView where gtkWidget tv = tv
instance gtkContainer GtkTextView where gtkContainer tv = tv
instance ptr GtkTextView
where
	toPtr   tv = tv
	fromPtr tv = tv

newTextView :: GtkM GtkTextView
newTextView =
	toStateR gtk_text_view_new >>= \text_view ->
	toState (gtk_text_view_set_editable text_view False) >>|
	show text_view

getTextBuffer :: !GtkTextView -> GtkTextBuffer
getTextBuffer text_view = gtk_text_view_get_buffer text_view

instance tune GtkTextView GtkWrapMode
where
	tune mode text_view =
		toState (gtk_text_view_set_wrap_mode text_view (toInt mode)) >>|
		pure text_view

:: GtkTreeView :== Pointer

instance gtkWidget GtkTreeView where gtkWidget tv = tv

newTreeView :: !GtkListStore -> GtkM GtkTreeView
newTreeView store =
	toStateR (gtk_tree_view_new_with_model store) >>= \view ->
	toState (g_object_unref store) >>|
	show view

appendColumnToTreeView :: !String !Int !GtkExpand !GtkTreeView -> GtkM GtkTreeView
appendColumnToTreeView title col expand tree_view =
	toStateR gtk_cell_renderer_text_new >>= \renderer ->
	toStateR gtk_tree_view_column_new >>= \column ->
	toState (gtk_tree_view_column_set_title column title) >>|
	toState (gtk_tree_view_column_pack_start column renderer expand=:Expand) >>|
	toState (gtk_tree_view_column_add_attribute column renderer "text" col) >>|
	toState (gtk_tree_view_append_column tree_view column) >>|
	pure tree_view

addSelectionChangedHandler :: !(GtkM ()) !GtkTreeView -> GtkM GtkTreeView
addSelectionChangedHandler handler tree =
	let selection = gtk_tree_view_get_selection tree in
	tune (ChangedHandler handler) selection >>|
	pure tree

getPathToSelection :: !GtkTreeView -> GtkM (Maybe [Int])
getPathToSelection tree =
	let selection = gtk_tree_view_get_selection tree in
	toStateR (gtk_tree_selection_get_selected selection) >>= \(selected,iter)
		| not selected ->
			pure Nothing
		| otherwise ->
			let
				model = gtk_tree_view_get_model tree
				path = gtk_tree_model_get_string_from_iter model iter
			in
			pure (Just [toInt part \\ part <- split ":" path])

selectPath :: ![Int] !GtkTreeView -> GtkM Bool
selectPath path tree =
	let
		store = gtk_tree_view_get_model tree
		selection = gtk_tree_view_get_selection tree
		(ok,iter) = gtk_tree_model_get_iter_from_string store ('Text'.join ":" [toString i \\ i <- path])
	in
	if ok
		(toState (gtk_tree_selection_select_iter selection iter) >>| pure True)
		(pure False)

:: GtkWidget :== Pointer

instance gtkWidget GtkWidget where gtkWidget w = w

instance ptr GtkWidget
where
	toPtr   w = w
	fromPtr w = w

show :: !w -> GtkM w | gtkWidget w
show widget = toState (gtk_widget_show (gtkWidget widget)) >>| pure widget

hide :: !w -> GtkM w | gtkWidget w
hide widget = toState (gtk_widget_hide (gtkWidget widget)) >>| pure widget

destroy :: !w -> GtkM () | gtkWidget w
destroy widget = toState (gtk_widget_destroy (gtkWidget widget))

addCSSClass :: !GtkCSSClass !w -> GtkM w | gtkWidget w
addCSSClass (Class cls) widget =
	toStateR (gtk_widget_get_style_context (gtkWidget widget)) >>= \context ->
	toState (gtk_style_context_add_class context cls) >>|
	pure widget

removeCSSClass :: !GtkCSSClass !w -> GtkM () | gtkWidget w
removeCSSClass (Class cls) widget =
	toStateR (gtk_widget_get_style_context (gtkWidget widget)) >>= \context ->
	toState (gtk_style_context_remove_class context cls)

setMargins :: !GtkMargins !w -> GtkM w | gtkWidget w
setMargins {left,top,right,bottom} widget` =
	let widget = gtkWidget widget` in
	toState (gtk_widget_set_margin_left   widget left)   >>|
	toState (gtk_widget_set_margin_top    widget top)    >>|
	toState (gtk_widget_set_margin_right  widget right)  >>|
	toState (gtk_widget_set_margin_bottom widget bottom) >>|
	pure widget`

instance tune w GtkSensitivity | gtkWidget w
where
	tune sens widget =
		toState (gtk_widget_set_sensitive (gtkWidget widget) sens=:Sensitive) >>|
		pure widget

instance tune w (GtkAlign,GtkAlign) | gtkWidget w
where
	tune (halign,valign) widget =
		let ptr = gtkWidget widget in
		toState (gtk_widget_set_halign ptr (toInt halign)) >>|
		toState (gtk_widget_set_valign ptr (toInt valign)) >>|
		pure widget

:: GtkWindow :== Pointer

instance gtkWidget GtkWindow where gtkWidget w = w
instance gtkContainer GtkWindow where gtkContainer w = w
instance gtkWindow GtkWindow where gtkWindow w = w

newPopup :: !(Maybe (Int,Int)) -> GtkM GtkWindow
newPopup size = new_window_or_popup True size

newWindow :: !(Maybe (Int,Int)) -> GtkM GtkWindow
newWindow size = new_window_or_popup False size

new_window_or_popup :: !Bool !(Maybe (Int,Int)) -> GtkM GtkWindow
new_window_or_popup is_popup size =
	toStateR (gtk_window_new is_popup) >>= \window ->
	(case size of
		Nothing    -> pure ()
		Just (h,v) -> toState (gtk_widget_set_size_request window h v)) >>|
	show window

instance tune w GtkTitle | gtkWindow w
where
	tune (Title s) window =
		toState (gtk_window_set_title (gtkWindow window) s) >>|
		pure window

// NB: it is also possible to attach CSS to one widget in particular (excluding
// children widgets). You then use gtk_widget_get_style_context and gtk_style_
// context_add_provider instead of gtk_widget_get_screen and gtk_style_context_
// add_provider_for_screen. This functionality has not been added to this
// library yet, but there is no reason to not provide it. To be clear that this
// style is global, we only allow it on GtkWindow, even though it would work on
// any GtkWidget.
addCSSFromFile :: !GtkStylePriority !FilePath !GtkWindow -> GtkM Bool
addCSSFromFile priority path window =
	toStateR gtk_css_provider_new >>= \provider ->
	toStateR (gtk_css_provider_load_from_path provider path 0) >>= \ok
		| not ok -> pure ok
		| otherwise ->
			toStateR (gtk_widget_get_screen window) >>= \screen ->
			toState (gtk_style_context_add_provider_for_screen screen provider (toInt priority)) >>|
			pure True