Skip to content

Commit

Permalink
add context menu to an example, add a few methods for lists
Browse files Browse the repository at this point in the history
  • Loading branch information
jwahlstrand committed Nov 3, 2024
1 parent 5ad7e8c commit e643ea6
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 17 deletions.
65 changes: 51 additions & 14 deletions examples/HDF5Viewer/src/HDF5Viewer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ using PrecompileTools
export hdf5view

const rprogbar = Ref{GtkProgressBarLeaf}()
const rcontext_menu = Ref{GMenuLeaf}()

# This is really just a toy at this point, but it is a less trivial example of
# using a ListView to show a tree and it uses a second thread to keep the UI
Expand All @@ -14,7 +15,6 @@ const rprogbar = Ref{GtkProgressBarLeaf}()

# Ideas for improvements:
# - style: color rows by type (group, data)
# - context menu that allows you to copy the key of an item (so you can paste it somewhere)
# - filter by type
# - replace TreeView for attributes with a ListView

Expand All @@ -24,7 +24,15 @@ _repr(d::HDF5.Group) = ""
# setup callback for the key ColumnView (the first column)
function setup_cb(f, li)
tree_expander = GtkTreeExpander()
set_child(tree_expander,GtkLabel(""))
key_label = GtkLabel("")
popupmenu = GtkPopoverMenu(rcontext_menu[])
Gtk4.parent(popupmenu, key_label)
g = GtkGestureClick(key_label, 3)
signal_connect(g, "pressed") do controller, n_press, x, y
popup(popupmenu)
return Cint(true) # event taken
end
set_child(tree_expander,key_label)
set_child(li,tree_expander)
end

Expand All @@ -34,11 +42,14 @@ list_setup_cb(f, li) = set_child(li,GtkLabel(""))
# bind callback for the key ColumnView
function bind_cb(f, li)
row = li[]
row === nothing && return
tree_expander = get_child(li)
tree_expander === nothing && return
Gtk4.set_list_row(tree_expander, row)
text = Gtk4.get_item(row).string
text = split(text,'/')[end]
label = get_child(tree_expander)
label === nothing && return
text = Gtk4.get_item(row).string::String
text = split(text,'/')[end]
label.label = text
end

Expand All @@ -52,7 +63,7 @@ function create_tree_model(filename, pwin)
ks = keys(h)
rootmodel = GtkStringList(ks)
function create_model(pp)
k=Gtk4.G_.get_string(pp)
k=Gtk4.string(pp)
return lmm(h[k],k)
end
GtkTreeListModel(GLib.GListModel(rootmodel),false, true, create_model)
Expand Down Expand Up @@ -82,14 +93,14 @@ function match_string(row, entrytext)
if item === nothing
return false
end
if contains(Gtk4.G_.get_string(item), entrytext)
if contains(Gtk4.string(item), entrytext)
return true
end
# if any of this row's children match, we should show this one too
cren = Gtk4.get_children(row)
if cren !== nothing
for i=0:(length(cren)-1)
if match_string(Gtk4.G_.get_child_row(row,i), entrytext)
for i=1:length(cren)
if match_string(row[i], entrytext)
return true
end
end
Expand Down Expand Up @@ -139,6 +150,7 @@ end
function _create_gui(filename, treemodel)
b = GtkBuilder(joinpath(@__DIR__, "HDF5Viewer.ui"))
w = b["win"]::GtkWindowLeaf
rcontext_menu[] = b["key_context_menu"]
Gtk4.title(w, "HDF5 Viewer: $filename")

factory = GtkSignalListItemFactory(setup_cb, bind_cb)
Expand All @@ -147,7 +159,7 @@ function _create_gui(filename, treemodel)
function type_bind_cb(f, li)
label = get_child(li)::GtkLabelLeaf
row = li[]::GtkTreeListRowLeaf
k=Gtk4.G_.get_string(Gtk4.get_item(row))
k=Gtk4.string(Gtk4.get_item(row))
h5open(filename,"r") do h
Gtk4.label(label, _render_type(h[k]))
end
Expand All @@ -157,7 +169,7 @@ function _create_gui(filename, treemodel)
function size_bind_cb(f, li)
label = get_child(li)::GtkLabelLeaf
row = li[]::GtkTreeListRowLeaf
k=Gtk4.G_.get_string(Gtk4.get_item(row))
k=Gtk4.string(Gtk4.get_item(row))
h5open(filename,"r") do h
Gtk4.label(label, _render_size(h[k]))
end
Expand Down Expand Up @@ -188,11 +200,16 @@ function _create_gui(filename, treemodel)
atv = b["atv"]
dtv = b["dtv"]::GtkTextViewLeaf

function get_selected_key(single_sel)
position = Gtk4.G_.get_selected(single_sel)
row = treemodel[position + 1]
row!==nothing || return ""
Gtk4.string(Gtk4.get_item(row))
end

function on_selected_changed(selection, position, n_items)
position = Gtk4.G_.get_selected(selection)
row = Gtk4.G_.get_row(treemodel,position)
row!==nothing || return
p = Gtk4.G_.get_string(Gtk4.get_item(row))
p = get_selected_key(selection)
isempty(p) && return
start(spinner)
Threads.@spawn h5open(filename,"r") do h
d=h[p]
Expand All @@ -219,19 +236,39 @@ function _create_gui(filename, treemodel)

