Tabs Studio Blog (organizing Visual Studio document tabs)

November 6, 2010

Tab coloring simplified

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 4:37 pm

Trying to reduce necessity to manually craft a XAML style, I’ve added presentation parameters and tab coloring rules to Tabs Studio. While a custom XAML style allows seamless integration of different visual adornments together, it takes some time to make it right. Presentation parameters are a new layer between a default style and a custom style. It implements most common style options thus simplifying a custom XAML style.

Presentation is a new tab in Tabs Studio options and it replaces the Quick Style dialog. Font size, Close tab button style and Animation are now presentation options instead of a part of Quick Style generated style. Selected tab style, Previously selected tab and Non-document tab options from the old Quick Style dialog can now be represented as tab coloring rules:

Presentation parameters

Presentation parameters


Selected tab style XP rule

Selected tab style XP rule


Previously selected tab rule

Previously selected tab rule


Non-document tab rule

Non-document tab rule

A tab coloring rule has 5 filtering options and a definition for a tab background brush. Checked boolean options apply the rule to tabs with the corresponding property set to True (e.g. IsTabSelected), unchecked – to False and undefined – to all tabs. Regular expression options apply Regex.IsMatch with the corresponding property (e.g. TabName) when the regex is not empty (see Regular Expression Language Elements MSDN page for .NET regular expressions details).

Two more examples. The Forms rule applies to tabs with the name starting from Form when this tab is not selected and not previously selected. The WindowsFormsApplication1 project rule applies when tab’s project name contains WindowsFormsApplication1 and tab name doesn’t start from Form.

Forms rule

Forms rule


WindowsFormsApplication1 project rule

WindowsFormsApplication1 project rule

Tab background definition must be a Brush descendant. Different options to specify a color in XAML are listed on the Color documentation page.

Everything that presentation parameters do can be achieved in a XAML style. For example, the following style is equivalent to what a tab coloring rule generates internally:

<Style TargetType="TabsStudio:Tab" BasedOn="{StaticResource DefaultTabStyle}">
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Path=IsTabSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
                <Condition Binding="{Binding Path=IsPreviouslySelectedTab, RelativeSource={RelativeSource Self}}" Value="False"/>
                <Condition Binding="{Binding Path=IsDocument, RelativeSource={RelativeSource Self}}" Value="True"/>
                <Condition Binding="{Binding Path=TabName, RelativeSource={RelativeSource Self}, 
                		Converter={StaticResource RegexMatch},ConverterParameter='^Class'}" Value="True"/>
                <Condition Binding="{Binding Path=ProjectName, RelativeSource={RelativeSource Self}, 
                		Converter={StaticResource RegexMatch},ConverterParameter='^Windows'}" Value="True"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background">
                <Setter.Value>
                     <SolidColorBrush Color="Red"/>
                </Setter.Value>
            </Setter>  
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

There is one more convenience feature to set tab color. On the right click context menu there is now the Set color… command:

Set color context menu command

Set color context menu command

When adding a new rule using this command the options are pre-populated with the tab item parameters and when a matching rule(s) already exists then the Set Color choice dialog is presented:

Set color choce dialog

Set color choce dialog

Download link: TabsStudio v2.1.6.

October 20, 2010

Limiting number of tab rows

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 8:37 am

Due to popular demand and new tabs panel customization capabilities in Tabs Studio v2.1.2, I’ve created the SingleRow add-in that allows you to limit maximum number of tab rows and show remaining tabs in a drop-down list similar to default Visual Studio behavior:

A single row of tabs and the drop-down list of hidden tabs

A single row of tabs and the drop-down list of hidden tabs


To use SingleRow you need to set tabs layout to Wrap and apply the following style changes:
The Wrap tabs layout option

The Wrap tabs layout option

<Style TargetType="TabsStudio:TabsHost" BasedOn="{StaticResource DefaultTabsHostStyle}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type TabsStudio:TabsHost}">
        <Grid>
          <Rectangle Width="{TemplateBinding Width}"
                     Height="{TemplateBinding Height}"
                     Fill="{TemplateBinding Background}"/>
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="*"/>
              <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <ContentPresenter Grid.Column="0"/>
            <TabsStudioSingleRow:HiddenTabs Grid.Column="1" TabsPanel="{TemplateBinding ContentControl.Content}"/>
          </Grid>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<Style TargetType="TabsStudio:Tab" BasedOn="{StaticResource DefaultTabStyle}">
  <Style.Triggers>
    <Trigger Property="TabsStudioSingleRow:Properties.IsTabHidden" Value="True">
      <Setter Property="Visibility"  Value="Collapsed"/>
    </Trigger>
  </Style.Triggers>
