### ----------------------------------------------------
### -- Gnome::Gtk3
### -- Licenses: Artistic-2.0
### -- Authors: Marcel Timmerman
### -- File: lib/Gnome/Gtk3/TreeModel.rakumod
### ----------------------------------------------------
### -- Chunk 2 of 2
 column 0 with type C<G_TYPE_STRING>, you would
write: `gtk_tree_model_get (model, iter, 0, &place_string_here, -1)`,
where `place_string_here` is a B<gchararray>
to be filled with the string.

Returned values with type C<G_TYPE_OBJECT> have to be unreferenced,
values with type C<G_TYPE_STRING> or C<G_TYPE_BOXED> have to be freed.
Other values are passed by value.
=end comment

  method gtk_tree_model_get (
    N-GtkTreeIter $iter, Int $column-gtype, $column-number, ...
    --> Any
  )

=item N-GtkTreeIter $iter; a row in this tree_model
=item Int $column-number: column numbers of wanted values

=end pod

sub gtk_tree_model_get (
  N-GObject $tree_model, N-GtkTreeIter $iter,
  Int $column-gtype, Int $column-number
  --> Any
) {
  my N-TypesMap $tm .= new;
  my CArray[N-TypesMap] $ret-loc .= new($tm);
  _gtk_tree_model_get( $tree_model, $iter, $column-number, $ret-loc, -1);

  my $ret-val;
  given $column-gtype {
    when G_TYPE_CHAR { $ret-val = $ret-loc[0].int8.Int; }
    when G_TYPE_UCHAR { $ret-val = $ret-loc[0].uint8.UInt; }
    when G_TYPE_UINT { $ret-val = $ret-loc[0].uint32.UInt; }
    when G_TYPE_UINT64 { $ret-val = $ret-loc[0].uint64.UInt; }
    when G_TYPE_FLOAT { $ret-val = $ret-loc[0].float.Num; }
    when G_TYPE_DOUBLE { $ret-val = $ret-loc[0].double.Num; }
    when G_TYPE_STRING { $ret-val = $ret-loc[0].string.Str; }
    when G_TYPE_OBJECT { $ret-val = $ret-loc[0].object; }

    when any(G_TYPE_BOOLEAN|G_TYPE_INT|G_TYPE_ENUM|G_TYPE_FLAGS) {
$ret-loc[0]
      $ret-val = $ret-loc[0].int32.Int;
    }

    when any(G_TYPE_LONG|G_TYPE_INT64) {
      $ret-val = $ret-loc[0].int64.Int;
    }

    when any(G_TYPE_POINTER|G_TYPE_BOXED|G_TYPE_PARAM|G_TYPE_VARIANT) {
      $ret-val = $ret-loc[0].pointer;
    }
  }

  $ret-val
}

sub _gtk_tree_model_get (
  N-GObject $tree_model, N-GtkTreeIter $iter,
  int32 $column-number, CArray[N-TypesMap] $location, int32 $end-list
) is native(&gtk-lib)
  is symbol('gtk_tree_model_get')
  { * }
}}
#`{{
#-------------------------------------------------------------------------------
#TM:0:gtk_tree_model_get_valist:
=begin pod
=head2 [[gtk_] tree_model_] get_valist

See C<gtk_tree_model_get()>, this version takes a va_list
for language bindings to use.

  method gtk_tree_model_get_valist ( N-GtkTreeIter $iter, va_list $var_args )

=item N-GtkTreeIter $iter; a row in I<tree_model>
=item va_list $var_args; va_list of column/return location pairs

=end pod

sub gtk_tree_model_get_valist ( N-GObject $tree_model, N-GtkTreeIter $iter, va_list $var_args )
  is native(&gtk-lib)
  { * }
}}

#-------------------------------------------------------------------------------
#TM:2:foreach:t/ListStore.t
=begin pod
=head2 foreach

Calls func on each node in model in a depth-first fashion.

If I<func> returns C<1>, then the tree ceases to be walked, and C<foreach()> returns.

  method foreach (
    $function-object, Str $function-name, *%user-options
  )

=item $function-object; an object where the function is defined
=item $function-name; the name of the function which is called
=item %user-options; named arguments which will be provided to the callback

The function signature is

  method f (
    N-GObject $n-store,
    Gnome::Gtk3::TreePath $path,
    Gnome::Gtk3::TreeIter $iter,
    *%user-options
    --> Bool
  )

The value in $n-store is a native object and cannot be created into a Raku object here because it is not known if this is a ListStore or a TreeStore object.

