This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
913 lines
27 KiB
C++
913 lines
27 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/gtk/renderer.cpp
|
|
// Purpose: implementation of wxRendererNative for wxGTK
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 20.07.2003
|
|
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// for compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include "wx/renderer.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/window.h"
|
|
#include "wx/dcclient.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/module.h"
|
|
#endif
|
|
|
|
#include "wx/dcgraph.h"
|
|
#ifndef __WXGTK3__
|
|
#include "wx/gtk/dc.h"
|
|
#endif
|
|
|
|
#include <gtk/gtk.h>
|
|
#include "wx/gtk/private.h"
|
|
#include "wx/gtk/private/gtk2-compat.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxRendererGTK: our wxRendererNative implementation
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
|
|
{
|
|
public:
|
|
// draw the header control button (used by wxListCtrl)
|
|
virtual int DrawHeaderButton(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0,
|
|
wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
|
|
wxHeaderButtonParams* params = NULL);
|
|
|
|
virtual int GetHeaderButtonHeight(wxWindow *win);
|
|
|
|
virtual int GetHeaderButtonMargin(wxWindow *win);
|
|
|
|
|
|
// draw the expanded/collapsed icon for a tree control item
|
|
virtual void DrawTreeItemButton(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
|
|
virtual void DrawSplitterBorder(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
virtual void DrawSplitterSash(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxSize& size,
|
|
wxCoord position,
|
|
wxOrientation orient,
|
|
int flags = 0);
|
|
|
|
virtual void DrawComboBoxDropButton(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
|
|
virtual void DrawDropArrow(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
|
|
virtual void DrawCheckBox(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
|
|
virtual void DrawPushButton(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
|
|
virtual void DrawItemSelectionRect(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags = 0);
|
|
|
|
virtual void DrawChoice(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags=0);
|
|
|
|
virtual void DrawComboBox(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags=0);
|
|
|
|
virtual void DrawTextCtrl(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags=0);
|
|
|
|
virtual void DrawRadioBitmap(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags=0);
|
|
|
|
virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
|
|
|
|
virtual wxSize GetCheckBoxSize(wxWindow *win);
|
|
|
|
virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
|
|
};
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
/* static */
|
|
wxRendererNative& wxRendererNative::GetDefault()
|
|
{
|
|
static wxRendererGTK s_rendererGTK;
|
|
|
|
return s_rendererGTK;
|
|
}
|
|
|
|
#ifdef __WXGTK3__
|
|
#define NULL_RECT
|
|
typedef cairo_t wxGTKDrawable;
|
|
|
|
static cairo_t* wxGetGTKDrawable(wxWindow*, const wxDC& dc)
|
|
{
|
|
wxGraphicsContext* gc = dc.GetGraphicsContext();
|
|
wxCHECK_MSG(gc, NULL, "cannot use wxRendererNative on wxDC of this type");
|
|
return static_cast<cairo_t*>(gc->GetNativeContext());
|
|
}
|
|
|
|
static const GtkStateFlags stateTypeToFlags[] = {
|
|
GTK_STATE_FLAG_NORMAL, GTK_STATE_FLAG_ACTIVE, GTK_STATE_FLAG_PRELIGHT,
|
|
GTK_STATE_FLAG_SELECTED, GTK_STATE_FLAG_INSENSITIVE, GTK_STATE_FLAG_INCONSISTENT,
|
|
GTK_STATE_FLAG_FOCUSED
|
|
};
|
|
|
|
#else
|
|
#define NULL_RECT NULL,
|
|
typedef GdkWindow wxGTKDrawable;
|
|
|
|
static GdkWindow* wxGetGTKDrawable(wxWindow* win, wxDC& dc)
|
|
{
|
|
GdkWindow* gdk_window = NULL;
|
|
|
|
#if wxUSE_GRAPHICS_CONTEXT
|
|
if ( wxDynamicCast(&dc, wxGCDC) )
|
|
gdk_window = win->GTKGetDrawingWindow();
|
|
else
|
|
#endif
|
|
{
|
|
wxDCImpl *impl = dc.GetImpl();
|
|
wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
|
|
if (gtk_impl)
|
|
gdk_window = gtk_impl->GetGDKWindow();
|
|
else
|
|
wxFAIL_MSG("cannot use wxRendererNative on wxDC of this type");
|
|
}
|
|
|
|
#if !wxUSE_GRAPHICS_CONTEXT
|
|
wxUnusedVar(win);
|
|
#endif
|
|
|
|
return gdk_window;
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// list/tree controls drawing
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int
|
|
wxRendererGTK::DrawHeaderButton(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags,
|
|
wxHeaderSortIconType sortArrow,
|
|
wxHeaderButtonParams* params)
|
|
{
|
|
GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
|
|
if (flags & wxCONTROL_SPECIAL)
|
|
button = wxGTKPrivate::GetHeaderButtonWidgetFirst();
|
|
if (flags & wxCONTROL_DIRTY)
|
|
button = wxGTKPrivate::GetHeaderButtonWidgetLast();
|
|
|
|
int x_diff = 0;
|
|
if (win->GetLayoutDirection() == wxLayout_RightToLeft)
|
|
x_diff = rect.width;
|
|
|
|
GtkStateType state = GTK_STATE_NORMAL;
|
|
if (flags & wxCONTROL_DISABLED)
|
|
state = GTK_STATE_INSENSITIVE;
|
|
else
|
|
{
|
|
if (flags & wxCONTROL_CURRENT)
|
|
state = GTK_STATE_PRELIGHT;
|
|
}
|
|
|
|
#ifdef __WXGTK3__
|
|
cairo_t* cr = wxGetGTKDrawable(win, dc);
|
|
if (cr)
|
|
{
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(button);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, stateTypeToFlags[state]);
|
|
gtk_render_background(sc, cr, rect.x - x_diff+4, rect.y+4, rect.width-8, rect.height-8);
|
|
gtk_render_frame(sc, cr, rect.x - x_diff+4, rect.y+4, rect.width-8, rect.height-8);
|
|
gtk_style_context_restore(sc);
|
|
}
|
|
#else
|
|
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
|
|
gtk_paint_box
|
|
(
|
|
gtk_widget_get_style(button),
|
|
gdk_window,
|
|
state,
|
|
GTK_SHADOW_OUT,
|
|
NULL,
|
|
button,
|
|
"button",
|
|
dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
|
|
);
|
|
#endif
|
|
|
|
return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
|
|
}
|
|
|
|
int wxRendererGTK::GetHeaderButtonHeight(wxWindow *WXUNUSED(win))
|
|
{
|
|
GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
|
|
|
|
GtkRequisition req;
|
|
#ifdef __WXGTK3__
|
|
gtk_widget_get_preferred_height(button, NULL, &req.height);
|
|
#else
|
|
GTK_WIDGET_GET_CLASS(button)->size_request(button, &req);
|
|
#endif
|
|
|
|
return req.height;
|
|
}
|
|
|
|
int wxRendererGTK::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
|
|
{
|
|
wxFAIL_MSG( "GetHeaderButtonMargin() not implemented" );
|
|
return -1;
|
|
}
|
|
|
|
|
|
// draw a ">" or "v" button
|
|
void
|
|
wxRendererGTK::DrawTreeItemButton(wxWindow* win,
|
|
wxDC& dc, const wxRect& rect, int flags)
|
|
{
|
|
GtkWidget *tree = wxGTKPrivate::GetTreeWidget();
|
|
|
|
GtkStateType state;
|
|
if ( flags & wxCONTROL_CURRENT )
|
|
state = GTK_STATE_PRELIGHT;
|
|
else
|
|
state = GTK_STATE_NORMAL;
|
|
|
|
int x_diff = 0;
|
|
if (win->GetLayoutDirection() == wxLayout_RightToLeft)
|
|
x_diff = rect.width;
|
|
|
|
#ifdef __WXGTK3__
|
|
cairo_t* cr = wxGetGTKDrawable(win, dc);
|
|
if (cr)
|
|
{
|
|
gtk_widget_set_state_flags(tree, stateTypeToFlags[state], true);
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(tree);
|
|
gtk_render_expander(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height);
|
|
}
|
|
#else
|
|
// x and y parameters specify the center of the expander
|
|
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
|
|
if (gdk_window == NULL)
|
|
return;
|
|
gtk_paint_expander
|
|
(
|
|
gtk_widget_get_style(tree),
|
|
gdk_window,
|
|
state,
|
|
NULL,
|
|
tree,
|
|
"treeview",
|
|
dc.LogicalToDeviceX(rect.x) + rect.width / 2 - x_diff,
|
|
dc.LogicalToDeviceY(rect.y) + rect.height / 2,
|
|
flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
|
|
: GTK_EXPANDER_COLLAPSED
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// splitter sash drawing
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static int GetGtkSplitterFullSize(GtkWidget* widget)
|
|
{
|
|
gint handle_size;
|
|
gtk_widget_style_get(widget, "handle_size", &handle_size, NULL);
|
|
|
|
return handle_size;
|
|
}
|
|
|
|
wxSplitterRenderParams
|
|
wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
|
|
{
|
|
// we don't draw any border, hence 0 for the second field
|
|
return wxSplitterRenderParams
|
|
(
|
|
GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
|
|
0,
|
|
true // hot sensitive
|
|
);
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
|
|
wxDC& WXUNUSED(dc),
|
|
const wxRect& WXUNUSED(rect),
|
|
int WXUNUSED(flags))
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawSplitterSash(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxSize& size,
|
|
wxCoord position,
|
|
wxOrientation orient,
|
|
int flags)
|
|
{
|
|
if (gtk_widget_get_window(win->m_wxwindow) == NULL)
|
|
{
|
|
// window not realized yet
|
|
return;
|
|
}
|
|
|
|
wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
|
|
if (drawable == NULL)
|
|
return;
|
|
|
|
// are we drawing vertical or horizontal splitter?
|
|
const bool isVert = orient == wxVERTICAL;
|
|
|
|
GtkWidget* widget = wxGTKPrivate::GetSplitterWidget(orient);
|
|
const int full_size = GetGtkSplitterFullSize(widget);
|
|
|
|
GdkRectangle rect;
|
|
|
|
if ( isVert )
|
|
{
|
|
rect.x = position;
|
|
rect.y = 0;
|
|
rect.width = full_size;
|
|
rect.height = size.y;
|
|
}
|
|
else // horz
|
|
{
|
|
rect.x = 0;
|
|
rect.y = position;
|
|
rect.height = full_size;
|
|
rect.width = size.x;
|
|
}
|
|
|
|
int x_diff = 0;
|
|
if (win->GetLayoutDirection() == wxLayout_RightToLeft)
|
|
x_diff = rect.width;
|
|
|
|
#ifdef __WXGTK3__
|
|
cairo_t* cr = wxGetGTKDrawable(win, dc);
|
|
if (cr)
|
|
{
|
|
gtk_widget_set_state_flags(widget, stateTypeToFlags[flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL], true);
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(widget);
|
|
gtk_render_handle(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height);
|
|
}
|
|
#else
|
|
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
|
|
if (gdk_window == NULL)
|
|
return;
|
|
gtk_paint_handle
|
|
(
|
|
gtk_widget_get_style(win->m_wxwindow),
|
|
gdk_window,
|
|
flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
|
|
GTK_SHADOW_NONE,
|
|
NULL /* no clipping */,
|
|
win->m_wxwindow,
|
|
"paned",
|
|
dc.LogicalToDeviceX(rect.x) - x_diff,
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width,
|
|
rect.height,
|
|
isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawDropArrow(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags)
|
|
{
|
|
GtkWidget *button = wxGTKPrivate::GetButtonWidget();
|
|
|
|
// If we give WX_PIZZA(win->m_wxwindow)->bin_window as
|
|
// a window for gtk_paint_xxx function, then it won't
|
|
// work for wxMemoryDC. So that is why we assume wxDC
|
|
// is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
|
|
// are derived from it) and use its m_window.
|
|
|
|
// draw arrow so that there is even space horizontally
|
|
// on both sides
|
|
const int size = rect.width / 2;
|
|
const int x = rect.x + (size + 1) / 2;
|
|
const int y = rect.y + (rect.height - size + 1) / 2;
|
|
|
|
GtkStateType state;
|
|
|
|
if ( flags & wxCONTROL_PRESSED )
|
|
state = GTK_STATE_ACTIVE;
|
|
else if ( flags & wxCONTROL_DISABLED )
|
|
state = GTK_STATE_INSENSITIVE;
|
|
else if ( flags & wxCONTROL_CURRENT )
|
|
state = GTK_STATE_PRELIGHT;
|
|
else
|
|
state = GTK_STATE_NORMAL;
|
|
|
|
#ifdef __WXGTK3__
|
|
cairo_t* cr = wxGetGTKDrawable(win, dc);
|
|
if (cr)
|
|
{
|
|
gtk_widget_set_state_flags(button, stateTypeToFlags[state], true);
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(button);
|
|
gtk_render_arrow(sc, cr, G_PI, x, y, size);
|
|
}
|
|
#else
|
|
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
|
|
if (gdk_window == NULL)
|
|
return;
|
|
// draw arrow on button
|
|
gtk_paint_arrow
|
|
(
|
|
gtk_widget_get_style(button),
|
|
gdk_window,
|
|
state,
|
|
flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
|
|
NULL,
|
|
button,
|
|
"arrow",
|
|
GTK_ARROW_DOWN,
|
|
FALSE,
|
|
x, y,
|
|
size, size
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags)
|
|
{
|
|
DrawPushButton(win,dc,rect,flags);
|
|
DrawDropArrow(win,dc,rect);
|
|
}
|
|
|
|
wxSize
|
|
wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
|
|
{
|
|
gint indicator_size, indicator_spacing;
|
|
gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
|
|
"indicator_size", &indicator_size,
|
|
"indicator_spacing", &indicator_spacing,
|
|
NULL);
|
|
|
|
int size = indicator_size + indicator_spacing * 2;
|
|
return wxSize(size, size);
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawCheckBox(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags )
|
|
{
|
|
GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
|
|
|
|
gint indicator_size, indicator_spacing;
|
|
gtk_widget_style_get(button,
|
|
"indicator_size", &indicator_size,
|
|
"indicator_spacing", &indicator_spacing,
|
|
NULL);
|
|
|
|
#ifndef __WXGTK3__
|
|
GtkStateType state;
|
|
|
|
if ( flags & wxCONTROL_PRESSED )
|
|
state = GTK_STATE_ACTIVE;
|
|
else if ( flags & wxCONTROL_DISABLED )
|
|
state = GTK_STATE_INSENSITIVE;
|
|
else if ( flags & wxCONTROL_CURRENT )
|
|
state = GTK_STATE_PRELIGHT;
|
|
else
|
|
state = GTK_STATE_NORMAL;
|
|
|
|
GtkShadowType shadow_type;
|
|
|
|
if ( flags & wxCONTROL_UNDETERMINED )
|
|
shadow_type = GTK_SHADOW_ETCHED_IN;
|
|
else if ( flags & wxCONTROL_CHECKED )
|
|
shadow_type = GTK_SHADOW_IN;
|
|
else
|
|
shadow_type = GTK_SHADOW_OUT;
|
|
#endif
|
|
|
|
#ifdef __WXGTK3__
|
|
cairo_t* cr = wxGetGTKDrawable(win, dc);
|
|
if (cr)
|
|
{
|
|
int stateFlags = GTK_STATE_FLAG_NORMAL;
|
|
if (flags & wxCONTROL_CHECKED)
|
|
stateFlags = GTK_STATE_FLAG_ACTIVE;
|
|
if (flags & wxCONTROL_DISABLED)
|
|
stateFlags |= GTK_STATE_FLAG_INSENSITIVE;
|
|
if (flags & wxCONTROL_UNDETERMINED)
|
|
stateFlags |= GTK_STATE_FLAG_INCONSISTENT;
|
|
if (flags & wxCONTROL_CURRENT)
|
|
stateFlags |= GTK_STATE_FLAG_PRELIGHT;
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(button);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, GtkStateFlags(stateFlags));
|
|
gtk_style_context_add_class(sc, GTK_STYLE_CLASS_CHECK);
|
|
gtk_render_check(sc, cr,
|
|
rect.x + (rect.width - indicator_size) / 2,
|
|
rect.y + (rect.height - indicator_size) / 2,
|
|
indicator_size, indicator_size);
|
|
gtk_style_context_restore(sc);
|
|
}
|
|
#else
|
|
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
|
|
if (gdk_window == NULL)
|
|
return;
|
|
|
|
gtk_paint_check
|
|
(
|
|
gtk_widget_get_style(button),
|
|
gdk_window,
|
|
state,
|
|
shadow_type,
|
|
NULL,
|
|
button,
|
|
"cellcheck",
|
|
dc.LogicalToDeviceX(rect.x) + indicator_spacing,
|
|
dc.LogicalToDeviceY(rect.y) + indicator_spacing,
|
|
indicator_size, indicator_size
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawPushButton(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags)
|
|
{
|
|
GtkWidget *button = wxGTKPrivate::GetButtonWidget();
|
|
|
|
// draw button
|
|
GtkStateType state;
|
|
|
|
if ( flags & wxCONTROL_PRESSED )
|
|
state = GTK_STATE_ACTIVE;
|
|
else if ( flags & wxCONTROL_DISABLED )
|
|
state = GTK_STATE_INSENSITIVE;
|
|
else if ( flags & wxCONTROL_CURRENT )
|
|
state = GTK_STATE_PRELIGHT;
|
|
else
|
|
state = GTK_STATE_NORMAL;
|
|
|
|
#ifdef __WXGTK3__
|
|
cairo_t* cr = wxGetGTKDrawable(win, dc);
|
|
if (cr)
|
|
{
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(button);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, stateTypeToFlags[state]);
|
|
gtk_render_background(sc, cr, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_render_frame(sc, cr, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_style_context_restore(sc);
|
|
}
|
|
#else
|
|
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
|
|
if (gdk_window == NULL)
|
|
return;
|
|
|
|
gtk_paint_box
|
|
(
|
|
gtk_widget_get_style(button),
|
|
gdk_window,
|
|
state,
|
|
flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
|
|
NULL,
|
|
button,
|
|
"button",
|
|
dc.LogicalToDeviceX(rect.x),
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width,
|
|
rect.height
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
wxRendererGTK::DrawItemSelectionRect(wxWindow* win,
|
|
wxDC& dc,
|
|
const wxRect& rect,
|
|
int flags )
|
|
{
|
|
wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
|
|
if (drawable == NULL)
|
|
return;
|
|
|
|
if (flags & wxCONTROL_SELECTED)
|
|
{
|
|
int x_diff = 0;
|
|
if (win->GetLayoutDirection() == wxLayout_RightToLeft)
|
|
x_diff = rect.width;
|
|
|
|
GtkWidget* treeWidget = wxGTKPrivate::GetTreeWidget();
|
|
|
|
#ifdef __WXGTK3__
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(treeWidget);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, GTK_STATE_FLAG_SELECTED);
|
|
gtk_style_context_add_class(sc, GTK_STYLE_CLASS_CELL);
|
|
gtk_render_background(sc, drawable, rect.x - x_diff, rect.y, rect.width, rect.height);
|
|
gtk_style_context_restore(sc);
|
|
#else
|
|
// the wxCONTROL_FOCUSED state is deduced
|
|
// directly from the m_wxwindow by GTK+
|
|
gtk_paint_flat_box(gtk_widget_get_style(treeWidget),
|
|
drawable,
|
|
GTK_STATE_SELECTED,
|
|
GTK_SHADOW_NONE,
|
|
NULL_RECT
|
|
win->m_wxwindow,
|
|
"cell_even",
|
|
dc.LogicalToDeviceX(rect.x) - x_diff,
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width,
|
|
rect.height );
|
|
#endif
|
|
}
|
|
|
|
if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED))
|
|
DrawFocusRect(win, dc, rect, flags);
|
|
}
|
|
|
|
void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
|
|
{
|
|
wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
|
|
if (drawable == NULL)
|
|
return;
|
|
|
|
GtkStateType state;
|
|
if (flags & wxCONTROL_SELECTED)
|
|
state = GTK_STATE_SELECTED;
|
|
else
|
|
state = GTK_STATE_NORMAL;
|
|
|
|
#ifdef __WXGTK3__
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(win->m_widget);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, stateTypeToFlags[state]);
|
|
gtk_render_focus(sc, drawable, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_style_context_restore(sc);
|
|
#else
|
|
gtk_paint_focus( gtk_widget_get_style(win->m_widget),
|
|
drawable,
|
|
state,
|
|
NULL_RECT
|
|
win->m_wxwindow,
|
|
NULL,
|
|
dc.LogicalToDeviceX(rect.x),
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width,
|
|
rect.height );
|
|
#endif
|
|
}
|
|
|
|
// Uses the theme to draw the border and fill for something like a wxTextCtrl
|
|
void wxRendererGTK::DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
|
|
{
|
|
wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
|
|
if (drawable == NULL)
|
|
return;
|
|
|
|
GtkWidget* entry = wxGTKPrivate::GetTextEntryWidget();
|
|
|
|
GtkStateType state = GTK_STATE_NORMAL;
|
|
if ( flags & wxCONTROL_DISABLED )
|
|
state = GTK_STATE_INSENSITIVE;
|
|
|
|
gtk_widget_set_can_focus(entry, (flags & wxCONTROL_CURRENT) != 0);
|
|
|
|
#ifdef __WXGTK3__
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(entry);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, stateTypeToFlags[state]);
|
|
gtk_render_background(sc, drawable, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_render_frame(sc, drawable, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_style_context_restore(sc);
|
|
#else
|
|
gtk_paint_shadow
|
|
(
|
|
gtk_widget_get_style(entry),
|
|
drawable,
|
|
state,
|
|
GTK_SHADOW_OUT,
|
|
NULL_RECT
|
|
entry,
|
|
"entry",
|
|
dc.LogicalToDeviceX(rect.x),
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width,
|
|
rect.height
|
|
);
|
|
#endif
|
|
}
|
|
|
|
// Draw the equivalent of a wxComboBox
|
|
void wxRendererGTK::DrawComboBox(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
|
|
{
|
|
wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
|
|
if (drawable == NULL)
|
|
return;
|
|
|
|
GtkWidget* combo = wxGTKPrivate::GetComboBoxWidget();
|
|
|
|
GtkStateType state = GTK_STATE_NORMAL;
|
|
if ( flags & wxCONTROL_DISABLED )
|
|
state = GTK_STATE_INSENSITIVE;
|
|
|
|
gtk_widget_set_can_focus(combo, (flags & wxCONTROL_CURRENT) != 0);
|
|
|
|
#ifdef __WXGTK3__
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(combo);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_set_state(sc, stateTypeToFlags[state]);
|
|
gtk_render_background(sc, drawable, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_render_frame(sc, drawable, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_style_context_restore(sc);
|
|
wxRect r = rect;
|
|
r.x += r.width - r.height;
|
|
r.width = r.height;
|
|
DrawComboBoxDropButton(win, dc, r, flags);
|
|
#else
|
|
gtk_paint_shadow
|
|
(
|
|
gtk_widget_get_style(combo),
|
|
drawable,
|
|
state,
|
|
GTK_SHADOW_OUT,
|
|
NULL_RECT
|
|
combo,
|
|
"combobox",
|
|
dc.LogicalToDeviceX(rect.x),
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width,
|
|
rect.height
|
|
);
|
|
|
|
wxRect r = rect;
|
|
int extent = rect.height / 2;
|
|
r.x += rect.width - extent - extent/2;
|
|
r.y += extent/2;
|
|
r.width = extent;
|
|
r.height = extent;
|
|
|
|
gtk_paint_arrow
|
|
(
|
|
gtk_widget_get_style(combo),
|
|
drawable,
|
|
state,
|
|
GTK_SHADOW_OUT,
|
|
NULL_RECT
|
|
combo,
|
|
"arrow",
|
|
GTK_ARROW_DOWN,
|
|
TRUE,
|
|
dc.LogicalToDeviceX(r.x),
|
|
dc.LogicalToDeviceY(r.y),
|
|
r.width,
|
|
r.height
|
|
);
|
|
|
|
r = rect;
|
|
r.x += rect.width - 2*extent;
|
|
r.width = 2;
|
|
|
|
gtk_paint_box
|
|
(
|
|
gtk_widget_get_style(combo),
|
|
drawable,
|
|
state,
|
|
GTK_SHADOW_ETCHED_OUT,
|
|
NULL_RECT
|
|
combo,
|
|
"vseparator",
|
|
dc.LogicalToDeviceX(r.x),
|
|
dc.LogicalToDeviceY(r.y+1),
|
|
r.width,
|
|
r.height-2
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void wxRendererGTK::DrawChoice(wxWindow* win, wxDC& dc,
|
|
const wxRect& rect, int flags)
|
|
{
|
|
DrawComboBox( win, dc, rect, flags );
|
|
}
|
|
|
|
|
|
// Draw a themed radio button
|
|
void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
|
|
{
|
|
wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
|
|
if (drawable == NULL)
|
|
return;
|
|
|
|
GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget();
|
|
|
|
#ifdef __WXGTK3__
|
|
int state = GTK_STATE_FLAG_NORMAL;
|
|
if (flags & wxCONTROL_CHECKED)
|
|
state = GTK_STATE_FLAG_ACTIVE;
|
|
else if (flags & wxCONTROL_UNDETERMINED)
|
|
state = GTK_STATE_FLAG_INCONSISTENT;
|
|
if (flags & wxCONTROL_DISABLED)
|
|
state |= GTK_STATE_FLAG_INSENSITIVE;
|
|
|
|
GtkStyleContext* sc = gtk_widget_get_style_context(button);
|
|
gtk_style_context_save(sc);
|
|
gtk_style_context_add_class(sc, GTK_STYLE_CLASS_RADIO);
|
|
gtk_style_context_set_state(sc, GtkStateFlags(state));
|
|
gtk_render_option(sc, drawable, rect.x, rect.y, rect.width, rect.height);
|
|
gtk_style_context_restore(sc);
|
|
#else
|
|
GtkShadowType shadow_type = GTK_SHADOW_OUT;
|
|
if ( flags & wxCONTROL_CHECKED )
|
|
shadow_type = GTK_SHADOW_IN;
|
|
else if ( flags & wxCONTROL_UNDETERMINED )
|
|
shadow_type = GTK_SHADOW_ETCHED_IN;
|
|
|
|
GtkStateType state = GTK_STATE_NORMAL;
|
|
if ( flags & wxCONTROL_DISABLED )
|
|
state = GTK_STATE_INSENSITIVE;
|
|
if ( flags & wxCONTROL_PRESSED )
|
|
state = GTK_STATE_ACTIVE;
|
|
/*
|
|
Don't know when to set this
|
|
state_type = GTK_STATE_PRELIGHT;
|
|
*/
|
|
|
|
gtk_paint_option
|
|
(
|
|
gtk_widget_get_style(button),
|
|
drawable,
|
|
state,
|
|
shadow_type,
|
|
NULL_RECT
|
|
button,
|
|
"radiobutton",
|
|
dc.LogicalToDeviceX(rect.x),
|
|
dc.LogicalToDeviceY(rect.y),
|
|
rect.width, rect.height
|
|
);
|
|
#endif
|
|
}
|