</Style>

<Style TargetType="TabsStudioSingleRow:HiddenTabs">
  <Setter Property="Content" Value=">"/>
  <Setter Property="Margin" Value="2,0,2,0"/>
  <Setter Property="VerticalAlignment" Value="Center"/>
  <Style.Triggers>
    <Trigger Property="TabsStudioSingleRow:Properties.IsHiddenTabs" Value="False">
      <Setter Property="Visibility"  Value="Collapsed"/>
    </Trigger>
  </Style.Triggers>
</Style>

This style adds the TabsStudioSingleRow:HiddenTabs button to open the drop-down list and binds it to the corresponding TabsPanel. SingleRow doesn’t actually hide tabs – it only sets the IsTabHidden property for them. The style above sets tab visibility based on this property. HiddenTabs button’s appearance is also defined in this style and the button is collapsed when there are no hidden tabs.

Tabs are hidden in the least recently used order and don’t automatically reappear even when space becomes available. Hidden tabs in the drop-down list are sorted alphabetically.

Default number of tab rows is 1, but you can change it in the SingleRow add-in options dialog:

SingleRow options dialog

SingleRow options dialog


Two rows of tabs and the hidden tabs list

Two rows of tabs and the hidden tabs list


Download link: SingleRow v1.0.0.

September 22, 2010

Visual Studio 2008 style explained

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 8:16 am

Please, read the Overlapping sloped tabs post first for the general approach to tab shape customization. Let’s have a closer look at default tabs in Visual Studio 2008:

Tabs in Visual Studio 2008 (2x zoom)

Tabs in Visual Studio 2008 (2x zoom)


Below the tabs you can see the frame border that is overlapped by the selected tab. Tabs Studio window with tabs overlaps default tabs and two pixels of this border. In the Visual Studio 2008 style for Tabs Studio we are going to recreate overlapped top of the border:

<Border Height="2" BorderBrush="#69A1BF" BorderThickness="1,1,1,0" Background="White"/>

Selected tab needs to overlap the border. For that we increase z-index for tabs panel with background from 0 to 1 and later specify bottom margin for the selected tab as -2:

          <Grid Panel.ZIndex="1">
          ...
          <Trigger Property="IsTabSelected" Value="True">                           <!--Selected tab-->
            <Setter Property="Margin" Value="0,2,-9,-2"/>

Right margin for tabs is set to -9: it is amount of horizontal overlap between the adjacent tabs. With negative right margin the right border of tabs also overlaps the last tab in a row. To prevent overlap of the last tab in a row, we set buffering right margin of tabs to 10:

<Style TargetType="TabsStudio:Tabs" BasedOn="{StaticResource DefaultTabsStyle}">
  <Setter Property="Margin" Value="0,0,10,0"/>
</Style>

The selected tab has different shape, background and border comparing to default tabs. We create separate descriptions for these properties depending on the value of the IsTabSelected property. For the selected tab, the left side geometry is the following figure:

                <PathGeometry>
                  <PathFigure StartPoint="4 21">
                    <LineSegment Point="-16 21" IsStroked="false"/>
                    <LineSegment Point="-16 18.5" IsStroked="false"/>
                    <BezierSegment Point1="-1 1" Point2="-1 1" Point3="4 0" IsStroked="true" IsSmoothJoin="true"/>
                  </PathFigure>
                </PathGeometry>