An example

  my Gnome::Gtk3::ListStore $ls;
  my Gnome::Gtk3::TreeIter $iter;

  # specify column types
  $ls .= new(:field-types( G_TYPE_INT, G_TYPE_STRING));

  # fill some rows
  $iter = $ls.gtk-list-store-append;
  $ls.gtk-list-store-set( $iter, 0, 1001, 1, 'some text');
  $iter = $ls.gtk-list-store-append;
  $ls.gtk-list-store-set( $iter, 0, 2002, 1, 'a bit more');

  # define class for handler
  class X {
    method row-loop (
      N-GObject $n-store,
      Gnome::Gtk3::TreePath $path,
      Gnome::Gtk3::TreeIter $iter
      --> Bool
    ) {
      # get values for this iterator
      my Gnome::Gtk3::ListStore $store .= new(:native-object($n-store));
      my Array[Gnome::GObject::Value] $va = $store.get-value( $iter, 0);

      # do something with this row ...

      my Int $value = $va[0].get-int;
      $va[0].clear-object;

      if $value of col 0 != 1001 {
        # let the search continue
        False
      }

      # value of col 0 == 1001
      else {
        # stop walking to the next row
        True
      }
    }
  }

  $ls.foreach( X.new, 'row-loop');

=end pod

method foreach ( $function-object, Str $function-name, *%user-options ) {

  if $function-object.^can($function-name) {
    sub local-handler (
      N-GObject $n-m, N-GtkTreePath $n-p, N-GtkTreeIter $n-i,
      OpaquePointer $d
      --> gboolean
    ) {
      CATCH { default { .message.note; .backtrace.concise.note } }
#note "TP 0: $n-p, $n-i";
#note "TP 1: ", gtk_tree_model_get_string_from_iter( $m, $n-i);
      my Bool $sts = $function-object."$function-name"(
        $n-m,
        Gnome::Gtk3::TreePath.new(:native-object($n-p)),
        Gnome::Gtk3::TreeIter.new(:native-object($n-i)),
        |%user-options
      );

#note "returns $sts";
      $sts ?? 1 !! 0
    }

    _gtk_tree_model_foreach(
      self._f('GtkTreeModel'), &local-handler, OpaquePointer,
    ) if self.iter-n-children(Any);
  }

  else {
    note "Method $function-name not found in object $function-object.gist()"
      if $Gnome::N::x-debug;
  }
}

sub gtk_tree_model_foreach (
  N-GObject:D $m, Any:D $func-object, Str:D $func-name, *%user-options
) {
  Gnome::N::deprecate( 'gtk_tree_model_foreach', 'foreach', '0.34.2', '0.40.0');

  if $func-object.^can($func-name) {
    _gtk_tree_model_foreach(
      $m,
      sub (
        N-GObject $n-m, N-GtkTreePath $n-p, N-GtkTreeIter $n-i,
        OpaquePointer $d
        --> int32
      ) {
        CATCH { default { .message.note; .backtrace.concise.note } }
#note "TP 0: $n-p, $n-i";
#note "TP 1: ", gtk_tree_model_get_string_from_iter( $m, $n-i);

#TODO? Cannot find type of model: liststore or treestore
#        my Gnome::GObject::Object $tm .= new(:native-object($n-m));
#        note $tm.perl, ', ', $tm.get-class-name;
        my int32 $sts = $func-object."$func-name"(
          $n-m,
          Gnome::Gtk3::TreePath.new(:native-object($n-p)),
          Gnome::Gtk3::TreeIter.new(:native-object($n-i)),
          |%user-options
        );
#note "returns $sts";
#$sts
      },
      OpaquePointer
    );
  }

  else {
    note "Method $func-name not found in object $func-object.perl()"
      if $Gnome::N::x-debug;
  }
}

sub _gtk_tree_model_foreach (
  N-GObject $model,
  Callable $func (
    N-GObject $m, N-GtkTreePath $p, N-GtkTreeIter $i, OpaquePointer $d
    --> int32
  ), OpaquePointer $user_data
) is native(&gtk-lib)
  is symbol('gtk_tree_model_foreach')
  { * }

#-------------------------------------------------------------------------------
#TM:2:gtk_tree_model_row_changed:t/ListStore.t
=begin pod
=head2 [[gtk_] tree_model_] row_changed

Emits the  I<row-changed> signal on the tree model.

  method gtk_tree_model_row_changed (
    Gnome::Gtk3::TreePath $path,
    Gnome::Gtk3::TreeIter $iter
  )

=item Gnome::Gtk3::TreePath $path; a path pointing to the changed row
=item Gnome::Gtk3::TreeIter $iter; an iterator pointing to the changed row

=end pod

sub gtk_tree_model_row_changed (
  N-GObject $tree_model, N-GtkTreePath $path, N-GtkTreeIter $iter
) is native(&gtk-lib)
  { * }

