04 November 2013

ASP.NET - A basic authentification system

The simplest login system for ASP.NET (MVC) works by simply doing something like this:
HttpContext.Current.Session["User"] = user;
If Session["User"] yields NULL, your not logged in, otherwise you are. While this works, it has an annoying consequence: while you're working on the application, and you rebuild, the session gets lost and you have to log in every time you want to test. This can be remedied like this: First, add the following to the system.web section of the Web.config:
<authentication mode="Forms">
  <forms cookieless="UseCookies" loginUrl="/Home/Login" name="BFWauth" timeout="10512000" slidingExpiration="true" />
</authentication>
Second, in the same code that assigns Session["User"], add this:
System.Web.Security.FormsAuthentication.SetAuthCookie(user.Id.ToString(), false);
The user ID you put in there will be persisted even when the session is reset. Third, to know whether the user is logged in use:
if(HttpContext.Current.User.Identity.IsAuthenticated) { ...
The user ID is available here:
int userId = HttpContext.Current.User.Identity.Name.ToInt(); //ToInt() is an extension of mine.
User user = GetUser(userId); //This one's obvious.
You can now rebuild your application without being logged out. Life just got a little bit better.

09 September 2013

CSS - Multilevel dropdown menu

The following is my slightly different version of the so-called suckerfish menu, as implemented here. It's a basic multilevel dropdown menu made from an unordered list using CSS:

HTML

<ul class="menu">
  <li>
    <a href="">Addresses<a>
    <ul>
      <li>
        <a href="">New<a>
        <ul>
          <li>
            <a href="">Address<a>
            <a href="">Selection<a>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

CSS

.right { float: right; } /* Used to have the menu on the right side. */
ul.menu,
ul.menu ul { margin: 0; padding: 0; list-style-type: none;
             list-style-position: outside; position: relative; line-height: 2em; }
  ul.menu ul { position: absolute; width: 12em; top: 2em; display: none; }
  ul.menu li { float: left; position: relative; }
  ul.menu li ul a { width: 12em; float: left; border-top: solid 1px #888; }
  ul.menu li ul ul { top: auto; left: 12em; border-left: solid 1px #888; }
  ul.menu li:hover ul ul,
  ul.menu li:hover ul ul ul,
  ul.menu li:hover ul ul ul ul { display: none; }
  ul.menu li:hover ul,
  ul.menu li li:hover ul,
  ul.menu li li li:hover ul,
  ul.menu li li li li:hover ul { display: block; z-index: 99; }
  ul.menu a:link,
  ul.menu a:active,
  ul.menu a:visited { display: block; padding: 0px 10px; border-right:
                      solid 1px #888; color: #fff; text-decoration: none; background-color: #000; }
  ul.menu a:hover { background-color: #888; }
ul.right a:link,
ul.right a:active,
ul.right a:visited { border-right: none; border-left: solid 1px #888; }

18 June 2013

VB6 - Dynamic cursor

For a drawing application I needed to be able to set the cursor dynamically to reflect the current size and color of the brush. I was working in VB6 (love it!) and with GDI, and the following does what I wanted. It uses a number of Windows API methods which signatures can be found on MSDN. All methods called in the code below are API methods. First, some constants and the type IconInfo that is needed for the Windows API:
Private Const GCL_HCURSOR = -12
Private Const BLACKNESS = 66
Private Const WHITENESS = 16711778
Private Const BLACK_BRUSH = 4
Private Const BLACK_PEN = 7
Private Const DC_BRUSH = 18
Private Const DC_PEN = 1

Private Type IconInfo
  IsIcon As Boolean
  Hotspot As PointL
  MaskBitmap As Long
  ColorBitmap As Long
End Type
You need to create a color bitmap of your cursor and a mask bitmap for it's transparancy. The following code creates a round cursor of size pixels and the color color.RgbColor.
'Create color bitmap
Dim colorDc As Long: colorDc = CreateCompatibleDC(mHdc)
mCursorInfo.ColorBitmap = CreateCompatibleBitmap(mHdc, size, size)
Dim prevColorBmp As Long: prevColorBmp = SelectObject(colorDc, mCursorInfo.ColorBitmap)
PatBlt colorDc, 0, 0, size, size, BLACKNESS
SelectObject colorDc, GetStockObject(DC_BRUSH)
SelectObject colorDc, GetStockObject(DC_PEN)
SetDCBrushColor colorDc, color.RgbColor
SetDCPenColor colorDc, color.RgbColor
Ellipse colorDc, 0, 0, size, size
SelectObject colorDc, prevColorBmp
DeleteDC colorDc

'Create mask bitmap
Dim maskDc As Long: maskDc = CreateCompatibleDC(mHdc)
mCursorInfo.MaskBitmap = CreateCompatibleBitmap(mHdc, size, size)
Dim prevMaskBmp As Long: prevMaskBmp = SelectObject(maskDc, mCursorInfo.MaskBitmap)
Rectangle maskDc, -1, -1, size + 1, size + 1
SelectObject maskDc, GetStockObject(BLACK_BRUSH)
SelectObject maskDc, GetStockObject(BLACK_PEN)
Ellipse maskDc, 0, 0, size, size
SelectObject maskDc, prevMaskBmp
DeleteDC maskDc
Then you need to tell Windows to use these as cursor. If I created a cursor before, I destroy it and it's bitmaps to free the memory:
'Create cursor
mCursorInfo.Hotspot.X = size / 2
mCursorInfo.Hotspot.Y = size / 2
mCursor = CreateIconIndirect(mCursorInfo)
If mCursor <= 0 Then
  Debug.Print "Could not create dot."
Else
  origCursor = SetCursor(mCursor)
  SetClassLong mHwnd, GCL_HCURSOR, mCursor
  If prevCursor > 0 Then
    If DestroyIcon(prevCursor) = False Then Debug.Print "Could not delete dot."
    DeleteObject prevInfo.ColorBitmap
    DeleteObject prevInfo.MaskBitmap
  End If
End If

25 April 2013

Extension - Adding a parameter to an ODBC command; the easy way

I find that adding parameters to an OdbcCommand is not very straightforward. That's why I wrote myself an extension to make it easier:
public static void AddParameter(this OdbcCommand command, string name, OdbcType type, object value, bool isNull = false) {
  if (command != null && name.HasValue()) { //"HasValue()" is another extension which simply returns ''!IsNullOrEmpty''. 
    if (!name.StartsWith("@"))
      name = '@' + name;
    if (value == null || isNull)
      value = DBNull.Value;
    command.Parameters.Add(new OdbcParameter(name, type));
    command.Parameters[name].Value = value;
  }
}
It takes care of the '@', replaces NULL by DBNull and adds the parameter in two steps as it is supposed to. It has a parameter isNull, in which you can say things like "if the int value = 0 then it constitutes NULL".

21 March 2013

C# - Convert an SVG path to a GraphicsPath

The following algorithm takes the data string of an SVG path and converts it to a GDI+ GraphicsPath.
char command = ' ';
int[] args = null;
Point initPoint = new Point(); //Initial point of the subpath
Point endPoint = new Point(); //End point of the (previous) command
Point currentPoint = new Point(); //Current point of the command
Point point = new Point(); //Parsing variable
GraphicsPath path = new GraphicsPath();
List points = new List();

var functions = Regex.Split(data, @"(?=[A-Za-z])").Where(c => c.HasValue());
foreach (string function in functions) {
  command = function[0];
  args = Regex.Split(function.Remove(0, 1), @"[\s,]|(?=-)").Where(c => c.HasValue()).Select(c => c.ToInt()).ToArray();
  switch (command) {
    case 'M':
    case 'm': //Open subpath
      initPoint = new Point {
        X = (char.IsUpper(command) ? translation.X : currentPoint.X) + args[0] * scale.X,
        Y = (char.IsUpper(command) ? translation.Y : currentPoint.Y) + args[1] * scale.Y
      };
      endPoint = initPoint;
      currentPoint = initPoint;
      break;
    case 'Z':
    case 'z':
      path.CloseFigure();
      currentPoint = initPoint; //Init point becomes the current point
      break;
    case 'C':
    case 'c':
      points.Clear();
      points.Add(endPoint);
      int n = 0;
      for (int i = 0; i < args.Length; i += 2) {
        point = new Point {
          X = (char.IsUpper(command) ? translation.X : currentPoint.X) + args[i] * scale.X,
          Y = (char.IsUpper(command) ? translation.Y : currentPoint.Y) + args[i + 1] * scale.Y
        };
        points.Add(point);
        if (++n >= 3) { //Not a control point
          currentPoint = point;
          endPoint = point;
          n = 0;
        }
      }
      path.AddBeziers(points.ToArray());
      break;
    case 'L':
    case 'l':
      points.Clear();
      points.Add(endPoint);
      for (int i = 0; i < args.Length; i += 2) {
        point = new Point {
          X = (char.IsUpper(command) ? translation.X : currentPoint.X) + args[i] * scale.X,
          Y = (char.IsUpper(command) ? translation.Y : currentPoint.Y) + args[i + 1] * scale.Y
        };
        points.Add(point);
        currentPoint = point;
      }
      endPoint = currentPoint;
      path.AddLines(points.ToArray());
      break;
  }
}
Note that the points translation and scale were also taken from SVG and are used to displace the path points.

C# - Call Potrace and pass it a bitmap from code

The following snippet calls Potrace — a tool that converts raster images to vector images — and returns an SVG-string, without creating any files in between. I use this one in a drawing application I'm working on.
Process potrace = new Process {
  StartInfo = new ProcessStartInfo {
    FileName = "potrace.exe",
    Arguments = "-s -u 1", //SVG
    RedirectStandardInput = true,
    RedirectStandardOutput = true,
    RedirectStandardError = Program.IsDebug,
    UseShellExecute = false,
    CreateNoWindow = true,
    WindowStyle = ProcessWindowStyle.Hidden
  },
  EnableRaisingEvents = false
};

StringBuilder svgBuilder = new StringBuilder();
potrace.OutputDataReceived += (object sender2, DataReceivedEventArgs e2) => {
  svgBuilder.AppendLine(e2.Data);
};
if (Program.IsDebug) {
  potrace.ErrorDataReceived += (object sender2, DataReceivedEventArgs e2) => {
    Console.WriteLine("Error: " + e2.Data);
  };
}
potrace.Start();
potrace.BeginOutputReadLine();
if (Program.IsDebug) {
  potrace.BeginErrorReadLine();
}

BinaryWriter writer = new BinaryWriter(potrace.StandardInput.BaseStream);
bitmap.Save(writer.BaseStream, ImageFormat.Bmp);
potrace.StandardInput.WriteLine(); //Without this line the input to Potrace won't go through.
potrace.WaitForExit();

28 January 2013

Math - The split-and-merge algorithm

The split-and-merge or (Ramer-)Douglas-Peucker algorithm simplifies a list of points, removing those deemed redundant with respect to a given tolerance. You can read more about it here. I used it to reduce the input of the mouse cursor to a manageable set of points in a drawing application. Next is an implementation in C# in the form of an extension that acts on a List<Point>:

The entry method:

internal static List<Point> SplitAndMerge(this List<Point> points, double tolerance) {
  if (points == null || points.Count < 3) {
    return points;
  }
  else {
    List<int> indices = new List<int>();
    indices.Add(0);
    indices.Add(points.Count - 1);

    points.SplitAndMerge(0, points.Count - 1, tolerance, ref indices);

    List<point> result = new List<Point>();
    indices.Sort();
    foreach (int i in indices)
      result.Add(points[i]);
    return result;
  }
}

The private submethod that handles the recursive calls:

private static void SplitAndMerge(this List<Point> points, int indexFirst, int indexLast, double tolerance, ref List<int> indices) {
  double maxDist = 0d;
  int indexMaxDist = 0;
  double dist = 0d;

  for (int i = indexFirst; i < indexLast; i++) {
    dist = points[i].PerpendicularDistanceFrom(points[indexFirst], points[indexLast]);
    if (dist > maxDist) {
      maxDist = dist;
      indexMaxDist = i;
    }
  }

  if (maxDist > tolerance && indexMaxDist > 0) {
    indices.Add(indexMaxDist);
    points.SplitAndMerge(indexFirst, indexMaxDist, tolerance, ref indices);
    points.SplitAndMerge(indexMaxDist, indexLast, tolerance, ref indices);
  }
}

A helper method that calculates the distance between a point p to the line between a and b:

internal static double PerpendicularDistanceFrom(this Point p, Point a, Point b) {
  double area = Math.Abs(0.5d * (a.X * b.Y + b.X * p.Y + p.X * a.Y - b.X * a.Y - p.X * b.Y - a.X * p.Y));
  double bottom = Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y));
  return area / bottom * 2d;
}