private void _list_PreviewTouchMove(object sender, TouchEventArgs e)
        {
            //if (debug_canvas == null)
            //{
            //    debug_canvas = new Canvas();
            //    debug_canvas.Width = window_manager.main_canvas.ActualWidth;
            //    debug_canvas.Height = window_manager.main_canvas.ActualHeight;
            //    window_manager.main_canvas.Children.Add(debug_canvas);
            //}
            IInputElement ie = e.TouchDevice.Captured;
            FrameworkElement findSource = e.Source as FrameworkElement;
            ListBoxItem element = null;
            while (element == null && findSource != null)
                if ((element = findSource as ListBoxItem) == null)
                    findSource = VisualTreeHelper.GetParent(findSource) as FrameworkElement;

            if (!touch_points.ContainsKey(e.TouchDevice.Id))
            {
                touch_info t = new touch_info();
                t.id = e.TouchDevice.Id; t.is_tap = false; t.points.Add(e.GetTouchPoint(this._list as IInputElement));
                this.touch_points.Add(e.TouchDevice.Id, t);
            }
            else
            {
                this.touch_points[e.TouchDevice.Id].points.Add(e.GetTouchPoint(this._list as IInputElement));
            }

            if (touch_points[e.TouchDevice.Id].is_drag == true) return;
            //TextBlock t1 = new TextBlock(); t1.Foreground = Brushes.White;
            //Canvas.SetLeft(t1, 80); Canvas.SetTop(t1, debug_var);
            //t1.Text =  e.GetTouchPoint(this._list as IInputElement).Position.X + ", " + e.GetTouchPoint(this._list as IInputElement).Position.Y;
            //t1.FontSize = 14; t1.FontWeight = FontWeights.Bold;
            //debug_canvas.Children.Add(t1);
            //debug_var = debug_var + 30;
            //if (debug_var > 1200) { debug_var = 10; debug_canvas.Children.RemoveRange(0, debug_canvas.Children.Count); }

            if (touch_points[e.TouchDevice.Id].points.Count < configurations.min_touch_points) return;
            double dy = touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 1].Position.Y - touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 2].Position.Y;
            double dx = touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 1].Position.X - touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 2].Position.X;
            double size_n = Math.Sqrt(dx * dx + dy * dy);
            dx = dx / size_n; dy = dy / size_n;
            if (dx == double.NaN || dy == double.NaN) return;
            double theta1 = Math.Acos(dx * drag_direction1.X + dy * drag_direction1.Y);
            double theta2 = Math.Acos(dx * drag_direction2.X + dy * drag_direction2.Y);
            //convert to degree
            theta1 = theta1 * 180 / Math.PI;
            theta2 = theta2 * 180 / Math.PI;
            double theta = (theta1 < theta2) ? theta1 : theta2;
            if (theta < configurations.drag_collection_theta && configurations.whole_item_drag)
            {
                if (touch_points[e.TouchDevice.Id].consecutive_drag_points < configurations.max_consecutive_drag_points)
                {
                    touch_points[e.TouchDevice.Id].consecutive_drag_points++;
                }
                else
                {
                    touch_points[e.TouchDevice.Id].is_tap = false;
                    if (touch_points[e.TouchDevice.Id].initial_attended_item != null)
                        attend_on_item(false, touch_points[e.TouchDevice.Id].initial_attended_item);
                    //if (element == null) element = last_dragged_element;
                    //if (configurations.whole_item_drag)
                    //{
                        UIElement dragged_item = HitTestOverItem(e, true, true, false, false);
                        if (dragged_item != null)
                        {
                            //avatar_drag(element, e.TouchDevice);
                            bool result = false;
                            if (dragged_item.GetType() == Type.GetType("nature_net.user_controls.item_generic_v2"))
                                result = start_drag((item_generic_v2)dragged_item, e);
                            //else
                            //    result = start_drag((Image)dragged_item, e.TouchDevice);

                            touch_points[e.TouchDevice.Id].is_drag = true;
                            touch_points[e.TouchDevice.Id].points.Clear();
                            touch_points[e.TouchDevice.Id].consecutive_drag_points = 0;
                            e.Handled = true;
                            touch_points.Remove(e.TouchDevice.Id);
                            return;
                        }
                    //}
                }
            }

            FadingScrollViewer scroll = configurations.GetDescendantByType(this._list, typeof(FadingScrollViewer)) as FadingScrollViewer;
            //double dv = touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 1].Position.Y - touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 2].Position.Y;
            //double dh = touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 1].Position.X - touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 2].Position.X;

            double dv = touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 1].Position.Y - touch_points[e.TouchDevice.Id].points[0].Position.Y;
            double dh = touch_points[e.TouchDevice.Id].points[touch_points[e.TouchDevice.Id].points.Count - 1].Position.X - touch_points[e.TouchDevice.Id].points[0].Position.X;
            //if (touch_points[e.TouchDevice.Id].points.Count > 4)
            //    dv++;
            if (Math.Abs(dv) > configurations.tap_error || Math.Abs(dh) > configurations.tap_error)
            {
                touch_points[e.TouchDevice.Id].is_tap = false;
                if (touch_points[e.TouchDevice.Id].initial_attended_item != null)
                    attend_on_item(false, touch_points[e.TouchDevice.Id].initial_attended_item);
            }
            if (!selectable) this._list.SelectedIndex = -1;
            if (configurations.manual_scroll)
            {
                if (is_horizontal)
                {
                    double new_offset = scroll.HorizontalOffset + (-1 * dh);
                    try { scroll.ScrollToHorizontalOffset(new_offset); }
                    catch (Exception) { }
                    //last_scroll_offset = scroll.HorizontalOffset;
                }
                else
                {
                    double new_offset = scroll.VerticalOffset + (-1 * dv);
                    try { scroll.ScrollToVerticalOffset(new_offset); }
                    catch (Exception) { }
                    //last_scroll_offset = scroll.VerticalOffset;
                }
            }
        }
        private void _list_PreviewTouchDown(object sender, TouchEventArgs e)
        {
            if (e.Handled)
                return;
            if (!touch_points.ContainsKey(e.TouchDevice.Id))
            {
                touch_info t = new touch_info();
                t.id = e.TouchDevice.Id; t.is_tap = true; t.points.Add(e.GetTouchPoint(this._list as IInputElement));
                try { t.initial_attended_item = (Control)e.Source; }
                catch (Exception) { }
                this.touch_points.Add(e.TouchDevice.Id, t);
            }
            else
            {

            }
            FadingScrollViewer scroll = configurations.GetDescendantByType(this._list, typeof(FadingScrollViewer)) as FadingScrollViewer;
            if (is_horizontal)
                last_scroll_offset = scroll.HorizontalOffset;
            else
                last_scroll_offset = scroll.VerticalOffset;
            //scroll.Elasticity = new Vector(0.0, 0.4);

            if (configurations.right_panel_drag)
            {
                UIElement dragged_item = null;
                if (collection_list)
                    dragged_item = HitTestOverItem(e, true, false, false, true);
                else
                    dragged_item = HitTestOverItem(e, true, true, false, false);
                if (dragged_item != null)
                {
                    //avatar_drag(element, e.TouchDevice);
                    bool result = false;
                    if (dragged_item.GetType() == Type.GetType("nature_net.user_controls.item_generic_v2"))
                        result = start_drag((item_generic_v2)dragged_item, e);
                    if (dragged_item.GetType() == Type.GetType("nature_net.user_controls.collection_listbox_item"))
                        result = start_drag((collection_listbox_item)dragged_item, e.TouchDevice);

                    touch_points[e.TouchDevice.Id].is_drag = true;
                    touch_points[e.TouchDevice.Id].points.Clear();
                    touch_points[e.TouchDevice.Id].consecutive_drag_points = 0;
                    e.Handled = true;
                    touch_points.Remove(e.TouchDevice.Id);
                    return;
                }
            }

            if (configurations.manual_scroll)
            {
                bool r = e.TouchDevice.Capture(this._list as IInputElement, CaptureMode.SubTree);
                e.Handled = true;
                touch_points.Remove(e.TouchDevice.Id);
                return;
            }
            if (touch_points[e.TouchDevice.Id].initial_attended_item != null)
                attend_on_item(true, touch_points[e.TouchDevice.Id].initial_attended_item);
        }