diff --git a/src/GLib/GLib.jl b/src/GLib/GLib.jl index 951e68e1..f1a9c369 100644 --- a/src/GLib/GLib.jl +++ b/src/GLib/GLib.jl @@ -20,7 +20,7 @@ export Maybe export GList, GSList, glist_iter, _GSList, _GList, GError, GVariant, GType, GBoxed export GObject, GInitiallyUnowned, GInterface, GTypeInterface, _GTypeInterface, GParam, GTypeInstance export GByteArray, GHashTable, GPtrArray -export g_timeout_add, g_idle_add, @idle_add, @guarded, g_source_remove +export g_timeout_add, g_idle_add, @idle_add, @guarded, g_source_remove, cancel export cfunction_, on_notify, signalnames, signal_return_type, signal_argument_types export gobject_ref, signal_connect, signal_emit, signal_handler_disconnect export signal_handler_block, signal_handler_unblock diff --git a/src/GLib/gerror.jl b/src/GLib/gerror.jl index 06da0f65..5e10dca3 100644 --- a/src/GLib/gerror.jl +++ b/src/GLib/gerror.jl @@ -24,7 +24,7 @@ struct GErrorException <: Exception message::String end -GErrorException(err::GError) = GErrorException(err.domain, err.code, bytestring(err.message)) +GErrorException(err::GError) = GErrorException(err.domain, err.code, message(err)) function check_err(err::Base.RefValue{Ptr{GError}}) if err[] != C_NULL diff --git a/src/basic_exports.jl b/src/basic_exports.jl index accb473c..edd385ab 100644 --- a/src/basic_exports.jl +++ b/src/basic_exports.jl @@ -23,13 +23,14 @@ export open_dialog, save_dialog export info_dialog, ask_dialog, warn_dialog, error_dialog, input_dialog export color_dialog export response +export open_file, save_path, open_path, select_folder, select_folder_path, open_multiple, open_paths, select_multiple_folders, select_multiple_folder_paths export GListModel, changed, model, selected_string, selected_string! # GLib-imported event handling export signal_connect, signal_handler_disconnect, signal_handler_block, signal_handler_unblock, signal_handler_is_connected, - signal_emit, g_timeout_add, g_idle_add + signal_emit, g_timeout_add, g_idle_add, GCancellable, cancel export @guarded, @idle_add export start_main_loop, stop_main_loop diff --git a/src/cairo.jl b/src/cairo.jl index ca134a9e..e531e66f 100644 --- a/src/cairo.jl +++ b/src/cairo.jl @@ -16,9 +16,7 @@ function _init_canvas!(widget, w, h) end function _canvas_on_realize(::Ptr, canvas) - if canvas.is_sized - _canvas_on_resize(da,1,1) - end + canvas.is_sized && _canvas_on_resize(da,1,1) nothing end @@ -120,9 +118,7 @@ end Return the CairoContext of the `CairoSurface` backing store of a `GtkCanvas`. """ function getgc(c::GtkCanvas) - if !isdefined(c,:backcc) - error("GtkCanvas not yet initialized.") - end + isdefined(c,:backcc) || error("GtkCanvas not yet initialized.") return c.backcc end @@ -132,8 +128,6 @@ end Return the image `CairoSurface` backing store for a `GtkCanvas`. """ function cairo_surface(c::GtkCanvas) - if !isdefined(c,:back) - error("GtkCanvas not yet initialized.") - end + isdefined(c,:back) || error("GtkCanvas not yet initialized.") return c.back end diff --git a/src/deprecated.jl b/src/deprecated.jl index 791367b3..c524cf60 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -2,3 +2,5 @@ GtkAdjustment(spinButton::GtkSpinButton) = G_.get_adjustment(spinButton) GtkAdjustment(range::GtkRange) = G_.get_adjustment(range) GtkAdjustment(scale::GtkScaleButton) = G_.get_adjustment(scale) +setindex!(buffer::GtkEntryBuffer, content::String, ::Type{String}) = + G_.set_text(buffer, content, -1) diff --git a/src/events.jl b/src/events.jl index 7dd82f09..27f9b4ed 100644 --- a/src/events.jl +++ b/src/events.jl @@ -20,7 +20,7 @@ penalty for creating a list of a widget's event controllers. Related GTK function: [`gtk_widget_observe_controllers`](https://docs.gtk.org/gtk4/method.Widget.observe_controllers.html)) """ function find_controller(w::GtkWidget, ::Type{T}) where T<: GtkEventController - list = GListModel(G_.observe_controllers(w)) + list = observe_controllers(w) i=findfirst(c->isa(c,T), list) i!==nothing ? list[i] : nothing end diff --git a/src/input.jl b/src/input.jl index fe7d4714..2156ff24 100644 --- a/src/input.jl +++ b/src/input.jl @@ -10,7 +10,7 @@ function GtkEntryBuffer(initial_text = nothing) G_.EntryBuffer_new(initial_text, -1) end -setindex!(buffer::GtkEntryBuffer, content::String, ::Type{String}) = +setindex!(buffer::GtkEntryBuffer, content::String) = G_.set_text(buffer, content, -1) complete(completion::GtkEntryCompletion) = G_.complete(completion) diff --git a/src/layout.jl b/src/layout.jl index 980e271e..3ef8da68 100644 --- a/src/layout.jl +++ b/src/layout.jl @@ -201,9 +201,22 @@ end ## GtkFrame — A decorative frame and optional label +""" + GtkFrame(label=nothing; kwargs...) + +Create a `GtkFrame`, a layout widget that can hold a single child widget, with +an optional string `label`. Keyword arguments allow you to set GObject +properties. +""" GtkFrame(;kwargs...) = GtkFrame(nothing; kwargs...) -function GtkFrame(w::GtkWidget; kwargs...) - f = GtkFrame(; kwargs...) +""" + GtkFrame(w::GtkWidget, label=nothing; kwargs...) + +Create a `GtkFrame` with an optional string `label` and add `w` as its child. +Keyword arguments allow you to set GObject properties. +""" +function GtkFrame(w::GtkWidget, label=nothing; kwargs...) + f = GtkFrame(label; kwargs...) f[] = w f end @@ -269,6 +282,14 @@ function empty!(w::GtkNotebook) end ## GtkOverlay + +""" + GtkOverlay(w=nothing; kwargs...) + +Create a `GtkOverlay`, a layout widget that holds one main child and other +child "overlay" widgets that are drawn on top of the main child. The main child +can be set using the argument `w`. +""" function GtkOverlay(w::GtkWidget; kwargs...) o = GtkOverlay(; kwargs...) o[] = w diff --git a/src/windows.jl b/src/windows.jl index dd2ad4e1..9f4e92a9 100644 --- a/src/windows.jl +++ b/src/windows.jl @@ -621,17 +621,18 @@ end """ save_path(dlg, resobj) -Get the path selected by the user in a save dialog. +Get the path selected by the user in a save dialog. An exception will be thrown +if the user cancelled the operation. """ save_path(dlg, resobj) = _path_finish(Gtk4.G_.save_finish, dlg, resobj) """ - open(cb, dlg::GtkFileDialog, parent = nothing, cancellable = nothing) + open_file(cb, dlg::GtkFileDialog, parent = nothing, cancellable = nothing) Open a dialog to open a file. The callback `cb` will be called when the user selects a file. """ -function Base.open(cb, dlg::GtkFileDialog, parent = nothing, cancellable = nothing) +function open_file(cb, dlg::GtkFileDialog, parent = nothing, cancellable = nothing) G_.open(dlg, parent, cancellable, cb) end @@ -682,8 +683,8 @@ open_paths(dlg, resobj) = _path_multiple_finish(Gtk4.G_.open_multiple_finish, dl Open a dialog to select multiple folders. The callback `cb` will be called when the user is done selecting folders. """ -function select_multiple(cb, dlg::GtkFileDialog, parent = nothing, cancellable = nothing) - G_.select_multiple(dlg, parent, cancellable, cb) +function select_multiple_folders(cb, dlg::GtkFileDialog, parent = nothing, cancellable = nothing) + G_.select_multiple_folders(dlg, parent, cancellable, cb) end """ diff --git a/test/comboboxtext.jl b/test/comboboxtext.jl index 03800066..4505e155 100644 --- a/test/comboboxtext.jl +++ b/test/comboboxtext.jl @@ -3,7 +3,7 @@ using Gtk4 @testset "comboboxtext" begin @testset "populate with push!" begin - cbstr = GtkComboBoxText() + cbstr = GtkComboBoxText(false) push!(cbstr, "1", "abc") push!(cbstr, "2", "xyz") diff --git a/test/gdkpixbuf.jl b/test/gdkpixbuf.jl index 754baecb..5f3a5e41 100644 --- a/test/gdkpixbuf.jl +++ b/test/gdkpixbuf.jl @@ -2,11 +2,19 @@ using Test, Gtk4.GdkPixbufLib @testset "pixbuf" begin -pb=GdkPixbufLib.G_.Pixbuf_new(0,true,8,300,300) +pb=GdkPixbufLib.G_.Pixbuf_new(0,false,8,300,300) @test isa(pb,GdkPixbufLib.GdkPixbuf) @test 300 == width(pb) +x=fill(GdkPixbufLib.RGB(0xff,0xff,0xff),(3,3)) +pb[1:3,1:3]=x +@test pb[1,1] == GdkPixbufLib.RGB(0xff,0xff,0xff) +@test pb[1,3] == GdkPixbufLib.RGB(0xff,0xff,0xff) +@test pb[1,4] != GdkPixbufLib.RGB(0xff,0xff,0xff) +@test pb[3,1] == GdkPixbufLib.RGB(0xff,0xff,0xff) +@test pb[4,1] != GdkPixbufLib.RGB(0xff,0xff,0xff) + end @testset "Transparent pixbuf" begin @@ -16,3 +24,4 @@ icon[5:end-5, 3:end-3] .= Ref(GdkPixbufLib.RGBA(0,0,0xff,0x80)) pb=GdkPixbuf(icon, true) @test eltype(pb) == GdkPixbufLib.RGBA end + diff --git a/test/gui/canvas.jl b/test/gui/canvas.jl index 13cdbc41..bee5572b 100644 --- a/test/gui/canvas.jl +++ b/test/gui/canvas.jl @@ -1,6 +1,6 @@ using Test, Gtk4, Cairo -@testset "Canvas & AspectFrame" begin +@testset "Canvas, AspectFrame, and event controllers" begin c = GtkCanvas(100,100) f = GtkAspectFrame(0.5, 1, 0.5, false) f[] = c @@ -10,10 +10,16 @@ gs = GtkEventControllerScroll(Gtk4.EventControllerScrollFlags_VERTICAL,c) gk = GtkEventControllerKey(c) ggc = GtkGestureClick(c) ggd = GtkGestureDrag(c) +gsc = GtkShortcutController(c) ggz = GtkGestureZoom(c) t = Gtk4.find_controller(c,GtkEventControllerMotion) @test t==gm @test widget(gm) == c + +delete!(c, gk) +t = Gtk4.find_controller(c,GtkEventControllerKey) +@test t===nothing + drew = Ref(false) resized = Ref(false) c.draw = function(_) diff --git a/test/gui/dialogs.jl b/test/gui/dialogs.jl index c09c5331..b3af6eb2 100644 --- a/test/gui/dialogs.jl +++ b/test/gui/dialogs.jl @@ -83,3 +83,77 @@ csvfilter4 = GtkFileFilter("*.csv", "text/csv") @test csvfilter4.name == "*.csv" end +@testset "New dialogs" begin +main_window = GtkWindow("New dialog example") +fd=GtkFileDialog() + +c=GCancellable() +save(fd, main_window, c) do dlg, resobj + try + x=save_path(dlg, resobj) + catch e + if !isa(e, Gtk4.GLib.GErrorException) + rethrow(e) + end + end +end +sleep(1.0) +cancel(c) + +c=GCancellable() +open_file(fd, main_window, c) do dlg, resobj + try + x=open_path(dlg, resobj) + catch e + if !isa(e, Gtk4.GLib.GErrorException) + rethrow(e) + end + end +end +sleep(1.0) +cancel(c) + +c=GCancellable() +select_folder(fd, main_window, c) do dlg, resobj + try + x=select_folder_path(dlg, resobj) + catch e + if !isa(e, Gtk4.GLib.GErrorException) + rethrow(e) + end + end +end +sleep(1.0) +cancel(c) + +c=GCancellable() +open_multiple(fd, main_window, c) do dlg, resobj + try + x=open_paths(dlg, resobj) + catch e + if !isa(e, Gtk4.GLib.GErrorException) + rethrow(e) + end + end +end +sleep(1.0) +cancel(c) + +c=GCancellable() +select_multiple_folders(fd, main_window, c) do dlg, resobj + try + x=select_multiple_folder_paths(dlg, resobj) + catch e + if !isa(e, Gtk4.GLib.GErrorException) + rethrow(e) + end + end +end +sleep(1.0) +cancel(c) + + +sleep(2.0) + +close(main_window) +end diff --git a/test/gui/input.jl b/test/gui/input.jl index bf18c4cb..1530c307 100644 --- a/test/gui/input.jl +++ b/test/gui/input.jl @@ -63,6 +63,8 @@ set_gtk_property!(e,:sensitive,false) b = GtkEntryBuffer("different") buffer(e, b) @test e.text == "different" +b[] = "new text" +@test e.text == "new text" @test fraction(e) == 0.0 fraction(e, 1.0) diff --git a/test/gui/layout.jl b/test/gui/layout.jl index b0fbcff1..3b2fce42 100644 --- a/test/gui/layout.jl +++ b/test/gui/layout.jl @@ -111,6 +111,8 @@ end l4 = GtkLabel("Named #2") s["named2"] = l4 @test s["named2"] == l4 + delete!(s,s["named2"]) + empty!(s) destroy(w) end diff --git a/test/gui/listviews.jl b/test/gui/listviews.jl index b2d2602f..1cf7896a 100644 --- a/test/gui/listviews.jl +++ b/test/gui/listviews.jl @@ -49,6 +49,13 @@ destroy(win) end +function match(item) + label = item.child + return startswith(label.label, "widget") +end + +alpha_compare(item1, item2) = isless(item1.child.label, item2.child.label) ? -1 : 1 + @testset "ListBox" begin win = GtkWindow("ListBox demo with filter") box = GtkBox(:v) @@ -77,6 +84,10 @@ listBox[1] = GtkLabel("widget 2") sw[] = listBox listBox.vexpand = true +Gtk4.set_filter_func(listBox, nothing) +Gtk4.set_sort_func(listBox, nothing) +Gtk4.set_sort_func(listBox, alpha_compare) + # while we're at it, test GtkExpression pe = GtkPropertyExpression(GtkWindow, "title") rgv=Ref(GLib.GValue()) @@ -122,7 +133,25 @@ listBox[1] = GtkLabel("widget 2") sw[] = listBox listBox.vexpand = true +Gtk4.set_filter_func(listBox, nothing) +Gtk4.set_sort_func(listBox, nothing) + +Gtk4.set_filter_func(listBox, match) +Gtk4.set_sort_func(listBox, alpha_compare) + destroy(win) end +@testset "CustomFilter and CustomSorter" begin +filt = GtkCustomFilter(match) +Gtk4.set_filter_func(filt,nothing) +Gtk4.set_filter_func(filt,match) +Gtk4.changed(filt) + +sorter = GtkCustomSorter(alpha_compare) +Gtk4.set_sort_func(sorter,nothing) +Gtk4.set_sort_func(sorter,alpha_compare) +Gtk4.changed(sorter) + +end diff --git a/test/gui/window.jl b/test/gui/window.jl index 9358a451..c16868d2 100644 --- a/test/gui/window.jl +++ b/test/gui/window.jl @@ -51,6 +51,8 @@ end unmaximize(w) sleep(1) @test !G_.is_maximized(w) + ag = GSimpleActionGroup() + push!(w, GActionGroup(ag), "window") Gtk4.default_size(w, 200, 500) @test Gtk4.default_size(w) == (200, 500) destroy(w)