The top bound of this figure is 0 – this is the rule for sides in Shaper. The right bound of this figure is 4 – making the slope overlap the tab contents by 4 pixels. An additional segment is automatically added by WPF from the end point to the start point to close the figure. For choosing Bezier control point values (Point1 and Point2) you can try the BezierExperimenter sample code from the “Applications = Code + Markup” book, chapter 28 (C# download, VB download).

The left bound of the right side figure is -3 – making the right side figure overlap the tab contents by 3 pixels (it doesn’t actually overlap the tab name because tab content has right margin 4):

                <PathGeometry>
                  <PathFigure StartPoint="-3 21">
                    <LineSegment Point="-1 21" IsStroked="false"/>
                    <LineSegment Point="-1 18.5" IsStroked="false"/>
                    <LineSegment Point="-1 2" IsStroked="true"/>
                    <LineSegment Point="-3 0" IsStroked="true"/>
                  </PathFigure>
                </PathGeometry>

The selected tab is 2 pixels higher than normal tabs – it has top margin 2 while normal tabs have top margin 4. Finally, selected tab font is bold and there is no close tab button:

<Style TargetType="TabsStudio:TabName" BasedOn="{StaticResource DefaultTabNameStyle}">
  <Style.Triggers>
    <Trigger Property="IsTabSelected" Value="True">
      <Setter Property="Control.FontWeight" Value="Bold"/>
    </Trigger>
  </Style.Triggers>
</Style>

<Style TargetType="TabsStudio:CloseTabButton" BasedOn="{StaticResource DefaultCloseTabButtonStyle}">
  <Setter Property="Visibility" Value="Collapsed"/>
</Style>

Here is the final Visual Studio 2008 style:

Visual Studio 2008 style in Tabs Studio (2x zoom)

Visual Studio 2008 style in Tabs Studio (2x zoom)

September 21, 2010

Overlapping sloped tabs

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 7:39 pm

I’ve extended Tabs Studio and created the Shaper add-in to make it possible to create customizable sloped tabs in Tabs Studio. To test the new capabilities, I tried to emulate default tabs of Visual Studio 2008 and Google Chrome. The results look almost exactly the same:

Tabs in Visual Studio 2008

Tabs in Visual Studio 2008


Visual Studio 2008 style in Tabs Studio

Visual Studio 2008 style in Tabs Studio


Tabs in Google Chrome

Tabs in Google Chrome


Chrome style in Tabs Studio

Chrome style in Tabs Studio

I’ll describe the new Visual Studio 2008 style in the next post. For now, let’s see what was added to Tabs Studio and how Shaper works.

TabsHost in Tabs Studio

Control tree now has a new root element TabsHost. The new root of the style specification is now:

TabsHost : ContentControl
|
 - Tabs : Panel (IsGroupSelected, IsGroupFocused for VS 2010, IsGroupWithLastActiveDocument for VS 2010)
   |
   ...

Introduction of TabsHost allows a tabs panel to be shifted and makes possible addition of other visual elements and controls at the tabs panel level. The DefaultTabsHostStyle is already a template using a rectangle behind the tabs to draw a background:

<Style x:Key="DefaultTabsHostStyle" TargetType="TabsStudio:TabsHost">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type TabsStudio:TabsHost}">
        <Grid>
          <Rectangle Width="{TemplateBinding Width}"
                     Height="{TemplateBinding Height}"
                     Fill="{TemplateBinding Background}"/>
          <ContentPresenter/>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Shaper

The first function of the Shaper add-in is to manage z-order of tabs so that tab #1 overlaps tab #2, tab #2 overlaps tab #3 and so on (default z-order is inverse). Shaper also sets z-index for the selected tab to overlap all others.

The second function of Shaper is the TabShape control. It is similar to the Border control, but specialized for trapezoid tabs. TabShape has LeftSide and RightSide properties of type Geometry plus Background Brush and Border Pen properties.

TabShape draws the central rectangular part of the trapezoid scaled to the tab content, draws the top border, draws sides and places tab content in the “middle”. Specifying negative and positive coordinates for left and right sides you control how sides overlap the content. All TabShape properties can be dynamically customized in style depending for example on whether tab is selected or not. Here is an example of the LeftSide geometry for the selected tab from the Visual Studio 2008 style (IsStroked property for each segment controls whether it drawn or not):

<Setter TargetName="TabShape" Property="LeftSide">
  <Setter.Value>
    <PathGeometry>
      <PathFigure StartPoint="4 21">
        <LineSegment Point="-16 21" IsStroked="false"/>
        <LineSegment Point="-16 18.5" IsStroked="false"/>
        <BezierSegment Point1="-1 1" Point2="-1 1" Point3="4 0" IsStroked="true" IsSmoothJoin="true"/>
      </PathFigure>
    </PathGeometry>
  </Setter.Value>
</Setter>

Download links

August 26, 2010

ASP.NET MVC tabs grouping and coloring

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 1:29 pm

I’ve created the MvcGroup add-in that groups ASP.NET MVC controller and view tabs near each other (a controller is placed before views). This add-in also adds IsController, IsView and GroupName properties that can be used to color MVC tabs by type and/or by group name. See the following two examples:

