Files
wxWidgets/src/aui/tabart.cpp
Vadim Zeitlin 1e30d94eff Fix border size computation in wxAuiTabArt.
Space was reserved for the borders even when it wasn't filled, resulting in
visual artefacts. Fix this by virtualizing the function returning the
additional space needed for the borders and only overriding it to return non
zero in wxAuiGtkTabArt.

Closes #14710.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72720 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-10-22 21:46:46 +00:00

1321 lines
38 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/aui/tabart.cpp
// Purpose: wxaui: wx advanced user interface - notebook-art
// Author: Benjamin I. Williams
// Modified by: Jens Lody (moved from auibook.cpp in extra file)
// Created: 2012-03-21
// RCS-ID: $Id:$
// Copyright: (C) Copyright 2006, Kirix Corporation, All Rights Reserved
// Licence: wxWindows Library Licence, Version 3.1
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_AUI
#ifndef WX_PRECOMP
#include "wx/dc.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
#include "wx/bitmap.h"
#include "wx/menu.h"
#endif
#include "wx/renderer.h"
#include "wx/aui/auibook.h"
#include "wx/aui/framemanager.h"
#include "wx/aui/dockart.h"
#ifdef __WXMAC__
#include "wx/osx/private.h"
#endif
// -- GUI helper classes and functions --
class wxAuiCommandCapture : public wxEvtHandler
{
public:
wxAuiCommandCapture() { m_lastId = 0; }
int GetCommandId() const { return m_lastId; }
bool ProcessEvent(wxEvent& evt)
{
if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
{
m_lastId = evt.GetId();
return true;
}
if (GetNextHandler())
return GetNextHandler()->ProcessEvent(evt);
return false;
}
private:
int m_lastId;
};
// these functions live in dockart.cpp -- they'll eventually
// be moved to a new utility cpp file
wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h,
const wxColour& color);
wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size);
static void DrawButtons(wxDC& dc,
const wxRect& _rect,
const wxBitmap& bmp,
const wxColour& bkcolour,
int button_state)
{
wxRect rect = _rect;
if (button_state == wxAUI_BUTTON_STATE_PRESSED)
{
rect.x++;
rect.y++;
}
if (button_state == wxAUI_BUTTON_STATE_HOVER ||
button_state == wxAUI_BUTTON_STATE_PRESSED)
{
dc.SetBrush(wxBrush(bkcolour.ChangeLightness(120)));
dc.SetPen(wxPen(bkcolour.ChangeLightness(75)));
// draw the background behind the button
dc.DrawRectangle(rect.x, rect.y, 15, 15);
}
// draw the button itself
dc.DrawBitmap(bmp, rect.x, rect.y, true);
}
static void IndentPressedBitmap(wxRect* rect, int button_state)
{
if (button_state == wxAUI_BUTTON_STATE_PRESSED)
{
rect->x++;
rect->y++;
}
}
// -- bitmaps --
#if defined( __WXMAC__ )
static const unsigned char close_bits[]={
0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
#elif defined( __WXGTK__)
static const unsigned char close_bits[]={
0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#else
static const unsigned char close_bits[]={
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
#endif
static const unsigned char left_bits[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char right_bits[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char list_bits[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// -- wxAuiGenericTabArt class implementation --
wxAuiGenericTabArt::wxAuiGenericTabArt()
{
m_normalFont = *wxNORMAL_FONT;
m_selectedFont = *wxNORMAL_FONT;
m_selectedFont.SetWeight(wxBOLD);
m_measuringFont = m_selectedFont;
m_fixedTabWidth = 100;
m_tabCtrlHeight = 0;
#if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
wxColor baseColour = wxColour( wxMacCreateCGColorFromHITheme(kThemeBrushToolbarBackground));
#else
wxColor baseColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
#endif
// the baseColour is too pale to use as our base colour,
// so darken it a bit --
if ((255-baseColour.Red()) +
(255-baseColour.Green()) +
(255-baseColour.Blue()) < 60)
{
baseColour = baseColour.ChangeLightness(92);
}
m_activeColour = baseColour;
m_baseColour = baseColour;
wxColor borderColour = baseColour.ChangeLightness(75);
m_borderPen = wxPen(borderColour);
m_baseColourPen = wxPen(m_baseColour);
m_baseColourBrush = wxBrush(m_baseColour);
m_activeCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
m_disabledCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
m_activeLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
m_disabledLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
m_activeRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
m_disabledRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
m_activeWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
m_disabledWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
m_flags = 0;
}
wxAuiGenericTabArt::~wxAuiGenericTabArt()
{
}
wxAuiTabArt* wxAuiGenericTabArt::Clone()
{
return new wxAuiGenericTabArt(*this);
}
void wxAuiGenericTabArt::SetFlags(unsigned int flags)
{
m_flags = flags;
}
void wxAuiGenericTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
size_t tab_count)
{
m_fixedTabWidth = 100;
int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
if (m_flags & wxAUI_NB_CLOSE_BUTTON)
tot_width -= m_activeCloseBmp.GetWidth();
if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
tot_width -= m_activeWindowListBmp.GetWidth();
if (tab_count > 0)
{
m_fixedTabWidth = tot_width/(int)tab_count;
}
if (m_fixedTabWidth < 100)
m_fixedTabWidth = 100;
if (m_fixedTabWidth > tot_width/2)
m_fixedTabWidth = tot_width/2;
if (m_fixedTabWidth > 220)
m_fixedTabWidth = 220;
m_tabCtrlHeight = tab_ctrl_size.y;
}
void wxAuiGenericTabArt::DrawBorder(wxDC& dc, wxWindow* wnd, const wxRect& rect)
{
int i, border_width = GetBorderWidth(wnd);
wxRect theRect(rect);
for (i = 0; i < border_width; ++i)
{
dc.DrawRectangle(theRect.x, theRect.y, theRect.width, theRect.height);
theRect.Deflate(1);
}
}
void wxAuiGenericTabArt::DrawBackground(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxRect& rect)
{
// draw background
wxColor top_color = m_baseColour.ChangeLightness(90);
wxColor bottom_color = m_baseColour.ChangeLightness(170);
wxRect r;
if (m_flags &wxAUI_NB_BOTTOM)
r = wxRect(rect.x, rect.y, rect.width+2, rect.height);
// TODO: else if (m_flags &wxAUI_NB_LEFT) {}
// TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
else //for wxAUI_NB_TOP
r = wxRect(rect.x, rect.y, rect.width+2, rect.height-3);
dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
// draw base lines
dc.SetPen(m_borderPen);
int y = rect.GetHeight();
int w = rect.GetWidth();
if (m_flags &wxAUI_NB_BOTTOM)
{
dc.SetBrush(wxBrush(bottom_color));
dc.DrawRectangle(-1, 0, w+2, 4);
}
// TODO: else if (m_flags &wxAUI_NB_LEFT) {}
// TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
else //for wxAUI_NB_TOP
{
dc.SetBrush(m_baseColourBrush);
dc.DrawRectangle(-1, y-4, w+2, 4);
}
}
// DrawTab() draws an individual tab.
//
// dc - output dc
// in_rect - rectangle the tab should be confined to
// caption - tab's caption
// active - whether or not the tab is active
// out_rect - actual output rectangle
// x_extent - the advance x; where the next tab should start
void wxAuiGenericTabArt::DrawTab(wxDC& dc,
wxWindow* wnd,
const wxAuiNotebookPage& page,
const wxRect& in_rect,
int close_button_state,
wxRect* out_tab_rect,
wxRect* out_button_rect,
int* x_extent)
{
wxCoord normal_textx, normal_texty;
wxCoord selected_textx, selected_texty;
wxCoord texty;
// if the caption is empty, measure some temporary text
wxString caption = page.caption;
if (caption.empty())
caption = wxT("Xj");
dc.SetFont(m_selectedFont);
dc.GetTextExtent(caption, &selected_textx, &selected_texty);
dc.SetFont(m_normalFont);
dc.GetTextExtent(caption, &normal_textx, &normal_texty);
// figure out the size of the tab
wxSize tab_size = GetTabSize(dc,
wnd,
page.caption,
page.bitmap,
page.active,
close_button_state,
x_extent);
wxCoord tab_height = m_tabCtrlHeight - 3;
wxCoord tab_width = tab_size.x;
wxCoord tab_x = in_rect.x;
wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
caption = page.caption;
// select pen, brush and font for the tab to be drawn
if (page.active)
{
dc.SetFont(m_selectedFont);
texty = selected_texty;
}
else
{
dc.SetFont(m_normalFont);
texty = normal_texty;
}
// create points that will make the tab outline
int clip_width = tab_width;
if (tab_x + clip_width > in_rect.x + in_rect.width)
clip_width = (in_rect.x + in_rect.width) - tab_x;
/*
wxPoint clip_points[6];
clip_points[0] = wxPoint(tab_x, tab_y+tab_height-3);
clip_points[1] = wxPoint(tab_x, tab_y+2);
clip_points[2] = wxPoint(tab_x+2, tab_y);
clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y);
clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2);
clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3);
// FIXME: these ports don't provide wxRegion ctor from array of points
#if !defined(__WXDFB__) && !defined(__WXCOCOA__)
// set the clipping region for the tab --
wxRegion clipping_region(WXSIZEOF(clip_points), clip_points);
dc.SetClippingRegion(clipping_region);
#endif // !wxDFB && !wxCocoa
*/
// since the above code above doesn't play well with WXDFB or WXCOCOA,
// we'll just use a rectangle for the clipping region for now --
dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3);
wxPoint border_points[6];
if (m_flags &wxAUI_NB_BOTTOM)
{
border_points[0] = wxPoint(tab_x, tab_y);
border_points[1] = wxPoint(tab_x, tab_y+tab_height-6);
border_points[2] = wxPoint(tab_x+2, tab_y+tab_height-4);
border_points[3] = wxPoint(tab_x+tab_width-2, tab_y+tab_height-4);
border_points[4] = wxPoint(tab_x+tab_width, tab_y+tab_height-6);
border_points[5] = wxPoint(tab_x+tab_width, tab_y);
}
else //if (m_flags & wxAUI_NB_TOP) {}
{
border_points[0] = wxPoint(tab_x, tab_y+tab_height-4);
border_points[1] = wxPoint(tab_x, tab_y+2);
border_points[2] = wxPoint(tab_x+2, tab_y);
border_points[3] = wxPoint(tab_x+tab_width-2, tab_y);
border_points[4] = wxPoint(tab_x+tab_width, tab_y+2);
border_points[5] = wxPoint(tab_x+tab_width, tab_y+tab_height-4);
}
// TODO: else if (m_flags &wxAUI_NB_LEFT) {}
// TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
int drawn_tab_yoff = border_points[1].y;
int drawn_tab_height = border_points[0].y - border_points[1].y;
if (page.active)
{
// draw active tab
// draw base background color
wxRect r(tab_x, tab_y, tab_width, tab_height);
dc.SetPen(wxPen(m_activeColour));
dc.SetBrush(wxBrush(m_activeColour));
dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4);
// this white helps fill out the gradient at the top of the tab
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4);
// these two points help the rounded corners appear more antialiased
dc.SetPen(wxPen(m_activeColour));
dc.DrawPoint(r.x+2, r.y+1);
dc.DrawPoint(r.x+r.width-2, r.y+1);
// set rectangle down a bit for gradient drawing
r.SetHeight(r.GetHeight()/2);
r.x += 2;
r.width -= 3;
r.y += r.height;
r.y -= 2;
// draw gradient background
wxColor top_color = *wxWHITE;
wxColor bottom_color = m_activeColour;
dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
}
else
{
// draw inactive tab
wxRect r(tab_x, tab_y+1, tab_width, tab_height-3);
// start the gradent up a bit and leave the inside border inset
// by a pixel for a 3D look. Only the top half of the inactive
// tab will have a slight gradient
r.x += 3;
r.y++;
r.width -= 4;
r.height /= 2;
r.height--;
// -- draw top gradient fill for glossy look
wxColor top_color = m_baseColour;
wxColor bottom_color = top_color.ChangeLightness(160);
dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
r.y += r.height;
r.y--;
// -- draw bottom fill for glossy look
top_color = m_baseColour;
bottom_color = m_baseColour;
dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
}
// draw tab outline
dc.SetPen(m_borderPen);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawPolygon(WXSIZEOF(border_points), border_points);
// there are two horizontal grey lines at the bottom of the tab control,
// this gets rid of the top one of those lines in the tab control
if (page.active)
{
if (m_flags &wxAUI_NB_BOTTOM)
dc.SetPen(wxPen(m_baseColour.ChangeLightness(170)));
// TODO: else if (m_flags &wxAUI_NB_LEFT) {}
// TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
else //for wxAUI_NB_TOP
dc.SetPen(m_baseColourPen);
dc.DrawLine(border_points[0].x+1,
border_points[0].y,
border_points[5].x,
border_points[5].y);
}
int text_offset = tab_x + 8;
int close_button_width = 0;
if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
{
close_button_width = m_activeCloseBmp.GetWidth();
}
int bitmap_offset = 0;
if (page.bitmap.IsOk())
{
bitmap_offset = tab_x + 8;
// draw bitmap
dc.DrawBitmap(page.bitmap,
bitmap_offset,
drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
true);
text_offset = bitmap_offset + page.bitmap.GetWidth();
text_offset += 3; // bitmap padding
}
else
{
text_offset = tab_x + 8;
}
wxString draw_text = wxAuiChopText(dc,
caption,
tab_width - (text_offset-tab_x) - close_button_width);
// draw tab text
dc.DrawText(draw_text,
text_offset,
drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1);
// draw focus rectangle
if (page.active && (wnd->FindFocus() == wnd))
{
wxRect focusRectText(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1),
selected_textx, selected_texty);
wxRect focusRect;
wxRect focusRectBitmap;
if (page.bitmap.IsOk())
focusRectBitmap = wxRect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
page.bitmap.GetWidth(), page.bitmap.GetHeight());
if (page.bitmap.IsOk() && draw_text.IsEmpty())
focusRect = focusRectBitmap;
else if (!page.bitmap.IsOk() && !draw_text.IsEmpty())
focusRect = focusRectText;
else if (page.bitmap.IsOk() && !draw_text.IsEmpty())
focusRect = focusRectText.Union(focusRectBitmap);
focusRect.Inflate(2, 2);
wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0);
}
// draw close button if necessary
if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
{
wxBitmap bmp = m_disabledCloseBmp;
if (close_button_state == wxAUI_BUTTON_STATE_HOVER ||
close_button_state == wxAUI_BUTTON_STATE_PRESSED)
{
bmp = m_activeCloseBmp;
}
int offsetY = tab_y-1;
if (m_flags & wxAUI_NB_BOTTOM)
offsetY = 1;
wxRect rect(tab_x + tab_width - close_button_width - 1,
offsetY + (tab_height/2) - (bmp.GetHeight()/2),
close_button_width,
tab_height);
IndentPressedBitmap(&rect, close_button_state);
dc.DrawBitmap(bmp, rect.x, rect.y, true);
*out_button_rect = rect;
}
*out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
dc.DestroyClippingRegion();
}
int wxAuiGenericTabArt::GetIndentSize()
{
return 5;
}
int wxAuiGenericTabArt::GetBorderWidth(wxWindow* wnd)
{
wxAuiManager* mgr = wxAuiManager::GetManager(wnd);
if (mgr)
{
wxAuiDockArt* art = mgr->GetArtProvider();
if (art)
return art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
}
return 1;
}
int wxAuiGenericTabArt::GetAdditionalBorderSpace(wxWindow* WXUNUSED(wnd))
{
return 0;
}
wxSize wxAuiGenericTabArt::GetTabSize(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxString& caption,
const wxBitmap& bitmap,
bool WXUNUSED(active),
int close_button_state,
int* x_extent)
{
wxCoord measured_textx, measured_texty, tmp;
dc.SetFont(m_measuringFont);
dc.GetTextExtent(caption, &measured_textx, &measured_texty);
dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty);
// add padding around the text
wxCoord tab_width = measured_textx;
wxCoord tab_height = measured_texty;
// if the close button is showing, add space for it
if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
tab_width += m_activeCloseBmp.GetWidth() + 3;
// if there's a bitmap, add space for it
if (bitmap.IsOk())
{
tab_width += bitmap.GetWidth();
tab_width += 3; // right side bitmap padding
tab_height = wxMax(tab_height, bitmap.GetHeight());
}
// add padding
tab_width += 16;
tab_height += 10;
if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
{
tab_width = m_fixedTabWidth;
}
*x_extent = tab_width;
return wxSize(tab_width, tab_height);
}
void wxAuiGenericTabArt::DrawButton(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxRect& in_rect,
int bitmap_id,
int button_state,
int orientation,
wxRect* out_rect)
{
wxBitmap bmp;
wxRect rect;
switch (bitmap_id)
{
case wxAUI_BUTTON_CLOSE:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledCloseBmp;
else
bmp = m_activeCloseBmp;
break;
case wxAUI_BUTTON_LEFT:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledLeftBmp;
else
bmp = m_activeLeftBmp;
break;
case wxAUI_BUTTON_RIGHT:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledRightBmp;
else
bmp = m_activeRightBmp;
break;
case wxAUI_BUTTON_WINDOWLIST:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledWindowListBmp;
else
bmp = m_activeWindowListBmp;
break;
}
if (!bmp.IsOk())
return;
rect = in_rect;
if (orientation == wxLEFT)
{
rect.SetX(in_rect.x);
rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
rect.SetWidth(bmp.GetWidth());
rect.SetHeight(bmp.GetHeight());
}
else
{
rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
bmp.GetWidth(), bmp.GetHeight());
}
IndentPressedBitmap(&rect, button_state);
dc.DrawBitmap(bmp, rect.x, rect.y, true);
*out_rect = rect;
}
int wxAuiGenericTabArt::ShowDropDown(wxWindow* wnd,
const wxAuiNotebookPageArray& pages,
int /*active_idx*/)
{
wxMenu menuPopup;
size_t i, count = pages.GetCount();
for (i = 0; i < count; ++i)
{
const wxAuiNotebookPage& page = pages.Item(i);
wxString caption = page.caption;
// if there is no caption, make it a space. This will prevent
// an assert in the menu code.
if (caption.IsEmpty())
caption = wxT(" ");
wxMenuItem* item = new wxMenuItem(NULL, 1000+i, caption);
if (page.bitmap.IsOk())
item->SetBitmap(page.bitmap);
menuPopup.Append(item);
}
// find out where to put the popup menu of window items
wxPoint pt = ::wxGetMousePosition();
pt = wnd->ScreenToClient(pt);
// find out the screen coordinate at the bottom of the tab ctrl
wxRect cli_rect = wnd->GetClientRect();
pt.y = cli_rect.y + cli_rect.height;
wxAuiCommandCapture* cc = new wxAuiCommandCapture;
wnd->PushEventHandler(cc);
wnd->PopupMenu(&menuPopup, pt);
int command = cc->GetCommandId();
wnd->PopEventHandler(true);
if (command >= 1000)
return command-1000;
return -1;
}
int wxAuiGenericTabArt::GetBestTabCtrlSize(wxWindow* wnd,
const wxAuiNotebookPageArray& pages,
const wxSize& requiredBmp_size)
{
wxClientDC dc(wnd);
dc.SetFont(m_measuringFont);
// sometimes a standard bitmap size needs to be enforced, especially
// if some tabs have bitmaps and others don't. This is important because
// it prevents the tab control from resizing when tabs are added.
wxBitmap measureBmp;
if (requiredBmp_size.IsFullySpecified())
{
measureBmp.Create(requiredBmp_size.x,
requiredBmp_size.y);
}
int max_y = 0;
size_t i, page_count = pages.GetCount();
for (i = 0; i < page_count; ++i)
{
wxAuiNotebookPage& page = pages.Item(i);
wxBitmap bmp;
if (measureBmp.IsOk())
bmp = measureBmp;
else
bmp = page.bitmap;
// we don't use the caption text because we don't
// want tab heights to be different in the case
// of a very short piece of text on one tab and a very
// tall piece of text on another tab
int x_ext = 0;
wxSize s = GetTabSize(dc,
wnd,
wxT("ABCDEFGHIj"),
bmp,
true,
wxAUI_BUTTON_STATE_HIDDEN,
&x_ext);
max_y = wxMax(max_y, s.y);
}
return max_y+2;
}
void wxAuiGenericTabArt::SetNormalFont(const wxFont& font)
{
m_normalFont = font;
}
void wxAuiGenericTabArt::SetSelectedFont(const wxFont& font)
{
m_selectedFont = font;
}
void wxAuiGenericTabArt::SetMeasuringFont(const wxFont& font)
{
m_measuringFont = font;
}
void wxAuiGenericTabArt::SetColour(const wxColour& colour)
{
m_baseColour = colour;
m_borderPen = wxPen(m_baseColour.ChangeLightness(75));
m_baseColourPen = wxPen(m_baseColour);
m_baseColourBrush = wxBrush(m_baseColour);
}
void wxAuiGenericTabArt::SetActiveColour(const wxColour& colour)
{
m_activeColour = colour;
}
// -- wxAuiSimpleTabArt class implementation --
wxAuiSimpleTabArt::wxAuiSimpleTabArt()
{
m_normalFont = *wxNORMAL_FONT;
m_selectedFont = *wxNORMAL_FONT;
m_selectedFont.SetWeight(wxBOLD);
m_measuringFont = m_selectedFont;
m_flags = 0;
m_fixedTabWidth = 100;
wxColour baseColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
wxColour backgroundColour = baseColour;
wxColour normaltabColour = baseColour;
wxColour selectedtabColour = *wxWHITE;
m_bkBrush = wxBrush(backgroundColour);
m_normalBkBrush = wxBrush(normaltabColour);
m_normalBkPen = wxPen(normaltabColour);
m_selectedBkBrush = wxBrush(selectedtabColour);
m_selectedBkPen = wxPen(selectedtabColour);
m_activeCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
m_disabledCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
m_activeLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
m_disabledLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
m_activeRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
m_disabledRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
m_activeWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
m_disabledWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
}
wxAuiSimpleTabArt::~wxAuiSimpleTabArt()
{
}
wxAuiTabArt* wxAuiSimpleTabArt::Clone()
{
return new wxAuiSimpleTabArt(*this);
}
void wxAuiSimpleTabArt::SetFlags(unsigned int flags)
{
m_flags = flags;
}
void wxAuiSimpleTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
size_t tab_count)
{
m_fixedTabWidth = 100;
int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
if (m_flags & wxAUI_NB_CLOSE_BUTTON)
tot_width -= m_activeCloseBmp.GetWidth();
if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
tot_width -= m_activeWindowListBmp.GetWidth();
if (tab_count > 0)
{
m_fixedTabWidth = tot_width/(int)tab_count;
}
if (m_fixedTabWidth < 100)
m_fixedTabWidth = 100;
if (m_fixedTabWidth > tot_width/2)
m_fixedTabWidth = tot_width/2;
if (m_fixedTabWidth > 220)
m_fixedTabWidth = 220;
}
void wxAuiSimpleTabArt::SetColour(const wxColour& colour)
{
m_bkBrush = wxBrush(colour);
m_normalBkBrush = wxBrush(colour);
m_normalBkPen = wxPen(colour);
}
void wxAuiSimpleTabArt::SetActiveColour(const wxColour& colour)
{
m_selectedBkBrush = wxBrush(colour);
m_selectedBkPen = wxPen(colour);
}
void wxAuiSimpleTabArt::DrawBorder(wxDC& dc, wxWindow* wnd, const wxRect& rect)
{
int i, border_width = GetBorderWidth(wnd);
wxRect theRect(rect);
for (i = 0; i < border_width; ++i)
{
dc.DrawRectangle(theRect.x, theRect.y, theRect.width, theRect.height);
theRect.Deflate(1);
}
}
void wxAuiSimpleTabArt::DrawBackground(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxRect& rect)
{
// draw background
dc.SetBrush(m_bkBrush);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
// draw base line
dc.SetPen(*wxGREY_PEN);
dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
}
// DrawTab() draws an individual tab.
//
// dc - output dc
// in_rect - rectangle the tab should be confined to
// caption - tab's caption
// active - whether or not the tab is active
// out_rect - actual output rectangle
// x_extent - the advance x; where the next tab should start
void wxAuiSimpleTabArt::DrawTab(wxDC& dc,
wxWindow* wnd,
const wxAuiNotebookPage& page,
const wxRect& in_rect,
int close_button_state,
wxRect* out_tab_rect,
wxRect* out_button_rect,
int* x_extent)
{
wxCoord normal_textx, normal_texty;
wxCoord selected_textx, selected_texty;
wxCoord textx, texty;
// if the caption is empty, measure some temporary text
wxString caption = page.caption;
if (caption.empty())
caption = wxT("Xj");
dc.SetFont(m_selectedFont);
dc.GetTextExtent(caption, &selected_textx, &selected_texty);
dc.SetFont(m_normalFont);
dc.GetTextExtent(caption, &normal_textx, &normal_texty);
// figure out the size of the tab
wxSize tab_size = GetTabSize(dc,
wnd,
page.caption,
page.bitmap,
page.active,
close_button_state,
x_extent);
wxCoord tab_height = tab_size.y;
wxCoord tab_width = tab_size.x;
wxCoord tab_x = in_rect.x;
wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
caption = page.caption;
// select pen, brush and font for the tab to be drawn
if (page.active)
{
dc.SetPen(m_selectedBkPen);
dc.SetBrush(m_selectedBkBrush);
dc.SetFont(m_selectedFont);
textx = selected_textx;
texty = selected_texty;
}
else
{
dc.SetPen(m_normalBkPen);
dc.SetBrush(m_normalBkBrush);
dc.SetFont(m_normalFont);
textx = normal_textx;
texty = normal_texty;
}
// -- draw line --
wxPoint points[7];
points[0].x = tab_x;
points[0].y = tab_y + tab_height - 1;
points[1].x = tab_x + tab_height - 3;
points[1].y = tab_y + 2;
points[2].x = tab_x + tab_height + 3;
points[2].y = tab_y;
points[3].x = tab_x + tab_width - 2;
points[3].y = tab_y;
points[4].x = tab_x + tab_width;
points[4].y = tab_y + 2;
points[5].x = tab_x + tab_width;
points[5].y = tab_y + tab_height - 1;
points[6] = points[0];
dc.SetClippingRegion(in_rect);
dc.DrawPolygon(WXSIZEOF(points) - 1, points);
dc.SetPen(*wxGREY_PEN);
//dc.DrawLines(active ? WXSIZEOF(points) - 1 : WXSIZEOF(points), points);
dc.DrawLines(WXSIZEOF(points), points);
int text_offset;
int close_button_width = 0;
if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
{
close_button_width = m_activeCloseBmp.GetWidth();
text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2);
}
else
{
text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2);
}
// set minimum text offset
if (text_offset < tab_x + tab_height)
text_offset = tab_x + tab_height;
// chop text if necessary
wxString draw_text = wxAuiChopText(dc,
caption,
tab_width - (text_offset-tab_x) - close_button_width);
// draw tab text
dc.DrawText(draw_text,
text_offset,
(tab_y + tab_height)/2 - (texty/2) + 1);
// draw focus rectangle
if (page.active && (wnd->FindFocus() == wnd))
{
wxRect focusRect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1),
selected_textx, selected_texty);
focusRect.Inflate(2, 2);
wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0);
}
// draw close button if necessary
if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
{
wxBitmap bmp;
if (page.active)
bmp = m_activeCloseBmp;
else
bmp = m_disabledCloseBmp;
wxRect rect(tab_x + tab_width - close_button_width - 1,
tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
close_button_width,
tab_height - 1);
DrawButtons(dc, rect, bmp, *wxWHITE, close_button_state);
*out_button_rect = rect;
}
*out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
dc.DestroyClippingRegion();
}
int wxAuiSimpleTabArt::GetIndentSize()
{
return 0;
}
int wxAuiSimpleTabArt::GetBorderWidth(wxWindow* wnd)
{
wxAuiManager* mgr = wxAuiManager::GetManager(wnd);
if (mgr)
{
wxAuiDockArt* art = mgr->GetArtProvider();
if (art)
return art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
}
return 1;
}
int wxAuiSimpleTabArt::GetAdditionalBorderSpace(wxWindow* WXUNUSED(wnd))
{
return 0;
}
wxSize wxAuiSimpleTabArt::GetTabSize(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxString& caption,
const wxBitmap& WXUNUSED(bitmap),
bool WXUNUSED(active),
int close_button_state,
int* x_extent)
{
wxCoord measured_textx, measured_texty;
dc.SetFont(m_measuringFont);
dc.GetTextExtent(caption, &measured_textx, &measured_texty);
wxCoord tab_height = measured_texty + 4;
wxCoord tab_width = measured_textx + tab_height + 5;
if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
tab_width += m_activeCloseBmp.GetWidth();
if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
{
tab_width = m_fixedTabWidth;
}
*x_extent = tab_width - (tab_height/2) - 1;
return wxSize(tab_width, tab_height);
}
void wxAuiSimpleTabArt::DrawButton(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxRect& in_rect,
int bitmap_id,
int button_state,
int orientation,
wxRect* out_rect)
{
wxBitmap bmp;
wxRect rect;
switch (bitmap_id)
{
case wxAUI_BUTTON_CLOSE:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledCloseBmp;
else
bmp = m_activeCloseBmp;
break;
case wxAUI_BUTTON_LEFT:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledLeftBmp;
else
bmp = m_activeLeftBmp;
break;
case wxAUI_BUTTON_RIGHT:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledRightBmp;
else
bmp = m_activeRightBmp;
break;
case wxAUI_BUTTON_WINDOWLIST:
if (button_state & wxAUI_BUTTON_STATE_DISABLED)
bmp = m_disabledWindowListBmp;
else
bmp = m_activeWindowListBmp;
break;
}
if (!bmp.IsOk())
return;
rect = in_rect;
if (orientation == wxLEFT)
{
rect.SetX(in_rect.x);
rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
rect.SetWidth(bmp.GetWidth());
rect.SetHeight(bmp.GetHeight());
}
else
{
rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
bmp.GetWidth(), bmp.GetHeight());
}
DrawButtons(dc, rect, bmp, *wxWHITE, button_state);
*out_rect = rect;
}
int wxAuiSimpleTabArt::ShowDropDown(wxWindow* wnd,
const wxAuiNotebookPageArray& pages,
int active_idx)
{
wxMenu menuPopup;
size_t i, count = pages.GetCount();
for (i = 0; i < count; ++i)
{
const wxAuiNotebookPage& page = pages.Item(i);
menuPopup.AppendCheckItem(1000+i, page.caption);
}
if (active_idx != -1)
{
menuPopup.Check(1000+active_idx, true);
}
// find out where to put the popup menu of window
// items. Subtract 100 for now to center the menu
// a bit, until a better mechanism can be implemented
wxPoint pt = ::wxGetMousePosition();
pt = wnd->ScreenToClient(pt);
if (pt.x < 100)
pt.x = 0;
else
pt.x -= 100;
// find out the screen coordinate at the bottom of the tab ctrl
wxRect cli_rect = wnd->GetClientRect();
pt.y = cli_rect.y + cli_rect.height;
wxAuiCommandCapture* cc = new wxAuiCommandCapture;
wnd->PushEventHandler(cc);
wnd->PopupMenu(&menuPopup, pt);
int command = cc->GetCommandId();
wnd->PopEventHandler(true);
if (command >= 1000)
return command-1000;
return -1;
}
int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow* wnd,
const wxAuiNotebookPageArray& WXUNUSED(pages),
const wxSize& WXUNUSED(requiredBmp_size))
{
wxClientDC dc(wnd);
dc.SetFont(m_measuringFont);
int x_ext = 0;
wxSize s = GetTabSize(dc,
wnd,
wxT("ABCDEFGHIj"),
wxNullBitmap,
true,
wxAUI_BUTTON_STATE_HIDDEN,
&x_ext);
return s.y+3;
}
void wxAuiSimpleTabArt::SetNormalFont(const wxFont& font)
{
m_normalFont = font;
}
void wxAuiSimpleTabArt::SetSelectedFont(const wxFont& font)
{
m_selectedFont = font;
}
void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont& font)
{
m_measuringFont = font;
}
#endif // wxUSE_AUI