art with code

2008-12-15

Filezoo day 34, part 2: keyboard shortcuts, dragging files


Did I show this mockup already? If not, great!

Anyhow. Got ctrl-x, ctrl-c, and ctrl-v going (though in a very manual fashion, I guess the right way to do it would be AccelGroups?) and added some other keyboard shortcuts (delete to trash, backspace to parent dir, home to home dir.) Made the mouse cursor change depending on what modifiers you have down. And got dragging working. And it was a pain. So I'm going to share the pain in the form of a couple dozen lines of code.

In button press handler:

if (e.Button == 1) {
int w, h;
e.Window.GetSize (out w, out h);
DragSourceEntry = FindHit((uint)w, (uint)h, e.X, e.Y, 8).Target;
DragSourcePath = DragSourceEntry.FullName;
}

In button release handler:

if (e.Button == 1) {
if (!dragInProgress) {
DragSourceEntry = null;
DragSourcePath = null;
}
dragInProgress = false;
}
dragging = false;
panning = panning && dragInProgress;

In motion handler:

bool left = (e.State & Gdk.ModifierType.Button1Mask) == Gdk.ModifierType.Button1Mask;
bool middle = (e.State & Gdk.ModifierType.Button2Mask) == Gdk.ModifierType.Button2Mask;

if (middle) {
dragging = true;
panning = true;
}
if (left) {
dragging = dragging || ((Math.Abs(dragX - dragStartX) + Math.Abs(dragY - dragStartY)) > 4);
panning = panning || (dragStartX > 128+FilesMarginLeft);
if (!dragInProgress && !panning && dragging) {
Gdk.DragAction action = Gdk.DragAction.Move;
if ((e.State & Gdk.ModifierType.ControlMask) == Gdk.ModifierType.ControlMask)
action = Gdk.DragAction.Copy;
if ((e.State & Gdk.ModifierType.ShiftMask) == Gdk.ModifierType.ShiftMask)
action = Gdk.DragAction.Copy;
if ((e.State & Gdk.ModifierType.Mod1Mask) == Gdk.ModifierType.Mod1Mask)
action = Gdk.DragAction.Ask;
dragInProgress = true;

Drag.Begin (this, new TargetList(targets), action, 1, e);

SetCursor (e.State);
}
}

And the drag event handlers:

DragDataGet += delegate (object o, DragDataGetArgs args) {
string items = "file://" + DragSourcePath;
if (Selection.Count > 0 && Selection.ContainsKey(DragSourcePath))
items = GetSelectionData ();
args.SelectionData.Set(args.SelectionData.Target, 8, System.Text.Encoding.UTF8.GetBytes(items));
args.SelectionData.Text = items;
};

DragEnd += delegate {
GetSelectionData ();
dragInProgress = false;
DragSourceEntry = null;
DragSourcePath = null;
};

Such fun, yes? Also, read this.

I still don't know how to change the action in response to modifier key state changes (try dragging something in Konqueror and pressing and releasing ctrl/shift/alt.)

Tomorrow, I think it's time for a recap. Everyone just loves recap episodes, don't they? Not to mention that this blog is like the worst sitcom ever made.

No comments:

Blog Archive