// Convert an Xsharp.Region to System.Drawing.Region internal static System.Drawing.Region RegionToDrawingRegion (Xsharp.Region region) { Xsharp.Rectangle[] rectangles = region.GetRectangles(); System.Drawing.Region newRegion = new System.Drawing.Region(); newRegion.MakeEmpty(); for (int i = 0; i < rectangles.Length; i++) { Xsharp.Rectangle rect = rectangles[i]; newRegion.Union(new System.Drawing.Rectangle (rect.x, rect.y, rect.width, rect.height)); } return(newRegion); }
/// <summary> /// <para>Construct a new <see cref="T:Xsharp.Region"/> /// instance that is initially set to the same area as /// a rectangle.</para> /// </summary> /// /// <param name="rect"> /// <para>The rectangle to set the region to initially.</para> /// </param> /// /// <exception cref="T:Xsharp.XException"> /// <para>Raised if the rectangle co-ordinates are out of range.</para> /// </exception> public Region(Rectangle rect) { lock(typeof(Region)) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } Union(rect.x, rect.y, rect.width, rect.height); } }
/// <summary> /// <para>Xor a rectangle with this region.</para> /// </summary> /// /// <param name="rect"> /// <para>The rectangle to xor with this region.</para> /// </param> /// /// <exception cref="T:Xsharp.XException"> /// <para>Raised if the rectangle co-ordinates are out of range.</para> /// </exception> /// /// <remarks> /// <para>If this region has been disposed, then it will be treated /// as empty prior to the xor operation.</para> /// </remarks> public void Xor(Rectangle rect) { lock(typeof(Region)) { if(region == IntPtr.Zero) { region = Xlib.XCreateRegion(); if(region == IntPtr.Zero) { Display.OutOfMemory(); } } XRectangle xrect = new XRectangle (rect.x, rect.y, rect.width, rect.height); IntPtr reg = Xlib.XCreateRegion(); if(reg == IntPtr.Zero) { Display.OutOfMemory(); } Xlib.XUnionRectWithRegion(ref xrect, reg, reg); Xlib.XXorRegion(region, reg, region); Xlib.XDestroyRegion(reg); } }
/// <summary> /// <para>Get the list of rectangles that defines this region.</para> /// </summary> /// /// <returns> /// <para>An array of <see cref="T:Xsharp.Rectangle"/> instances /// corresponding to the rectangles that make up the region. /// Returns a zero-length array if the region is empty.</para> /// </returns> public Rectangle[] GetRectangles() { lock(typeof(Region)) { if(region == IntPtr.Zero) { return new Rectangle [0]; } else { Rectangle[] rects; XRectangle xrect; int size, index; size = Xlib.XSharpGetRegionSize(region); rects = new Rectangle [size]; for(index = 0; index < size; ++index) { Xlib.XSharpGetRegionRect(region, index, out xrect); rects[index].x = xrect.x; rects[index].y = xrect.y; rects[index].width = xrect.width; rects[index].height = xrect.height; } return rects; } } }
/// <summary> /// <para>Get the smallest rectangle that completely contains /// this region.</para> /// </summary> /// /// <returns> /// <para>A <see cref="T:Xsharp.Rectangle"/> instance corresponding /// to the smallest rectangle that contains the region.</para> /// </returns> public Rectangle ClipBox() { lock(typeof(Region)) { Rectangle rect; if(region == IntPtr.Zero) { rect = new Rectangle(0, 0, 0, 0); } else { XRectangle xrect; Xlib.XClipBox(region, out xrect); rect = new Rectangle(xrect.x, xrect.y, xrect.width, xrect.height); } return rect; } }
/// <summary> /// <para>Determine if a rectangle is overlaps with this region.</para> /// </summary> /// /// <param name="rect"> /// <para>The rectangle to test against this region.</para> /// </param> /// /// <returns> /// <para>Returns <see langword="true"/> if the rectangle overlaps /// with this region; <see langword="false"/> otherwise.</para> /// </returns> public bool Overlaps(Rectangle rect) { lock(typeof(Region)) { if(region == IntPtr.Zero) { return false; } else { return (Xlib.XRectInRegion(region, rect.x, rect.y, (uint)(rect.width), (uint)(rect.height)) != 0); // RectangleOut } } }
/// <summary> /// <para>Determine if a rectangle is completely contained /// in this region.</para> /// </summary> /// /// <param name="rect"> /// <para>The rectangle to test against this region.</para> /// </param> /// /// <returns> /// <para>Returns <see langword="true"/> if the rectangle is completely /// contained within this region; <see langword="false"/> otherwise.</para> /// </returns> public bool Contains(Rectangle rect) { lock(typeof(Region)) { if(region == IntPtr.Zero) { return false; } else { return (Xlib.XRectInRegion(region, rect.x, rect.y, (uint)(rect.width), (uint)(rect.height)) == 1); // RectangleIn } } }
/// <summary> /// <para>Draw a rectangle.</para> /// </summary> /// /// <param name="rect"> /// <para>The position and size of the rectangle.</para> /// </param> /// /// <exception cref="T:Xsharp.XException"> /// <para>One of the co-ordinate or size values is out of range.</para> /// </exception> public void DrawRectangle(Rectangle rect) { DrawRectangle(rect.x, rect.y, rect.width, rect.height); }
// Paint this widget in response to an "Expose" event. protected override void OnPaint(Graphics graphics) { // Draw the thick 3D border around the outside first. graphics.DrawEffect(0, 0, width, height, Effect.Raised); // Get the rectangle containing the caption area. Rectangle rect = new Rectangle (FrameBorderSize, FrameBorderSize, width - FrameBorderSize * 2, captionHeight - FrameBorderSize); // If the rectangle does not overlap the expose region, // then there is no point drawing the main caption area. if(!graphics.ExposeRegion.Overlaps(rect)) { return; } // Get the colors to use for the foreground and background. Color foreground, background, endBackground; if((flags & CaptionFlags.Active) != 0) { foreground = new Color(StandardColor.HighlightForeground); background = new Color(StandardColor.HighlightBackground); endBackground = new Color(StandardColor.HighlightEndBackground); } else { foreground = new Color(StandardColor.Background); background = new Color(StandardColor.BottomShadow); endBackground = new Color(StandardColor.EndBackground); } // Create a gradient for the title bar, if necessary. if(gradient != null && (gradient.Width != rect.width || gradient.Height != rect.height)) { // The size has changed and we need a new gradient. gradient.Dispose(); gradient = null; } if(gradient == null && screen.DefaultDepth >= 15) { DotGNU.Images.Image image = CreateGradient (rect.width, rect.height, background, endBackground); gradient = new Xsharp.Image(screen, image.GetFrame(0)); image.Dispose(); } // Clear the caption background. if(gradient == null) { graphics.Foreground = background; graphics.SetFillSolid(); graphics.FillRectangle(rect); } else { graphics.SetFillTiled(gradient.Pixmap, rect.x, rect.y); graphics.FillRectangle(rect); graphics.SetFillSolid(); } // Draw the caption buttons and then subtract that // region off the caption rectangle so we don't get // bleed through when we draw the caption text. rect.width -= DrawCaptionButtons (graphics, rect, flags, (CaptionFlags)(~0)); // Bail out if the rectangle is too small for the text. if(rect.width <= 2) { return; } // Position the caption text. Font font = GetCaptionFont(); FontExtents extents = font.GetFontExtents(graphics); int textY = (rect.height - extents.Ascent) / 2; textY += rect.y + extents.Ascent; // Draw the caption text, clipped to the caption area // so that it won't overwrite the buttons on the right. using(Region region = new Region(graphics.ExposeRegion)) { region.Intersect(rect); graphics.SetClipRegion(region); graphics.Foreground = foreground; graphics.DrawString(rect.x + 2, textY, child.Name, font); } }
// Draw the caption buttons in their current state. Returns the // number of pixels on the right of the caption that are occupied // by the buttons. private static int DrawCaptionButtons (Graphics graphics, Rectangle rect, CaptionFlags flags, CaptionFlags buttonsToDraw) { int subtract = 2; if((flags & CaptionFlags.HasClose) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.ClosePressed) != 0), ((buttonsToDraw & CaptionFlags.HasClose) != 0), graphics.dpy.bitmaps.Close); if((flags & (CaptionFlags.HasMaximize | CaptionFlags.HasRestore | CaptionFlags.HasMinimize)) != 0) { // Leave a gap between the close button and the others. subtract += 2; } } if((flags & CaptionFlags.HasMaximize) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.MaximizePressed) != 0), ((buttonsToDraw & CaptionFlags.HasMaximize) != 0), graphics.dpy.bitmaps.Maximize); } if((flags & CaptionFlags.HasRestore) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.RestorePressed) != 0), ((buttonsToDraw & CaptionFlags.HasRestore) != 0), graphics.dpy.bitmaps.Restore); } if((flags & CaptionFlags.HasMinimize) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.MinimizePressed) != 0), ((buttonsToDraw & CaptionFlags.HasMinimize) != 0), graphics.dpy.bitmaps.Minimize); } if((flags & CaptionFlags.HasHelp) != 0) { // Leave a gap between the help button and the others. subtract += 2; subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.HelpPressed) != 0), ((buttonsToDraw & CaptionFlags.HasHelp) != 0), graphics.dpy.bitmaps.Help); } if(subtract > 2) { // Leave a gap between the buttons and the text. return subtract + 2; } else { // There are no buttons, so no need for an extra gap. return 2; } }
// Draw a caption button. Returns the width of the button. private static int DrawCaptionButton (Graphics graphics, Rectangle rect, int subtract, bool pressed, bool draw, XPixmap buttonPixmap) { int buttonSize = rect.height - 4; int x = rect.x + rect.width - subtract - buttonSize; int y = rect.y + 2; if(draw) { if(pressed) { graphics.DrawEffect(x, y, buttonSize, buttonSize, Effect.CaptionButtonIndented); ++x; ++y; } else { graphics.DrawEffect(x, y, buttonSize, buttonSize, Effect.CaptionButtonRaised); } x += (buttonSize - 9) / 2; y += (buttonSize - 9) / 2; graphics.DrawBitmap(x, y, 9, 9, buttonPixmap); } return buttonSize; }
// Process a minimize event on the child. private void MinimizeChild() { // Bail out if the child is already iconic. if(child.iconic) { return; } // Mark the child as iconic. child.iconic = true; // Save the restore position if we aren't maximized. if(!(child.maximized)) { restoreX = x; restoreY = y; restoreWidth = width; restoreHeight = height; } // Resize the caption widget to the minimized size. Rectangle rect = new Rectangle (0, 0, MinimizedWidth, captionHeight + FrameBorderSize); ((MdiClientWidget)Parent).PlaceMinimizedRectangle (ref rect, this); MoveResize(rect.x, rect.y, rect.width, rect.height); // Unmap the child window. try { IntPtr display = dpy.Lock(); Xlib.XUnmapWindow(display, child.GetWidgetHandle()); } finally { dpy.Unlock(); } // Lower this window and select a new active window. Lower(); // Update the decorations to match the new flags. UpdateDecorations(); }
/// <summary> /// <para>Fill a list of rectangles.</para> /// </summary> /// /// <param name="rects"> /// <para>The list of rectangles to be drawn.</para> /// </param> /// /// <exception cref="T:System.ArgumentNullException"> /// <para>Raised if <paramref name="rects"/> is <see langword="null"/>. /// </para> /// </exception> /// /// <exception cref="T:Xsharp.XException"> /// <para>One of the co-ordinate or size values is out of range, or /// <paramref name="rects"/> has less than 1 element.</para> /// </exception> public void FillRectangles(Rectangle[] rects) { int len; // Validate the parameter. if(rects == null) { throw new ArgumentNullException("rects"); } len = rects.Length; if(len < 1) { throw new XException(S._("X_Need1Rect")); } else if(len > ((dpy.MaxRequestSize() - 3) / 2)) { throw new XException(S._("X_MaxReqSizeExceeded")); } // Convert the "Rectangle" array into an "XRectangle" array. XRectangle[] xrects = new XRectangle [len]; int r; for(r = 0; r < len; ++r) { xrects[r] = new XRectangle(rects[r].x, rects[r].y, rects[r].width, rects[r].height); } // Draw the rectangles. try { IntPtr display = Lock(); Xlib.XFillRectangles(display, drawableHandle, gc, xrects, len); } finally { dpy.Unlock(); } }
/// <summary> /// <para>Fill a rectangle.</para> /// </summary> /// /// <param name="rect"> /// <para>The position and size of the rectangle.</para> /// </param> /// /// <exception cref="T:Xsharp.XException"> /// <para>One of the co-ordinate or size values is out of range.</para> /// </exception> public void FillRectangle(Rectangle rect) { FillRectangle(rect.x, rect.y, rect.width, rect.height); }
// Change the state of a caption button. Returns true if the // button was pressed before we changed its state. private bool ChangeButtonState(HitTest hitTest, bool pressed) { // Determine what change we need to apply. CaptionFlags buttonsToDraw = (CaptionFlags)0; CaptionFlags pressedState = (CaptionFlags)0; CaptionFlags origFlags = flags; switch(hitTest) { case HitTest.Close: { buttonsToDraw = CaptionFlags.HasClose; pressedState = CaptionFlags.ClosePressed; } break; case HitTest.Maximize: { buttonsToDraw = CaptionFlags.HasMaximize; pressedState = CaptionFlags.MaximizePressed; } break; case HitTest.Minimize: { buttonsToDraw = CaptionFlags.HasMinimize; pressedState = CaptionFlags.MinimizePressed; } break; case HitTest.Restore: { buttonsToDraw = CaptionFlags.HasRestore; pressedState = CaptionFlags.RestorePressed; } break; case HitTest.Help: { buttonsToDraw = CaptionFlags.HasHelp; pressedState = CaptionFlags.HelpPressed; } break; } if(pressed) { flags |= pressedState; } else { flags &= ~pressedState; } // Redraw the caption buttons to match the state change. if(flags != origFlags) { Rectangle rect = new Rectangle (FrameBorderSize, FrameBorderSize, width - FrameBorderSize * 2, captionHeight - FrameBorderSize); using(Graphics graphics = new Graphics(this)) { DrawCaptionButtons (graphics, rect, flags, buttonsToDraw); } } return ((origFlags & pressedState) != 0); }
// Place a minimized window rectangle. internal void PlaceMinimizedRectangle(ref Rectangle rect, Widget placed) { // Create a region that consists of all minimized areas. Region region = new Region(); Widget current = TopChild; while(current != null) { if(current is CaptionWidget && current.IsMapped && ((CaptionWidget)current).Child.IsIconic) { if(current != placed) { region.Union (current.x, current.y, current.width, current.height); } } current = current.NextBelow; } // Place the minimized rectangle. int yplace = height - rect.height; int xplace = 0; for(;;) { // Move up to the next line if we've overflowed this one. if((xplace + rect.width) > width && width >= rect.width) { yplace -= rect.height; xplace = 0; } // Determine if the rectangle overlaps the region. // If it doesn't, then we have found the best location. rect.x = xplace; rect.y = yplace; if(!region.Overlaps(rect)) { region.Dispose(); return; } // Move on to the next candidate. xplace += rect.width; } }
/// <summary> /// <para>Clear a rectangular area within the drawable to /// its background color.</para> /// </summary> /// /// <param name="rect"> /// <para>The rectangle to be cleared.</para> /// </param> /// /// <remarks> /// <para>If the drawable is an input-output widget, it uses the /// background color (or pixmap) of the widget, not the background /// color of the graphics object.</para> /// /// <para>If the graphics object has an active clipping region, then the /// cleared area will be clipped to the region.</para> /// </remarks> /// /// <exception cref="T:Xsharp.XException"> /// <para>One of the co-ordinate or size values is out of range.</para> /// </exception> public void Clear(Rectangle rect) { Clear(rect.x, rect.y, rect.width, rect.height); }