aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Theming/Default/TabControlPainter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Theming/Default/TabControlPainter.cs')
-rw-r--r--source/ShiftUI/Theming/Default/TabControlPainter.cs507
1 files changed, 507 insertions, 0 deletions
diff --git a/source/ShiftUI/Theming/Default/TabControlPainter.cs b/source/ShiftUI/Theming/Default/TabControlPainter.cs
new file mode 100644
index 0000000..2ecdacd
--- /dev/null
+++ b/source/ShiftUI/Theming/Default/TabControlPainter.cs
@@ -0,0 +1,507 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2007 Novell, Inc.
+//
+// Authors:
+// Andreia Gaita ([email protected])
+
+using System;
+using System.Drawing;
+using System.Drawing.Text;
+using ShiftUI;
+using ShiftUI.VisualStyles;
+
+namespace ShiftUI.Theming.Default
+{
+ /// <summary>
+ /// Summary description for TabWidget.
+ /// </summary>
+ internal class TabWidgetPainter {
+ protected SystemResPool ResPool { get { return ThemeEngine.Current.ResPool; } }
+
+ #region private
+
+ private Size defaultItemSize;
+ private Point defaultPadding;
+ private int minimumTabWidth;
+ private Rectangle selectedTabDelta;
+
+ private Point tabPanelOffset;
+
+ private int selectedSpacing;
+
+ private Size rowSpacingNormal;
+ private Size rowSpacingButtons;
+ private Size rowSpacingFlatButtons;
+ private int scrollerWidth;
+ private Point focusRectSpacing;
+ private Rectangle tabPageSpacing;
+ private int colSpacing;
+ private int flatButtonSpacing;
+
+ private Point imagePadding;
+
+ private StringFormat defaultFormatting;
+
+ private Rectangle borderThickness;
+
+ #endregion
+
+ #region Properties
+
+ public virtual Size DefaultItemSize {
+ get { return defaultItemSize; }
+ set { defaultItemSize = value; }
+ }
+
+ public virtual Point DefaultPadding {
+ get { return defaultPadding; }
+ set { defaultPadding = value; }
+ }
+
+ public virtual int MinimumTabWidth {
+ get { return minimumTabWidth; }
+ set { minimumTabWidth = value; }
+ }
+
+ public virtual Rectangle SelectedTabDelta {
+ get { return selectedTabDelta; }
+ set { selectedTabDelta = value; }
+ }
+
+ public virtual Point TabPanelOffset {
+ get { return tabPanelOffset; }
+ set { tabPanelOffset = value; }
+ }
+
+ public virtual int SelectedSpacing {
+ get { return selectedSpacing; }
+ set { selectedSpacing = value; }
+ }
+
+ public virtual Size RowSpacingNormal {
+ get { return rowSpacingNormal; }
+ set { rowSpacingNormal = value; }
+ }
+
+ public virtual Size RowSpacingButtons {
+ get { return rowSpacingButtons; }
+ set { rowSpacingButtons = value; }
+ }
+
+ public virtual Size RowSpacingFlatButtons {
+ get { return rowSpacingFlatButtons; }
+ set { rowSpacingFlatButtons = value; }
+ }
+
+ public virtual Point FocusRectSpacing {
+ get { return focusRectSpacing; }
+ set { focusRectSpacing = value; }
+ }
+
+ public virtual int ColSpacing {
+ get { return colSpacing; }
+ set { colSpacing = value; }
+ }
+
+ public virtual int FlatButtonSpacing {
+ get { return flatButtonSpacing; }
+ set { flatButtonSpacing = value; }
+ }
+
+ public virtual Rectangle TabPageSpacing {
+ get { return tabPageSpacing; }
+ set { tabPageSpacing = value; }
+ }
+
+ public virtual Point ImagePadding {
+ get { return imagePadding; }
+ set { imagePadding = value; }
+ }
+
+ public virtual StringFormat DefaultFormatting {
+ get { return defaultFormatting; }
+ set { defaultFormatting = value; }
+ }
+
+ public virtual Rectangle BorderThickness {
+ get { return borderThickness; }
+ set { borderThickness = value; }
+ }
+
+ public virtual int ScrollerWidth {
+ get { return scrollerWidth; }
+ set { scrollerWidth = value; }
+ }
+
+ public virtual Size RowSpacing (ShiftUI.TabWidget tab) {
+ switch (tab.Appearance) {
+ case TabAppearance.Normal:
+ return rowSpacingNormal;
+ case TabAppearance.Buttons:
+ return rowSpacingButtons;
+ case TabAppearance.FlatButtons:
+ return rowSpacingFlatButtons;
+ default:
+ throw new Exception ("Invalid Appearance value: " + tab.Appearance);
+ }
+ }
+ #endregion
+
+ public TabWidgetPainter ()
+ {
+ defaultItemSize = new Size (42, 16);
+ defaultPadding = new Point (6, 3);
+ selectedTabDelta = new Rectangle (2, 2, 4, 3);
+ selectedSpacing = 0;
+
+ rowSpacingNormal = new Size (0, 0);
+ rowSpacingButtons = new Size (3, 3);
+ rowSpacingFlatButtons = new Size (9, 3);
+
+ colSpacing = 0;
+
+ minimumTabWidth = 42;
+ scrollerWidth = 17;
+ focusRectSpacing = new Point (2, 2);
+ tabPanelOffset = new Point (4, 0);
+ flatButtonSpacing = 8;
+ tabPageSpacing = new Rectangle (4, 2, 3, 4);
+
+ imagePadding = new Point (2, 3);
+
+ defaultFormatting = new StringFormat();
+ // Horizontal Alignment is handled in the Draw method
+ defaultFormatting.Alignment = StringAlignment.Near;
+ defaultFormatting.LineAlignment = StringAlignment.Center;
+ defaultFormatting.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
+ defaultFormatting.HotkeyPrefix = HotkeyPrefix.Show;
+
+ borderThickness = new Rectangle (1, 1, 2, 2);
+ }
+
+ public virtual Rectangle GetLeftScrollRect (ShiftUI.TabWidget tab)
+ {
+ switch (tab.Alignment) {
+ case TabAlignment.Top:
+ return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth * 2), tab.ClientRectangle.Top + 1, scrollerWidth, scrollerWidth);
+ default:
+ Rectangle panel_rect = GetTabPanelRect (tab);
+ return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth * 2), panel_rect.Bottom + 2, scrollerWidth, scrollerWidth);
+ }
+ }
+
+ public virtual Rectangle GetRightScrollRect (ShiftUI.TabWidget tab)
+ {
+ switch (tab.Alignment) {
+ case TabAlignment.Top:
+ return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth), tab.ClientRectangle.Top + 1, scrollerWidth, scrollerWidth);
+ default:
+ Rectangle panel_rect = GetTabPanelRect (tab);
+ return new Rectangle (tab.ClientRectangle.Right - (scrollerWidth), panel_rect.Bottom + 2, scrollerWidth, scrollerWidth);
+ }
+ }
+
+ public Rectangle GetDisplayRectangle (ShiftUI.TabWidget tab)
+ {
+ Rectangle ext = GetTabPanelRect (tab);
+ // Account for border size
+ return new Rectangle (ext.Left + tabPageSpacing.X, ext.Top + tabPageSpacing.Y,
+ ext.Width - tabPageSpacing.X - tabPageSpacing.Width, ext.Height - tabPageSpacing.Y - tabPageSpacing.Height);
+ }
+
+ public Rectangle GetTabPanelRect (ShiftUI.TabWidget tab)
+ {
+ // Offset the tab page (panel) from the top corner
+ Rectangle res = tab.ClientRectangle;
+
+ if (tab.TabCount == 0)
+ return res;
+
+ int spacing = RowSpacing (tab).Height;
+ int tabOffset = (tab.ItemSize.Height + spacing - selectedTabDelta.Height) * tab.RowCount + selectedTabDelta.Y;
+ switch (tab.Alignment) {
+ case TabAlignment.Top:
+ res.Y += tabOffset;
+ res.Height -= tabOffset;
+ break;
+ case TabAlignment.Bottom:
+ res.Height -= tabOffset;
+ break;
+ case TabAlignment.Left:
+ res.X += tabOffset;
+ res.Width -= tabOffset;
+ break;
+ case TabAlignment.Right:
+ res.Width -= tabOffset;
+ break;
+ }
+
+ return res;
+ }
+
+ public virtual void Draw (Graphics dc, Rectangle area, TabWidget tab)
+ {
+ DrawBackground (dc, area, tab);
+
+ int start = 0;
+ int end = tab.TabPages.Count;
+ int delta = 1;
+
+ if (tab.Alignment == TabAlignment.Top) {
+ start = end;
+ end = 0;
+ delta = -1;
+ }
+
+ if (tab.SizeMode == TabSizeMode.Fixed)
+ defaultFormatting.Alignment = StringAlignment.Center;
+ else
+ defaultFormatting.Alignment = StringAlignment.Near;
+
+ int counter = start;
+ for (; counter != end; counter += delta) {
+ for (int i = tab.SliderPos; i < tab.TabPages.Count; i++) {
+ if (i == tab.SelectedIndex)
+ continue;
+ if (counter != tab.TabPages[i].Row)
+ continue;
+ Rectangle rect = tab.GetTabRect (i);
+ if (!rect.IntersectsWith (area))
+ continue;
+ DrawTab (dc, tab.TabPages[i], tab, rect, false);
+ }
+ }
+
+ if (tab.SelectedIndex != -1 && tab.SelectedIndex >= tab.SliderPos) {
+ Rectangle rect = tab.GetTabRect (tab.SelectedIndex);
+ if (rect.IntersectsWith (area))
+ DrawTab (dc, tab.TabPages[tab.SelectedIndex], tab, rect, true);
+ }
+
+ if (tab.ShowSlider) {
+ Rectangle right = GetRightScrollRect (tab);
+ Rectangle left = GetLeftScrollRect (tab);
+ DrawScrollButton (dc, right, area, ScrollButton.Right, tab.RightSliderState);
+ DrawScrollButton (dc, left, area, ScrollButton.Left, tab.LeftSliderState);
+ }
+ }
+
+ protected virtual void DrawScrollButton (Graphics dc, Rectangle bounds, Rectangle clippingArea, ScrollButton button, PushButtonState state)
+ {
+ WidgetPaint.DrawScrollButton (dc, bounds, button, GetButtonState (state));
+ }
+
+ static ButtonState GetButtonState (PushButtonState state)
+ {
+ switch (state) {
+ case PushButtonState.Pressed:
+ return ButtonState.Pushed;
+ default:
+ return ButtonState.Normal;
+ }
+ }
+
+ protected virtual void DrawBackground (Graphics dc, Rectangle area, TabWidget tab)
+ {
+ Brush brush = SystemBrushes.Control;
+ dc.FillRectangle (brush, area);
+ Rectangle panel_rect = GetTabPanelRect (tab);
+
+ if (tab.Appearance == TabAppearance.Normal) {
+ WidgetPaint.DrawBorder3D (dc, panel_rect, Border3DStyle.RaisedInner, Border3DSide.Left | Border3DSide.Top);
+ WidgetPaint.DrawBorder3D (dc, panel_rect, Border3DStyle.Raised, Border3DSide.Right | Border3DSide.Bottom);
+ }
+ }
+
+ protected virtual int DrawTab (Graphics dc, ShiftUI.TabPage page, ShiftUI.TabWidget tab, Rectangle bounds, bool is_selected)
+ {
+ Rectangle interior;
+ int res = bounds.Width;
+
+ dc.FillRectangle (ResPool.GetSolidBrush (tab.BackColor), bounds);
+
+ if (tab.Appearance == TabAppearance.Buttons || tab.Appearance == TabAppearance.FlatButtons) {
+ // Separators
+ if (tab.Appearance == TabAppearance.FlatButtons) {
+ int width = bounds.Width;
+ bounds.Width += (flatButtonSpacing - 2);
+ res = bounds.Width;
+ if (tab.Alignment == TabAlignment.Top || tab.Alignment == TabAlignment.Bottom)
+ ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Etched, Border3DSide.Right);
+ else
+ ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Etched, Border3DSide.Top);
+ bounds.Width = width;
+ }
+
+ if (is_selected) {
+ ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Sunken, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
+ } else if (tab.Appearance != TabAppearance.FlatButtons) {
+ ThemeEngine.Current.CPDrawBorder3D (dc, bounds, Border3DStyle.Raised, Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
+ }
+
+
+ } else {
+ CPColor cpcolor = ResPool.GetCPColor (tab.BackColor);
+
+ Pen light = ResPool.GetPen (cpcolor.LightLight);
+
+ switch (tab.Alignment) {
+
+ case TabAlignment.Top:
+
+ dc.DrawLine (light, bounds.Left, bounds.Bottom - 1, bounds.Left, bounds.Top + 3);
+ dc.DrawLine (light, bounds.Left, bounds.Top + 3, bounds.Left + 2, bounds.Top);
+ dc.DrawLine (light, bounds.Left + 2, bounds.Top, bounds.Right - 3, bounds.Top);
+
+ dc.DrawLine (SystemPens.ControlDark, bounds.Right - 2, bounds.Top + 1, bounds.Right - 2, bounds.Bottom - 1);
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 2, bounds.Top + 1, bounds.Right - 1, bounds.Top + 2);
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 1, bounds.Top + 2, bounds.Right - 1, bounds.Bottom - 1);
+ break;
+
+ case TabAlignment.Bottom:
+
+ dc.DrawLine (light, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom - 2);
+ dc.DrawLine (light, bounds.Left, bounds.Bottom - 2, bounds.Left + 3, bounds.Bottom);
+
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Left + 3, bounds.Bottom, bounds.Right - 3, bounds.Bottom);
+ dc.DrawLine (SystemPens.ControlDark, bounds.Left + 3, bounds.Bottom - 1, bounds.Right - 3, bounds.Bottom - 1);
+
+ dc.DrawLine (SystemPens.ControlDark, bounds.Right - 2, bounds.Bottom - 1, bounds.Right - 2, bounds.Top + 1);
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 2, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 2);
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right - 1, bounds.Bottom - 2, bounds.Right - 1, bounds.Top + 1);
+
+ break;
+
+ case TabAlignment.Left:
+
+ dc.DrawLine (light, bounds.Left - 2, bounds.Top, bounds.Right, bounds.Top);
+ dc.DrawLine (light, bounds.Left, bounds.Top + 2, bounds.Left - 2, bounds.Top);
+ dc.DrawLine (light, bounds.Left, bounds.Top + 2, bounds.Left, bounds.Bottom - 2);
+
+ dc.DrawLine (SystemPens.ControlDark, bounds.Left, bounds.Bottom - 2, bounds.Left + 2, bounds.Bottom - 1);
+
+ dc.DrawLine (SystemPens.ControlDark, bounds.Left + 2, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1);
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Left + 2, bounds.Bottom, bounds.Right, bounds.Bottom);
+
+ break;
+
+ default: // TabAlignment.Right
+
+ dc.DrawLine (light, bounds.Left, bounds.Top, bounds.Right - 3, bounds.Top);
+ dc.DrawLine (light, bounds.Right - 3, bounds.Top, bounds.Right, bounds.Top + 3);
+
+ dc.DrawLine (SystemPens.ControlDark, bounds.Right - 1, bounds.Top + 1, bounds.Right - 1, bounds.Bottom - 1);
+ dc.DrawLine (SystemPens.ControlDark, bounds.Left, bounds.Bottom - 1, bounds.Right - 2, bounds.Bottom - 1);
+
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Right, bounds.Top + 3, bounds.Right, bounds.Bottom - 3);
+ dc.DrawLine (SystemPens.ControlDarkDark, bounds.Left, bounds.Bottom, bounds.Right - 3, bounds.Bottom);
+
+ break;
+ }
+ }
+
+ Point padding = tab.Padding;
+ interior = new Rectangle (bounds.Left + padding.X - 1, // substract a little offset
+ bounds.Top + padding.Y,
+ bounds.Width - (padding.X * 2),
+ bounds.Height - (padding.Y * 2));
+
+ if (tab.DrawMode == TabDrawMode.Normal && page.Text != null) {
+ if (tab.Alignment == TabAlignment.Left) {
+ dc.TranslateTransform (bounds.Left, bounds.Bottom);
+ dc.RotateTransform (-90);
+ dc.DrawString (page.Text, tab.Font,
+ SystemBrushes.ControlText,
+ tab.Padding.X - 2, // drawstring adds some extra unwanted leading spaces, so trimming
+ tab.Padding.Y,
+ defaultFormatting);
+ dc.ResetTransform ();
+ } else if (tab.Alignment == TabAlignment.Right) {
+ dc.TranslateTransform (bounds.Right, bounds.Top);
+ dc.RotateTransform (90);
+ dc.DrawString (page.Text, tab.Font,
+ SystemBrushes.ControlText,
+ tab.Padding.X - 2, // drawstring adds some extra unwanted leading spaces, so trimming
+ tab.Padding.Y,
+ defaultFormatting);
+ dc.ResetTransform ();
+ } else {
+ Rectangle str_rect = interior;
+
+ if (is_selected) {
+ // Reduce the interior size to match the inner size of non-selected tabs
+ str_rect.X += selectedTabDelta.X;
+ str_rect.Y += selectedTabDelta.Y;
+ str_rect.Width -= selectedTabDelta.Width;
+ str_rect.Height -= selectedTabDelta.Height;
+
+ str_rect.Y -= selectedTabDelta.Y; // Move up the text / image of the selected tab
+ }
+
+ if (tab.ImageList != null && page.ImageIndex >= 0 && page.ImageIndex < tab.ImageList.Images.Count) {
+ int image_x;
+ if (tab.SizeMode != TabSizeMode.Fixed) {
+ image_x = str_rect.X;
+ }
+ else {
+ image_x = str_rect.X + (str_rect.Width - tab.ImageList.ImageSize.Width) / 2;
+ if (page.Text != null) {
+ SizeF textSize = dc.MeasureString(page.Text, page.Font, str_rect.Size);
+ image_x -= (int)(textSize.Width / 2);
+ }
+ }
+ int image_y = str_rect.Y + (str_rect.Height - tab.ImageList.ImageSize.Height) / 2;
+ tab.ImageList.Draw (dc, new Point (image_x, image_y), page.ImageIndex);
+ str_rect.X += tab.ImageList.ImageSize.Width + 2;
+ str_rect.Width -= tab.ImageList.ImageSize.Width + 2;
+ }
+ dc.DrawString (page.Text, tab.Font,
+ SystemBrushes.ControlText,
+ str_rect,
+ defaultFormatting);
+
+ }
+ } else if (page.Text != null) {
+ DrawItemState state = DrawItemState.None;
+ if (page == tab.SelectedTab)
+ state |= DrawItemState.Selected;
+ DrawItemEventArgs e = new DrawItemEventArgs (dc,
+ tab.Font, bounds, tab.IndexForTabPage (page),
+ state, page.ForeColor, page.BackColor);
+ tab.OnDrawItemInternal (e);
+ return res;
+ }
+
+ // TabWidget ignores the value of ShowFocusCues
+ if (page.Parent.Focused && is_selected) {
+ Rectangle focus_rect = bounds;
+ focus_rect.Inflate (-2, -2);
+ ThemeEngine.Current.CPDrawFocusRectangle (dc, focus_rect, tab.BackColor, tab.ForeColor);
+ }
+
+ return res;
+ }
+
+ public virtual bool HasHotElementStyles (TabWidget tabWidget) {
+ return false;
+ }
+ }
+}