Tabs Studio Blog (organizing Visual Studio document tabs)

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 27, 2010

Preinstalled Tabs Studio add-ins

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

I’ve included the most popular Tabs Studio add-ins in the Tabs Studio installer, so that you don’t have to download and install them separately:

Preinstalled Tabs Studio add-ins in the new Add-in Manager window

Preinstalled Tabs Studio add-ins in the new Add-in Manager window

After installation all these add-ins are disabled. You can easily enable them checking the Startup option in the new Add-in Manager window. Restart of Visual Studio is still required to actually load or unload add-ins. Internally, an active add-in is a regular dll file in the Add-in installation folder, while a disabled add-in is the same file renamed to have the inactive extension.

For loaded add-ins that support configuration via the TabsStudioExt.IConfigurable interface, the Options button is displayed. See the Navigator add-in as an example.

Download link: Tabs Studio v2.1.2.

September 22, 2010

New group for all

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 12:35 pm

I’ve found that in Visual Studio 2008 Window.TileHorizontally and Window.TileVertically commands can be called to create a new horizontal or vertical tab group. I’ve tested it in SSMS 2005, SSMS 2008 R2 and VS 2005 – it works for them too. I’ve added these commands to the NewGroup add-in (that previously supported only VS 2010 with Window.NewHorizontalTabGroup and Window.NewVerticalTabGroup commands):

New tab group context menu commands in Visual Studio 2008

New tab group context menu commands in Visual Studio 2008


Download link: NewGroup v1.0.1.

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

September 19, 2010

Cycle tab when navigating

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 2:21 pm

The Navigator add-in adds NavigateToNextTab and NavigateToPreviousTab commands to navigate tabs using keyboard. These commands stop when they reach the first or the last tab. This week Chee-Hung Loh posted to the Tabs Studio mail list code for NavigateToNextTab go to first tab if the selected tab is the last tab and NavigateToPreviousTab go to the last tab if the selected tab is the first tab. And then added an option to select between the default and new behavior. To access navigator options go to Add-in Manager, select Navigator and press Configure:

Navigator Options

Navigator Options

I’ve also added the NavigateToLastTab command for symmetry with NavigateToTab1:

Navigate to last tab shortcut keys assignment

Navigate to last tab shortcut keys assignment

Download link: Navigator v1.0.3.

September 12, 2010

Switching to a specific tab number

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 3:11 pm

Popular browsers such as IE, Firefox and Chrome have CTRL+n keyboard shortcuts to switch to a specific tab number. I’ve added similar functionality to Navigator. You can assign any shortcut keys to TabsStudio.Connect.NavigateToTabXX commands and quickly navigate to the first 20 tabs in Tabs Studio:

Keyboard shortcut options in Visual Studio

Keyboard shortcut options in Visual Studio

Download link: Navigator v1.0.2.

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.

August 12, 2010

Extensions ordering

Filed under: Uncategorized — Tags: — Sergey Vlasov @ 11:01 pm

By default extensions in a tab are alphabetically sorted. The new OrderEx add-in allows you to specify custom order for extensions. For example, by default OrderEx places .h extension before .cpp:

Custom extensions order

Custom extensions order

In the add-in, priorityExtensions array specifies order of extensions. Extensions not found in this array are placed after specified ones:

private string[] priorityExtensions = { ".h", ".cpp" };

It is highly recommended to use Tabs Studio v2.1.0 or greater with this add-in, otherwise custom ordering may be occasionally reset to default.

Download link: OrderEx v1.0.

June 28, 2010

NewGroup add-in for VS 2010

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

I’m often asked about the missing New horizontal/vertical tab group commands in the Tabs Studio context menu. Due to technical difficulties I can’t come up with a good overall solution for it, but now that Visual Studio 2010 introduces two new Window.NewHorizontalTabGroup and Window.NewVerticalTabGroup commands I can solve the most common case with an add-in:

New tab group commands

New tab group commands

The NewGroup add-in adds the New horizontal/vertical tab group commands to the Tabs Studio context menu for the selected tab/extension if commands are available. For example, the New horizontal tab group command is not available when vertical tab groups already created and both commands are not available when there is only one tab in a selected group. In Tabs Studio you can open a tab context menu without making the tab selected – in this case the two new commands are not shown as it is much harder to determine if they should be available in this case.

Download the NewGroup add-in for VS 2010.

« Newer PostsOlder Posts »

Blog at WordPress.com.