signal_connect(on_selected_changed,sel,"selection_changed")

function copy_activated(a, p)
p = get_selected_key(single_sel)
c = Gtk4.clipboard(GdkDisplay())
Gtk4.set_text(c, "/"*p)
end

ag = GSimpleActionGroup()
add_action(GActionMap(ag), "copy", copy_activated)
Gtk4.G_.insert_action_group(w, "win", GActionGroup(ag))

show(w)

@idle_add on_selected_changed(single_sel, 0, 1)

nothing
end

const css = """
#DataTextView {
font-size:12px;
font-family:monospace;
}
"""

function __init__()
if Threads.nthreads() == 1 && Threads.nthreads(:interactive) < 1
@warn("For a more responsive UI, run with multiple threads enabled.")
end
cssprov = GtkCssProvider(css)
push!(GdkDisplay(), cssprov) # applies CSS to default display
end

# Precompile a few methods
let
@setup_workload begin
@compile_workload begin
Expand Down
7 changes: 7 additions & 0 deletions examples/HDF5Viewer/src/HDF5Viewer.ui
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="key_context_menu">
<item>
<attribute name="label">Copy key name</attribute>
<attribute name="action">win.copy</attribute>
</item>
</menu>
<object class="GtkWindow" id="win">
<property name="default-width">800</property>
<property name="default-height">600</property>
Expand Down Expand Up @@ -97,6 +103,7 @@
<object class="GtkTextView" id="dtv">
<property name="editable">false</property>
<property name="wrap-mode">GTK_WRAP_WORD</property>
<property name="name">DataTextView</property>
</object>
</child>
</object>
Expand Down
4 changes: 3 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Gtk4.jl Examples

These examples should be run in the REPL unless stated otherwise.

## Basic examples
- `calculator4.jl` demonstrates a simple GUI with lots of buttons. Adapted from an example in Gtk.jl by Nand Vinchhi.
- `css.jl` demonstrates widget styling using CSS.
Expand Down Expand Up @@ -32,7 +34,7 @@
- The `ExampleApplication` subdirectory shows how to use Gtk4.jl with [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl).

## Toys
- `HDF5Viewer` is a more extended example that shows the contents of an HDF5 file. Uses `GtkBuilder`, `GtkColumnView`, and `GtkTextView` and does some work in a separate thread to keep the UI responsive.
- `HDF5Viewer` is a more extended example that shows the contents of an HDF5 file. Uses `GtkBuilder`, `GtkColumnView`, and `GtkTextView` and does some work in a separate thread to keep the UI responsive. This directory should be `dev`'ed to use it.

## Experimental

Expand Down
6 changes: 6 additions & 0 deletions src/Gdk4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ function monitors()
G_.get_monitors(d)
end

## GdkClipboard

function set_text(c::GdkClipboard, str::AbstractString)
ccall((:gdk_clipboard_set_text, libgtk4), Nothing, (Ptr{GObject}, Cstring), c, str)
end

## GdkTexture

size(t::GdkTexture) = (G_.get_width(t),G_.get_height(t))
Expand Down
8 changes: 6 additions & 2 deletions src/lists.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function show(io::IO, sl::GtkStringList)
println(io, "0-element GtkStringList")
end
end
string(obj::GtkStringObject) = G_.get_string(obj)

## GtkDropdown

Expand Down Expand Up @@ -142,11 +143,11 @@ end
GtkColumnView(; kwargs...) = GtkColumnView(nothing; kwargs...)

function scroll_to(cv::GtkColumnView, pos, flags::ListScrollFlags = ListScrollFlags_NONE)
G_.scroll_to(lv, pos - 1, nothing, flags, nothing)
G_.scroll_to(cv, pos - 1, nothing, flags, nothing)
end

function scroll_to(cv::GtkColumnView, pos, column::GtkColumnViewColumn, flags::ListScrollFlags = ListScrollFlags_NONE)
G_.scroll_to(lv, pos - 1, column, flags, nothing)
G_.scroll_to(cv, pos - 1, column, flags, nothing)
end

GtkColumnViewColumn(title=""; kwargs...) = GtkColumnViewColumn(title, nothing; kwargs...)
Expand All @@ -162,6 +163,7 @@ get_child(te::GtkTreeExpander) = G_.get_child(te)

get_item(trl::GtkTreeListRow) = G_.get_item(trl)
get_children(trl::GtkTreeListRow) = G_.get_children(trl)
getindex(trl::GtkTreeListRow, pos) = G_.get_child_row(trl, pos - 1)

function GtkTreeListModel(root, passthrough, autoexpand, create_func)
rootlm = GListModel(root)
Expand All @@ -172,6 +174,8 @@ function GtkTreeListModel(root, passthrough, autoexpand, create_func)
GtkTreeListModelLeaf(ret, true)
end

getindex(tlm::GtkTreeListModel, pos) = G_.get_row(tlm, pos - 1)

"""
GtkSignalListItemFactory(setup_cb, bind_cb)
Expand Down

0 comments on commit e643ea6

Please sign in to comment.