#-------------------------------------------------------------------------------
#TM:2:gtk_tree_model_row_inserted:t/ListStore.t
=begin pod
=head2 [[gtk_] tree_model_] row_inserted

Emits the  I<row-inserted> signal on the tree model.

  method gtk_tree_model_row_inserted (
    Gnome::Gtk3::TreePath $path,
    Gnome::Gtk3::TreeIter $iter
  )

=item Gnome::Gtk3::TreePath $path; a path pointing to the changed row
=item Gnome::Gtk3::TreeIter $iter; an iterator pointing to the changed row

=end pod

sub gtk_tree_model_row_inserted ( N-GObject $tree_model, N-GtkTreePath $path, N-GtkTreeIter $iter )
  is native(&gtk-lib)
  { * }

#-------------------------------------------------------------------------------
#TM:2:gtk_tree_model_row_has_child_toggled:t/ListStore.t
=begin pod
=head2 [[gtk_] tree_model_] row_has_child_toggled

Emits the  I<row-has-child-toggled> signal on
I<tree_model>. This should be called by models after the child
state of a node changes.

  method gtk_tree_model_row_has_child_toggled ( N-GtkTreePath $path, N-GtkTreeIter $iter )

=item N-GtkTreePath $path; a B<Gnome::Gtk3::TreePath>-struct pointing to the changed row
=item N-GtkTreeIter $iter; a valid B<Gnome::Gtk3::TreeIter>-struct pointing to the changed row

=end pod

sub gtk_tree_model_row_has_child_toggled ( N-GObject $tree_model, N-GtkTreePath $path, N-GtkTreeIter $iter )
  is native(&gtk-lib)
  { * }

#-------------------------------------------------------------------------------
#TM:2:gtk_tree_model_row_deleted:t/ListStore.t
=begin pod
=head2 [[gtk_] tree_model_] row_deleted

Emits the  I<row-deleted> signal on I<tree_model>.

This should be called by models after a row has been removed.
The location pointed to by I<path> should be the location that
the row previously was at. It may not be a valid location anymore.

Nodes that are deleted are not unreffed, this means that any
outstanding references on the deleted node should not be released.

  method gtk_tree_model_row_deleted ( N-GtkTreePath $path )

=item N-GtkTreePath $path; a B<Gnome::Gtk3::TreePath>-struct pointing to the previous location of the deleted row

=end pod

sub gtk_tree_model_row_deleted ( N-GObject $tree_model, N-GtkTreePath $path )
  is native(&gtk-lib)
  { * }

#-------------------------------------------------------------------------------
#TM:2:gtk_tree_model_rows_reordered:t/ListStore.t
=begin pod
=head2 [[gtk_] tree_model_] rows_reordered

Emits the  I<rows-reordered> signal on I<tree_model>.

This should be called by models when their rows have been
reordered.

  method gtk_tree_model_rows_reordered ( N-GtkTreePath $path, N-GtkTreeIter $iter, Int $new_order )

=item N-GtkTreePath $path; a B<Gnome::Gtk3::TreePath>-struct pointing to the tree node whose children have been reordered
=item N-GtkTreeIter $iter; a valid B<Gnome::Gtk3::TreeIter>-struct pointing to the node whose children have been reordered, or C<Any> if the depth of I<path> is 0
=item Int $new_order; an array of integers mapping the current position of each child to its old position before the re-ordering, i.e. I<new_order>`[newpos] = oldpos`

=end pod

sub gtk_tree_model_rows_reordered (
  N-GObject $tree_model, N-GtkTreePath $path,
  N-GtkTreeIter $iter, CArray[int32] $new_order
) is native(&gtk-lib)
  { * }

#-------------------------------------------------------------------------------
#TM:2:gtk_tree_model_rows_reordered_with_length:t/ListStore.t
=begin pod
=head2 [[gtk_] tree_model_] rows_reordered_with_length

Emits the  I<rows-reordered> signal on I<tree_model>.

This should be called by models when their rows have been
reordered.

Since: 3.10

  method gtk_tree_model_rows_reordered_with_length ( N-GtkTreePath $path, N-GtkTreeIter $iter, Int $new_order, Int $length )

=item N-GtkTreePath $path; a B<Gnome::Gtk3::TreePath>-struct pointing to the tree node whose children have been reordered
=item N-GtkTreeIter $iter; (allow-none): a valid B<Gnome::Gtk3::TreeIter>-struct pointing to the node whose children have been reordered, or C<Any> if the depth of I<path> is 0
=item Int $new_order; (array length=length): an array of integers mapping the current position of each child to its old position before the re-ordering, i.e. I<new_order>`[newpos] = oldpos`
=item Int $length; length of I<new_order> array

=end pod