<Style TargetType="TabsStudio:Tab" BasedOn="{StaticResource DefaultTabStyle}">
  <Style.Triggers>
    <MultiTrigger>
      <MultiTrigger.Conditions>
        <Condition Property="TabsStudioMvcGroup:Properties.IsController" Value="True"/>
        <Condition Property="IsTabSelected" Value="False"/>
      </MultiTrigger.Conditions>
      <Setter Property="Background">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <GradientStop Color="#F5F5F5" Offset="0"/>
            <GradientStop Color="#B0D0B0" Offset="1"/>
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </MultiTrigger>
    <MultiTrigger>
      <MultiTrigger.Conditions>
        <Condition Property="TabsStudioMvcGroup:Properties.IsView" Value="True"/>
        <Condition Property="IsTabSelected" Value="False"/>
      </MultiTrigger.Conditions>
      <Setter Property="Background">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <GradientStop Color="#F5F5F5" Offset="0"/>
            <GradientStop Color="#B0B0D0" Offset="1"/>
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </MultiTrigger>
  </Style.Triggers>
</Style>
ASP.NET MVC tabs grouping and coloring by type

ASP.NET MVC tabs grouping and coloring by type

<Style TargetType="TabsStudio:Tab" BasedOn="{StaticResource DefaultTabStyle}">
  <Style.Triggers>
    <MultiTrigger>
      <MultiTrigger.Conditions>
        <Condition Property="TabsStudioMvcGroup:Properties.GroupName" Value="Account"/>
        <Condition Property="IsTabSelected" Value="False"/>
      </MultiTrigger.Conditions>
      <Setter Property="Background">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <GradientStop Color="#F5F5F5" Offset="0"/>
            <GradientStop Color="#B0D0B0" Offset="1"/>
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </MultiTrigger>
    <MultiTrigger>
      <MultiTrigger.Conditions>
        <Condition Property="TabsStudioMvcGroup:Properties.GroupName" Value="Home"/>
        <Condition Property="IsTabSelected" Value="False"/>
      </MultiTrigger.Conditions>
      <Setter Property="Background">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <GradientStop Color="#F5F5F5" Offset="0"/>
            <GradientStop Color="#B0B0D0" Offset="1"/>
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </MultiTrigger>
  </Style.Triggers>
</Style>
ASP.NET MVC tabs grouping and coloring by group name

ASP.NET MVC tabs grouping and coloring by group name

Download link: MvcGroup v1.0.0.

August 20, 2010

Per project tab coloring

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 8:52 am

As the Decorator add-in demonstrated, it is easy to add project properties to tabs and use it for coloring. I decided to write the separate Projector add-in that explicitly adds the project name property to tabs.

With the Projector installed, to color tabs for the ClassLibrary2 project with purple you can use the following style:

<Style TargetType="TabsStudio:Tab" BasedOn="{StaticResource DefaultTabStyle}">
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="TabsStudioProjector:Properties.ProjectName" Value="ClassLibrary2"/>
                <Condition Property="IsTabSelected" Value="False"/>
            </MultiTrigger.Conditions>
            <Setter Property="Background">
                <Setter.Value>
                     <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                         <GradientStop Color="#F5F5F5" Offset="0"/>
                         <GradientStop Color="#B0B0F0" Offset="1"/>
                     </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </MultiTrigger>
    </Style.Triggers>
</Style>
Purple tab from the ClassLibrary2 project

Purple tab from the ClassLibrary2 project

Finding and assigning a distinct color for each project in a solution could be hard. Assigning a single color to a group of projects is more practical, except WPF doesn’t have direct capability to trigger match between a project name and a list of names. Projector adds custom IsAnyOfConverter inherited from System.Windows.Data.IValueConverter to support this scenario. The custom Convert function of the converter receives tab’s project name as the value parameter, comma separated list of project names for a color as the parameter parameter and returns true if tab’s project name is in the list:

public object Convert(object value, System.Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
{
    string[] allowedValues = ((string)parameter).Split(new System.Char[] { ',' });
    return ((System.Collections.Generic.IList)allowedValues).Contains((string)value);
}

To use this converter in XAML we define it as a static resource and invoke in a data trigger:

<TabsStudioProjector:IsAnyOfConverter x:Key="IsAnyOf" />

<Style TargetType="TabsStudio:Tab" BasedOn="{StaticResource DefaultTabStyle}">
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Path=(TabsStudioProjector:Properties.ProjectName), 
                        RelativeSource={RelativeSource Self}, 
                        Converter={StaticResource IsAnyOf},
                        ConverterParameter='ClassLibrary3,ClassLibrary4'}" 
                        Value="True"/>
                <Condition Binding="{Binding Path=IsTabSelected, RelativeSource={RelativeSource Self}}" Value="False"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background">
                <Setter.Value>
                     <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                         <GradientStop Color="#F5F5F5" Offset="0"/>
                         <GradientStop Color="#A0C0A0" Offset="1"/>
                     </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </MultiDataTrigger>
    </Style.Triggers>
