private static extern bool ClientToScreen(IntPtr window, out Point2D coords);
private static void AAEdgeCopy(byte* addr, int width, int stride, double x1, double x2, int y, byte* srcAddr, int srcWidth, int srcStride, Point2D offset, bool left, int clipMin = int.MinValue, int clipMax = int.MaxValue) { if(x1 > x2) Util.Swap(ref x1, ref x2); addr += (y * width * stride); srcAddr += ((y + offset.Y) * srcWidth * stride); double xmin; double xmax = x1; double ymin; double ymax = 1; double dydx = -1 / (x2 - x1); if(x2 == x1) dydx = 0; double alpha; do { xmin = xmax; xmax = Min((int)xmin + 1, x2); ymin = ymax; ymax = ymin + (xmax - xmin) * dydx; if(xmin < clipMin) continue; if(xmin > clipMax) break; alpha = (xmin - (int)xmin) * ymin; alpha += (ymax + ymin) * (xmax - xmin) / 2; ARGB color = *(ARGB*)(srcAddr + (((int)xmin + offset.X) * srcStride)); *(ARGB*)(addr + ((int)xmin * stride)) &= new ARGB((byte)(color.A * (left ? (1 - alpha) : alpha)), color.RGB); }while(xmax != x2); }
protected override void WndProc(ref Message m) { try { int code = m.Msg; DualParameter wParam = (DualParameter)m.WParam; DualParameter lParam = (DualParameter)m.LParam; switch (m.Msg) { case WM_CLOSE: { if(OnClose != null) OnClose(); return; } case WM_SIZE: { Size = new Point2D(lParam.LowWord, lParam.HighWord); if(OnResize != null) OnResize(Size); break; } case WM_PAINT: { PaintData data; IntPtr screenDC = BeginPaint(Handle, out data); WinAPIUtils.Assert(screenDC != IntPtr.Zero); //blit display buffer to screen Image buffer = BufferStrategy.GetDisplayBuffer().Image; bool success = BitBlt(screenDC, 0, 0, buffer.Width, buffer.Height, buffer.GetDeviceContext(), 0, 0, SRCCOPY); WinAPIUtils.Assert(success); EndPaint(Handle, ref data); return; } case WM_SETFOCUS: { IsFocused = true; break; } case WM_KILLFOCUS: { IsFocused = false; break; } case WM_MOUSEMOVE: { //get move info Point2D mouseCoords = (Point2D)lParam; Point2D delta = mouseCoords - PrevMouseCoords; //if mouse was previously outside window if(!IsMouseInWindow) { IsMouseInWindow = true; if(OnMouseEnter != null) OnMouseEnter(); //suppress inaccurate delta value delta = new Point2D(0, 0); //start tracking mouse so we recieve WM_MOUSELEAVE TRACKMOUSEEVENT eventTrack = new TRACKMOUSEEVENT(Handle); bool success = TrackMouseEvent(ref eventTrack); WinAPIUtils.Assert(success); } //call event if(OnMouseMove != null) { OnMouseMove(mouseCoords, delta); PrevMouseCoords = mouseCoords; //consume return; }else { PrevMouseCoords = mouseCoords; } break; } case WM_MOUSELEAVE: { IsMouseInWindow = false; if(OnMouseExit != null) OnMouseExit(); break; } case WM_LBUTTONDOWN: { if(OnMousePress != null) { OnMousePress(MouseButton.LEFT); //consume return; } break; } case WM_LBUTTONUP: { if(OnMouseRelease != null) { OnMouseRelease(MouseButton.LEFT); //consume return; } break; } case WM_RBUTTONDOWN: { if(OnMousePress != null) { OnMousePress(MouseButton.RIGHT); //consume return; } break; } case WM_RBUTTONUP: { if(OnMouseRelease != null) { OnMouseRelease(MouseButton.RIGHT); //consume return; } break; } case WM_MBUTTONDOWN: { if(OnMousePress != null) { OnMousePress(MouseButton.MIDDLE); //consume return; } break; } case WM_MBUTTONUP: { if(OnMouseRelease != null) { OnMouseRelease(MouseButton.MIDDLE); //consume return; } break; } case WM_XBUTTONDOWN: { if(OnMousePress != null) { MouseButton button = (wParam.HighWord == 0x0001 ? MouseButton.EXTRA_1 : MouseButton.EXTRA_2); OnMousePress(button); //consume return; } break; } case WM_XBUTTONUP: { if(OnMouseRelease != null) { MouseButton button = (wParam.HighWord == 0x0001 ? MouseButton.EXTRA_1 : MouseButton.EXTRA_2); OnMouseRelease(button); //consume return; } break; } case WM_MOUSEWHEEL: { if(OnMouseWheel != null) { int delta = (wParam.HighWord / WHEEL_DELTA); OnMouseWheel(delta); //consume return; } break; } case WM_KEYDOWN: case WM_SYSKEYDOWN: { if(OnKeyPress != null) { //only post event if not a repeat //aka previous state up if((lParam.Number & 0x40000000) == 0) { KeyboardButton button = (KeyboardButton)wParam.Number; OnKeyPress(button); //consume return; } } break; } case WM_KEYUP: case WM_SYSKEYUP: { if(OnKeyRelease != null) { //only post event if not a repeat //aka previous state down if((lParam.Number & 0x40000000) != 0) { KeyboardButton button = (KeyboardButton)wParam.Number; OnKeyRelease(button); //consume return; } } break; } case WM_CHAR: { if(OnCharTyped != null) { char c = (char)wParam.Number; bool repeat = ((lParam.Number & 0x40000000) != 0); //ok if char events are repeats OnCharTyped(c, repeat); //consume return; } break; } } }catch(System.Threading.ThreadAbortException) { //do nothing, simply means we called Stop on the message thread }catch(Exception ex) { Console.WriteLine(ex); } base.WndProc(ref m); }
protected void Render(Image image, bool useMarker, int markerLoc = -1) { image.Fill(BackColor.Value); string text = Text.Value; if(text == null) text = "null"; int length = text.Length; if(length == 0) { return; } if(!LockFont) { Point2D idealSize = new Point2D(image.Width / (Math.Max(length, lengthOverride) - Margin.Value.X * 2), image.Height - Margin.Value.Y * 2); if(CurrentFont == null || CurrentFont.Size != idealSize) { CurrentFont = Font.GetFont(idealSize, Style); } } int x = 0; int y = 0; switch(HorizontalJustify) { case Justify.MIN: x = Margin.Value.X; break; case Justify.MIDDLE: x = (image.Width / 2) - (CurrentFont.Width * length / 2); break; case Justify.MAX: x = image.Width - (CurrentFont.Width * length) - Margin.Value.X; break; } switch(VerticalJustify) { case Justify.MIN: y = Margin.Value.Y; break; case Justify.MIDDLE: y = (image.Height / 2) - (CurrentFont.Height / 2); break; case Justify.MAX: y = image.Height - CurrentFont.Height - Margin.Value.Y; break; } CurrentFont.Draw(image, x, y, text, TextColor.Value); if(useMarker) { CurrentFont.Draw(image, x + (int)((markerLoc - .5) * CurrentFont.Width), y, '|', TextColor.Value); } }
/// <summary> /// Basic implementation of a map src solid filling renderer. /// </summary> /// <param name="clip">The clipping rectangle.</param> /// <param name="scanner">The scans to render.</param> /// <param name="dest">The map to render to.</param> /// <param name="src">The source map.</param> /// <param name="offset">The offset of the source map.</param> /// <param name="mode">The color blending mode to use.</param> /// <param name="isAA">True if anti-aliasing is enabled.</param> public static void SolidCopyRender(Rectangle clip, Scanner scanner, DataMap<ARGB> dest, DataMap<ARGB> src, Point2D offset, ColorMode mode = ColorMode.NORMAL, bool isAA = true) { IUnsafeMap uDest = dest as IUnsafeMap; IUnsafeMap uSrc = src as IUnsafeMap; if(uDest == null) { throw new InvalidOperationException("Destination image does not support advanced color rendering!"); } if(uSrc == null) { throw new InvalidOperationException("Source image does not support advanced color rendering!"); } byte* addr = uDest.BeginUnsafeOperation(); int width = dest.Width; int stride = uDest.GetStride(); byte* srcAddr = uSrc.BeginUnsafeOperation(); int srcWidth = src.Width; int srcStride = uSrc.GetStride(); for(int y = scanner.yMin; y <= scanner.yMax; y++) { double x1 = Max(scanner[y].min, clip.Min.X); double x2 = Min(scanner[y].max, clip.Max.X); //Anti-Aliasing variables //x1 vars are x min side //x2 vars are x max side //xb vars are y min side //xa vars are y max side double x1b = 0, x1a = 0; double x2b = 0, x2a = 0; int left; int right; if(isAA) { bool hasMin = false, hasMax = false; //if not at ymin or ymin is a clipped min (aka we have another "ghost" scan) if(y > scanner.yMin || scanner.isYMinClipped) { x1b = Max(scanner[y - 1].min, clip.Min.X); x2b = Min(scanner[y - 1].max, clip.Max.X); x1b = (x1b + x1) / 2; x2b = (x2b + x2) / 2; hasMin = true; } //if not at ymax or ymax is a clipped max (aka we have another "ghost" scan) if(y < scanner.yMax || scanner.isYMaxClipped) { x1a = Max(scanner[y + 1].min, clip.Min.X); x2a = Min(scanner[y + 1].max, clip.Max.X); x1a = (x1a + x1) / 2; x2a = (x2a + x2) / 2; hasMax = true; } if(!hasMin) { //if single line shape, just make everything literal if(!hasMax) { x1b = x1a = x1; x2b = x2a = x2; }else//if at ymin, extrapolate max->current into current->min { x1b = x1 - (x1a - x1); x2b = x2 - (x2a - x2); } }else//if at ymax, extrapolate min->current into current->max if(!hasMax) { x1a = x1 + (x1 - x1b); x2a = x2 + (x2 - x2b); } //if aa, round toward center, otherwise round away to match default renderer left = (int)Math.Ceiling(Max(x1b, x1a)); right = (int)Math.Floor(Min(x2b, x2a)); }else { //if not aa, round away to match default renderer left = (int)Math.Floor(x1); right = (int)Math.Ceiling(x2); } //if valid center if(left <= right) { //solid fill with blend modes byte* ptr = addr + (left + (y * width)) * stride; byte* srcPtr = srcAddr + ((left + offset.X) + ((y + offset.Y) * srcWidth)) * srcStride; byte* endPtr = ptr + (right - left + 1) * stride; switch(mode) { case ColorMode.BLEND: { while(ptr != endPtr) { //*((ARGB*)ptr) &= *((ARGB*)srcPtr); //manually inline blending ARGB srcColor = *(ARGB*)srcPtr; ARGB color = *(ARGB*)ptr; int aComp = 255 - srcColor.A; color = new ARGB{A = (byte)(srcColor.A + color.A), R = (byte)(((srcColor.R * srcColor.A) + (color.R * aComp)) >> 8), G = (byte)(((srcColor.G * srcColor.A) + (color.G * aComp)) >> 8), B = (byte)(((srcColor.B * srcColor.A) + (color.B * aComp)) >> 8)}; *(ARGB*)ptr = color; ptr += stride; srcPtr += srcStride; } break; } case ColorMode.NORMAL: { while(ptr != endPtr) { *((ARGB*)ptr) = *((ARGB*)srcPtr); ptr += stride; srcPtr += srcStride; } break; } case ColorMode.MASK: { while(ptr != endPtr) { if((*((ARGB*)srcPtr)).A != 0) *((ARGB*)ptr) = *((ARGB*)srcPtr); ptr += stride; srcPtr += srcStride; } break; } } } //if aa, add smoothing to edges if(isAA) { int center = (left + right) / 2; if(Min(x1b, x1a) != left) AAEdgeCopy(addr, width, stride, x1b, x1a, y, srcAddr, srcWidth, srcStride, offset, true, clipMax: Min(center, clip.Max.X)); if(Max(x2b, x2a) != right) AAEdgeCopy(addr, width, stride, x2b + 1, x2a + 1, y, srcAddr, srcWidth, srcStride, offset, false, clipMin: Max(center + 1, clip.Min.X)); } } uDest.EndUnsafeOperation(); uSrc.EndUnsafeOperation(); }
public MouseWheelEventArgs(MouseWheelEventArgs args) : base(args) { Coords = args.Coords; Delta = args.Delta; }
private void OnMove(Point2D coords, Point2D delta) { mouseCoords.Value = coords; }
public MouseMoveEventArgs(Point2D coords, Point2D delta) { Coords = coords; Delta = delta; }
public MouseWheelEventArgs(Point2D coords, int delta) { Coords = coords; Delta = delta; }
public MouseButtonEventArgs(MouseButtonEventArgs args) : base(args) { Coords = args.Coords; Button = args.Button; Pressed = args.Pressed; }
public MouseButtonEventArgs(Point2D coords, MouseButton button, bool pressed) { Coords = coords; Button = button; Pressed = pressed; }
/// <summary> /// Resizes this <see cref="Root"/> to ensure it always matches its <see cref="Window"/> /// </summary> /// <param name="size">The new size.</param> private void OnResize(Point2D size) { Size.Value = size; }
/// <summary> /// Finds every visible, non-hidden component in the given location in decreasing z order. /// </summary> /// <param name="location">The location.</param> /// <param name="findInvisible">If true, the search will include invisible and hidden components.</param> /// <param name="inputMode">If true, uses input visible and hidden.</param> /// <returns>The components in z order.</returns> public Component[] FindAll(Point2D location, bool findInvisible = false, bool inputMode = false) { return FindAll(new Rectangle{Min = location, Max = location}, findInvisible, inputMode); }
internal void MouseMoveEvent(Point2D mouseCoords, Point2D delta) { if(Parent != null) { Point2D oldCoords = mouseCoords - delta; //store all components that are guaranteed a call ActiveComponents.Clear(); foreach(MouseButton button in Enum.GetValues(typeof(MouseButton))) { ActiveComponents.UnionWith(MouseActiveComponents.GetValues(button)); } //add all entered components to exited //if they don't get removed, then we schedule an exit ExitedComponents.Clear(); ExitedComponents.UnionWith(EnteredComponents); CheckZone(); //prepare event list Component[] eventList = Parent.FindAll(new Rectangle{Min = VectorUtil.Min(mouseCoords, oldCoords), Max = VectorUtil.Max(mouseCoords, oldCoords)}, false, true); //true if the cursor was set to a special value bool cursorSet = false; //true if the drop zone was updated bool zoneSet = false; //perform normal event passing foreach(Component comp in eventList) { //if not set yet and special cursor if(!cursorSet && comp.HoverCursor.Value != Cursor.UNSPECIFIED) { cursorSet = true; if(previousCursor == Cursor.UNSPECIFIED) previousCursor = Parent.WindowObj.CurrentCursor; Parent.WindowObj.CurrentCursor = comp.HoverCursor.Value; } //if haven't entered yet if(!EnteredComponents.Contains(comp)) { //call enter comp.InvokeMouseEnter(); EnteredComponents.Add(comp); }else //else prevent automatic exit { ExitedComponents.Remove(comp); } if(grabbedComponent != null && !zoneSet && comp is IDropZone && comp.Bounds.Contains(mouseCoords) && CurrentZone != comp) { IDropZone zone = (IDropZone)comp; if(zone.Handles(grabbedComponent)) { CurrentZone = zone; zoneSet = true; } } //call event with local mouse coords comp.InvokeMouseMove(mouseCoords - (Point2D)comp.Position.Value, delta); //remove from active components (we don't care if it doesn't contain the element, it'll just do nothing) ActiveComponents.Remove(comp); //consume if opaque if(comp.InputOpaque.Value) { break; } } //if cursor was not if(!cursorSet && previousCursor != Cursor.UNSPECIFIED) { Parent.WindowObj.CurrentCursor = previousCursor; } //satisfy all waiting components foreach(Component comp in ActiveComponents) { //call event with local mouse coords comp.InvokeMouseMove(mouseCoords - (Point2D)comp.Position.Value, delta); } //remove all exited from entered EnteredComponents.ExceptWith(ExitedComponents); //exit all exited foreach(Component comp in ExitedComponents) { //call exit comp.InvokeMouseExit(); } } }