sub gtk_tree_model_rows_reordered_with_length (
  N-GObject $tree_model, N-GtkTreePath $path,
  N-GtkTreeIter $iter, CArray[int32] $new_order, int32 $length
) is native(&gtk-lib)
  { * }

#-------------------------------------------------------------------------------
=begin pod
=head1 Signals

There are two ways to connect to a signal. The first option you have is to use C<register-signal()> from B<Gnome::GObject::Object>. The second option is to use C<g_signal_connect_object()> directly from B<Gnome::GObject::Signal>.

=head2 First method

The positional arguments of the signal handler are all obligatory as well as their types. The named attributes C<:$widget> and user data are optional.

  # handler method
  method mouse-event ( N-GdkEvent $event, :$widget ) { ... }

  # connect a signal on window object
  my Gnome::Gtk3::Window $w .= new( ... );
  $w.register-signal( self, 'mouse-event', 'button-press-event');

=head2 Second method

  my Gnome::Gtk3::Window $w .= new( ... );
  my Callable $handler = sub (
    N-GObject $native, N-GdkEvent $event, OpaquePointer $data
  ) {
    ...
  }

  $w.connect-object( 'button-press-event', $handler);

Also here, the types of positional arguments in the signal handler are important. This is because both methods C<register-signal()> and C<g_signal_connect_object()> are using the signatures of the handler routines to setup the native call interface.

=head2 Supported signals


=comment #TS:2:row-changed:t/ListStore.t
=head3 row-changed

This signal is emitted when a row in the model has changed.

  method handler (
    N-GObject $path,
    N-GtkTreeIter $iter,
    Int :$_handler_id,
    Gnome::GObject::Object :_widget($tree_model),
    *%user-options
  );

=item Gnome::Gtk3::TreeModel $tree_model; the model on which the signal is emitted
=item N-GObject $path; a native B<Gnome::Gtk3::TreePath> identifying the changed row
=item N-GtkTreeIter $iter; a native B<Gnome::Gtk3::TreeIter> pointing to the changed row


=comment #TS:2:row-deleted:t/ListStore.t
=head3 row-deleted

This signal is emitted when a row in the model is deleted.

  method handler (
    N-GObject $path,
    Int :$_handler_id,
    Gnome::GObject::Object :_widget($tree_model),
    *%user-options
  );

=item Gnome::Gtk3::TreeModel $tree_model; the model on which the signal is emitted.
=item N-GObject $path; a native B<Gnome::Gtk3::TreePath> identifying where the deleted row has been at. This path may not be a valid location anymore.


=comment #TS:0=2:row-inserted:t/ListStore.t
=head3 row-inserted

This signal is emitted when a new row has been inserted in
the model.

Note that the row may still be empty at this point, since it is a common pattern to first insert an empty row, and then fill it with the desired values.

  method handler (
    N-GObject $path,
    N-GtkTreeIter $iter,
    Int :$_handler_id,
    Gnome::GObject::Object :_widget($tree_model),
    *%user-options
  );

=item Gnome::Gtk3::TreeModel $tree_model; the model on which the signal is emitted
=item $path; a native B<Gnome::Gtk3::TreePath> identifying the new row
=item $iter; a native B<Gnome::Gtk3::TreeIter> pointing to the new row


=comment #TS:2:row-has-child-toggled:t/ListStore.t
=head3 row-has-child-toggled

This signal is emitted when a row has gotten the first child row or lost its last child row.

  method handler (
    N-GObject $path,
    N-GtkTreeIter $iter,
    Int :$_handler_id,
    Gnome::GObject::Object :_widget($tree_model),
    *%user-options
  );

=item Gnome::Gtk3::TreeModel $tree_model; the model on which the signal is emitted
=item $path; a native B<Gnome::Gtk3::TreePath> identifying the new row
=item $iter; a native B<Gnome::Gtk3::TreeIter> pointing to the new row


=comment #TS:2:rows-reordered:t/ListStore.t
=head3 rows-reordered

This signal is emitted when the children of a node in the GtkTreeModel have been reordered.

Note that this signal is not emitted when rows are reordered by DND, since this is implemented by removing and then reinserting the row.

  method handler (
    N-GObject $path,
    N-GtkTreeIter $iter,
    CArray[int32] $new-order,
    Int :$_handler_id,
    Gnome::GObject::Object :_widget($tree_model),
    *%user-options
  );

=item Gnome::Gtk3::TreeModel $tree_model; the model on which the signal is emitted
=item $path; a native B<Gnome::Gtk3::TreePath> identifying the new row
=item $iter; a native B<Gnome::Gtk3::TreeIter> pointing to the new row
=item $new-order; an array of integers mapping the current position of each child to its old position before the re-ordering, i.e. C<$new_order[newpos] = oldpos>.


=end pod