</Style>
Green tabs from the ClassLibrary3 and ClassLibrary4 projects

Green tabs from the ClassLibrary3 and ClassLibrary4 projects

Using the same technique it is possible, for example, to create a regex converter matching tab’s project name with a regular expression specified as the parameter.

Download link: Projector v1.0.

May 8, 2010

Styling tabs in a separate window

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 7:43 pm

In Visual Studio 2010 default style for tabs uses left and right margins of 1 pixel:

<Style x:Key="DefaultTabsStyle" TargetType="TabsStudio:Tabs">
  <Setter Property="Margin" Value="1,0,1,0"/>
</Style>

It makes transition between Tabs Studio tabs and Visual Studio border under the tabs in the left and right corners smooth:

Left tab margin

Left tab margin


When tabs are in a separate window, default margins create white lines to the left and to the right of the tabs:
White lines to the left and to the right of the tabs

White lines to the left and to the right of the tabs


Setting margins to 0 removes these lines:

<Style TargetType="TabsStudio:Tabs" BasedOn="{StaticResource DefaultTabsStyle}">
  <Setter Property="Margin" Value="0,0,0,0"/>
</Style>

Excessive tabs margins removed

Excessive tabs margins removed

Another useful customization for tabs in a separate window is tabs background. The default background in VS 2010 style is transparent, it results in dark blue for normal tabs placement and white for tabs in a separate window. As an example, the following style sets tabs background to dark blue:

<Style TargetType="TabsStudio:Tabs" BasedOn="{StaticResource DefaultTabsStyle}">
  <Setter Property="Background" Value="#293955"/>
</Style>

Dark blue tabs background

Dark blue tabs background


A similar style can be used to customize tabs background in VS 2008, which is by default grey control brush.

April 13, 2010

Updated Visual Studio 2010 tab style

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 11:38 am

I’ve changed selected tab colors to match the default VS 2010 theme – yellow for active, dark blue for inactive and grey for unfocused:

Active and inactive tabs

Active and inactive tabs


Unfocused tabs

Unfocused tabs

April 12, 2010

Close file buttons

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 10:41 pm

I’ve added the close file button to each extension. It should be particularly useful in SSMS where you more often need to close a file rather than a whole tab:

Close file buttons in SSMS

Close file buttons in SSMS


In the default style these buttons are collapsed, but you can use all usual properties in a custom style to make them visible. For example, the following style makes close file buttons visible on the selected tab and hides the close tab button in a tab when it contains more than a one extension:

<Style TargetType="TabsStudio:TabExtensionCloseButton" BasedOn="{StaticResource DefaultTabExtensionCloseButton}">
  <Style.Triggers>
    <Trigger Property="IsTabSelected" Value="True">
      <Setter Property="Visibility" Value="Visible"/>
    </Trigger>
  </Style.Triggers>
</Style>

<Style TargetType="TabsStudio:CloseTabButton" BasedOn="{StaticResource DefaultCloseTabButtonStyle}">
  <Style.Triggers>
    <Trigger Property="IsMultiExtensions" Value="True">
      <Setter Property="Visibility" Value="Collapsed"/>
    </Trigger>
  </Style.Triggers>
</Style>

January 23, 2010

Visual Studio 2010 Silver theme

Filed under: Uncategorized — Tags: , — Sergey Vlasov @ 3:24 pm

This month Matthew Johnson released the Visual Studio Color Theme Editor extension for Visual Studio 2010. This extension allows users to customize colors used by Visual Studio 2010 and contains three example themes (Autumn, Emerald and Silver):

Default Visual Studio 2010 theme

Default Visual Studio 2010 theme


Visual Studio 2010 Silver theme

Visual Studio 2010 Silver theme


Jameel Al-Aziz, in addition to his Tabs Studio 2010 style, has created Tabs Studio 2010 Silver theme style:
Tabs Studio 2010 Silver theme style

Tabs Studio 2010 Silver theme style


Get Tabs Studio 2010 Silver theme style by Jameel Al-Aziz (Visual Studio 2010 Beta 2 and Tabs Studio v1.7.6 or greater required).

« Newer PostsOlder Posts »

Blog at WordPress.com.