Browse Source

Implemented system dialogs

pull/875/head
Nikita Tsukanov 9 years ago
parent
commit
cbc401b565
  1. 2
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  2. 10
      src/Gtk/Avalonia.Gtk3/Interop/GObject.cs
  3. 52
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  4. 21
      src/Gtk/Avalonia.Gtk3/Stubs.cs
  5. 94
      src/Gtk/Avalonia.Gtk3/SystemDialogs.cs
  6. 2
      src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

2
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@ -64,7 +64,7 @@
<Compile Include="PlatformIconLoader.cs" />
<Compile Include="PopupImpl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Stubs.cs" />
<Compile Include="SystemDialogs.cs" />
<Compile Include="TopLevelImpl.cs" />
<Compile Include="Interop\Utf8Buffer.cs" />
<Compile Include="WindowImpl.cs" />

10
src/Gtk/Avalonia.Gtk3/Interop/GObject.cs

@ -48,5 +48,15 @@ namespace Avalonia.Gtk3.Interop
{
}
class GtkDialog : GtkWindow
{
}
class GtkFileChooser : GtkDialog
{
}
}

52
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@ -95,6 +95,17 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_window_move(GtkWindow gtkWindow, int x, int y);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate GtkFileChooser gtk_file_chooser_dialog_new(Utf8Buffer title, GtkWindow parent, GtkFileChooserAction action, IntPtr ignore);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public unsafe delegate GSList* gtk_file_chooser_get_filenames(GtkFileChooser chooser);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_file_chooser_set_select_multiple(GtkFileChooser chooser, bool allow);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_file_chooser_set_filename(GtkFileChooser chooser, Utf8Buffer file);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
public delegate void gtk_dialog_add_button(GtkDialog raw, Utf8Buffer button_text, GtkResponseType response_id);
@ -203,6 +214,8 @@ namespace Avalonia.Gtk3.Interop
public delegate ulong g_timeout_add(uint interval, timeout_callback callback, IntPtr data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
public delegate ulong g_free(IntPtr data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
public unsafe delegate void g_slist_free(GSList* data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gio)]
public delegate GInputStream g_memory_input_stream_new_from_data(IntPtr ptr, IntPtr len, IntPtr destroyCallback);
@ -212,6 +225,9 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool signal_generic(IntPtr gtkWidget, IntPtr userData);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool signal_dialog_response(IntPtr gtkWidget, GtkResponseType response, IntPtr userData);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool signal_onevent(IntPtr gtkWidget, IntPtr ev, IntPtr userData);
@ -247,11 +263,17 @@ namespace Avalonia.Gtk3.Interop
public static D.gtk_window_set_default_size GtkWindowSetDefaultSize;
public static D.gtk_window_get_position GtkWindowGetPosition;
public static D.gtk_window_move GtkWindowMove;
public static D.gtk_file_chooser_dialog_new GtkFileChooserDialogNew;
public static D.gtk_file_chooser_set_select_multiple GtkFileChooserSetSelectMultiple;
public static D.gtk_file_chooser_set_filename GtkFileChooserSetFilename;
public static D.gtk_file_chooser_get_filenames GtkFileChooserGetFilenames;
public static D.gtk_dialog_add_button GtkDialogAddButton;
public static D.g_object_unref GObjectUnref;
public static D.g_signal_connect_object GSignalConnectObject;
public static D.g_signal_handler_disconnect GSignalHandlerDisconnect;
public static D.g_timeout_add GTimeoutAdd;
public static D.g_free GFree;
public static D.g_slist_free GSlistFree;
public static D.g_memory_input_stream_new_from_data GMemoryInputStreamNewFromData;
public static D.gtk_widget_set_double_buffered GtkWidgetSetDoubleBuffered;
public static D.gtk_widget_set_events GtkWidgetSetEvents;
@ -467,6 +489,13 @@ namespace Avalonia.Gtk3.Interop
public guint is_modifier;
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct GSList
{
public IntPtr Data;
public GSList* Next;
}
[Flags]
public enum GdkWindowState
{
@ -481,6 +510,29 @@ namespace Avalonia.Gtk3.Interop
Ttiled = 256
}
public enum GtkResponseType
{
Help = -11,
Apply = -10,
No = -9,
Yes = -8,
Close = -7,
Cancel = -6,
Ok = -5,
DeleteEvent = -4,
Accept = -3,
Reject = -2,
None = -1,
}
public enum GtkFileChooserAction
{
Open,
Save,
SelectFolder,
CreateFolder,
}
[StructLayout(LayoutKind.Sequential)]
struct GdkGeometry
{

21
src/Gtk/Avalonia.Gtk3/Stubs.cs

@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Input.Platform;
using Avalonia.Platform;
//TODO: This file should be empty once everything is implemented
namespace Avalonia.Gtk3
{
class SystemDialogStub : ISystemDialogImpl
{
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) => Task.FromResult(new string[0]);
public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
=> Task.FromResult((string) null);
}
}

94
src/Gtk/Avalonia.Gtk3/SystemDialogs.cs

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Gtk3.Interop;
using Avalonia.Input.Platform;
using Avalonia.Platform;
//TODO: This file should be empty once everything is implemented
namespace Avalonia.Gtk3
{
class SystemDialogStub : ISystemDialogImpl
{
unsafe static Task<string[]> ShowDialog(string title, GtkWindow parent, GtkFileChooserAction action,
bool multiselect, string initialFileName)
{
GtkFileChooser dlg;
using (var name = title != null ? new Utf8Buffer(title) : null)
dlg = Native.GtkFileChooserDialogNew(name, parent, action, IntPtr.Zero);
if (multiselect)
Native.GtkFileChooserSetSelectMultiple(dlg, true);
Native.GtkWindowSetModal(dlg, true);
var tcs = new TaskCompletionSource<string[]>();
List<IDisposable> disposables = null;
Action dispose = () =>
{
foreach (var d in disposables)
d.Dispose();
disposables.Clear();
};
disposables = new List<IDisposable>
{
Signal.Connect<Native.D.signal_generic>(dlg, "close", delegate
{
tcs.TrySetResult(null);
dispose();
return false;
}),
Signal.Connect<Native.D.signal_dialog_response>(dlg, "response", (_, resp, __)=>
{
string[] result = null;
if (resp == GtkResponseType.Accept)
{
var rlst = new List<string>();
var gs = Native.GtkFileChooserGetFilenames(dlg);
var cgs = gs;
while (cgs != null)
{
if (cgs->Data != IntPtr.Zero)
rlst.Add(Utf8Buffer.StringFromPtr(cgs->Data));
cgs = cgs->Next;
}
Native.GSlistFree(gs);
result = rlst.ToArray();
}
Native.GtkWidgetHide(dlg);
dispose();
tcs.TrySetResult(result);
return false;
}),
dlg
};
using (var open = new Utf8Buffer("Open"))
Native.GtkDialogAddButton(dlg, open, GtkResponseType.Accept);
using (var open = new Utf8Buffer("Cancel"))
Native.GtkDialogAddButton(dlg, open, GtkResponseType.Cancel);
if(initialFileName!=null)
using (var fn = new Utf8Buffer(initialFileName))
Native.GtkFileChooserSetFilename(dlg, fn);
Native.GtkWindowPresent(dlg);
return tcs.Task;
}
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
return ShowDialog(dialog.Title, ((TopLevelImpl) parent)?.GtkWidget,
dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
(dialog as OpenFileDialog)?.AllowMultiple ?? false, dialog.InitialFileName);
}
public async Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
{
var res = await ShowDialog(dialog.Title, ((TopLevelImpl) parent)?.GtkWidget,
GtkFileChooserAction.SelectFolder, false, dialog.InitialDirectory);
return res?.FirstOrDefault();
}
}
}

2
src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

@ -14,7 +14,7 @@ namespace Avalonia.Gtk3
{
abstract class TopLevelImpl : ITopLevelImpl, IPlatformHandle
{
protected readonly GtkWindow GtkWidget;
public readonly GtkWindow GtkWidget;
private IInputRoot _inputRoot;
private readonly GtkImContext _imContext;
private readonly FramebufferManager _framebuffer;

Loading…
Cancel
Save