lazarus/lcl/interfaces/qt/qtthemes.pas
2008-02-09 20:32:37 +00:00

413 lines
13 KiB
ObjectPascal

unit QtThemes;
{$mode objfpc}{$H+}
interface
{$I qtdefines.inc}
uses
// rtl
Types, Classes, SysUtils,
// qt bindings
qt4,
// lcl
LCLType, LCLProc, LCLIntf, Graphics, Themes, TmSchema,
// widgetset
InterfaceBase, QtObjects
;
type
TQtDrawVariant =
(
qdvNone,
qdvPrimitive,
qdvControl,
qdvComplexControl,
qdvStandardPixmap
);
TQtDrawElement = record
case DrawVariant: TQtDrawVariant of
qdvPrimitive:
(PrimitiveElement: QStylePrimitiveElement);
qdvControl:
(ControlElement: QStyleControlElement);
qdvComplexControl:
(ComplexControl: QStyleComplexControl;
SubControls: QStyleSubControls);
qdvStandardPixmap:
(StandardPixmap: QStyleStandardPixmap);
end;
{ TQtThemeServices }
TQtThemeServices = class(TThemeServices)
private
FStyle: QStyleH;
function GetStyle: QStyleH;
protected
function InitThemes: Boolean; override;
function UseThemes: Boolean; override;
function ThemedControlsEnabled: Boolean; override;
procedure InternalDrawParentBackground(Window: HWND; Target: HDC; Bounds: PRect); override;
function GetControlState(Details: TThemedElementDetails): QStyleState;
function GetDetailSize(Details: TThemedElementDetails): Integer; override;
function GetDrawElement(Details: TThemedElementDetails): TQtDrawElement;
property Style: QStyleH read GetStyle;
public
procedure DrawElement(DC: HDC; Details: TThemedElementDetails; const R: TRect; ClipRect: PRect); override;
procedure DrawEdge(DC: HDC; Details: TThemedElementDetails; const R: TRect; Edge, Flags: Cardinal; AContentRect: PRect); override;
procedure DrawIcon(DC: HDC; Details: TThemedElementDetails; const R: TRect; himl: HIMAGELIST; Index: Integer); override;
function ContentRect(DC: HDC; Details: TThemedElementDetails; BoundingRect: TRect): TRect; override;
function HasTransparentParts(Details: TThemedElementDetails): Boolean; override;
end;
implementation
{ TQtThemeServices }
function TQtThemeServices.GetStyle: QStyleH;
begin
if FStyle = nil then
FStyle := QApplication_style();
Result := FStyle;
end;
function TQtThemeServices.InitThemes: Boolean;
begin
FStyle := nil;
Result := True;
end;
function TQtThemeServices.UseThemes: Boolean;
begin
Result := True;
end;
function TQtThemeServices.ThemedControlsEnabled: Boolean;
begin
Result := True;
end;
function TQtThemeServices.ContentRect(DC: HDC;
Details: TThemedElementDetails; BoundingRect: TRect): TRect;
begin
Result := BoundingRect;
InflateRect(Result, -1, -1);
end;
procedure TQtThemeServices.DrawEdge(DC: HDC;
Details: TThemedElementDetails; const R: TRect; Edge, Flags: Cardinal;
AContentRect: PRect);
begin
end;
procedure TQtThemeServices.DrawElement(DC: HDC;
Details: TThemedElementDetails; const R: TRect; ClipRect: PRect);
var
Context: TQtDeviceContext absolute DC;
opt: QStyleOptionH;
ARect: TRect;
AIcon: QIconH;
Element: TQtDrawElement;
Features: QStyleOptionButtonButtonFeatures;
Position: QStyleOptionHeaderSectionPosition;
begin
if (Context <> nil) then
begin
ARect := R;
Element := GetDrawElement(Details);
case Element.DrawVariant of
qdvControl:
begin
if (Element.ControlElement in [QStyleCE_PushButton, QStyleCE_RadioButton, QStyleCE_CheckBox]) then
begin
opt := QStyleOptionButton_create();
Features := QStyleOptionButtonNone;
if Details.Element = teToolBar then
Features := Features or QStyleOptionButtonFlat;
QStyleOptionButton_setFeatures(QStyleOptionButtonH(opt), Features);
end
else
if (Element.ControlElement = QStyleCE_HeaderSection) then
begin
opt := QStyleOptionHeader_create();
case Details.Part of
HP_HEADERITEM: Position := QStyleOptionHeaderMiddle;
HP_HEADERITEMLEFT: Position := QStyleOptionHeaderBeginning;
HP_HEADERITEMRIGHT: Position := QStyleOptionHeaderEnd;
end;
QStyleOptionHeader_setPosition(QStyleOptionHeaderH(opt), Position);
QStyleOptionHeader_setOrientation(QStyleOptionHeaderH(opt), QtHorizontal);
end
else
opt := QStyleOptionComplex_create(LongInt(QStyleOptionVersion), LongInt(QStyleOptionSO_Default));
QStyleOption_setState(opt, GetControlState(Details));
QStyleOption_setRect(opt, @ARect);
QStyle_drawControl(Style, Element.ControlElement, opt, Context.Widget);
QStyleOption_Destroy(opt);
end;
qdvComplexControl:
begin
Context.save;
case Element.ComplexControl of
QStyleCC_ToolButton: opt := QStyleOptionToolButton_create();
QStyleCC_TitleBar, QStyleCC_MdiControls:
begin
opt := QStyleOptionTitleBar_create();
QStyleOptionTitleBar_setTitleBarFlags(QStyleOptionTitleBarH(opt), QtWindow or QtWindowSystemMenuHint);
// workaround: qt has own minds about position of requested part -
// but we need a way to draw it at our position
Context.translate(ARect.Left, ARect.Top);
OffsetRect(ARect, -ARect.Left, -ARect.Top);
end;
else
opt := QStyleOptionComplex_create(LongInt(QStyleOptionVersion), LongInt(QStyleOptionSO_Default));
end;
QStyleOptionComplex_setSubControls(QStyleOptionComplexH(opt), Element.SubControls);
QStyleOption_setState(opt, GetControlState(Details));
QStyleOption_setRect(opt, @ARect);
QStyle_drawComplexControl(Style, Element.ComplexControl, QStyleOptionComplexH(opt), Context.Widget);
QStyleOption_Destroy(opt);
Context.restore;
end;
qdvPrimitive:
begin
opt := QStyleOption_create(Integer(QStyleOptionVersion), Integer(QStyleOptionSO_Default));
QStyleOption_setState(opt, GetControlState(Details));
QStyleOption_setRect(opt, @ARect);
QStyle_drawPrimitive(Style, Element.PrimitiveElement, opt, Context.Widget);
QStyleOption_Destroy(opt);
end;
qdvStandardPixmap:
begin
opt := QStyleOption_create(Integer(QStyleOptionVersion), Integer(QStyleOptionSO_Default));
AIcon := QIcon_create();
QStyle_standardIcon(Style, AIcon, Element.StandardPixmap, opt);
QIcon_paint(AIcon, Context.Widget, ARect.Left, ARect.Top,
ARect.Right - ARect.Left, ARect.Bottom - ARect.Top);
QIcon_destroy(AIcon);
QStyleOption_Destroy(opt);
end;
end;
end;
end;
procedure TQtThemeServices.DrawIcon(DC: HDC;
Details: TThemedElementDetails; const R: TRect; himl: HIMAGELIST;
Index: Integer);
begin
end;
function TQtThemeServices.HasTransparentParts(Details: TThemedElementDetails): Boolean;
begin
Result := True;
end;
procedure TQtThemeServices.InternalDrawParentBackground(Window: HWND;
Target: HDC; Bounds: PRect);
begin
// ?
end;
function TQtThemeServices.GetControlState(Details: TThemedElementDetails): QStyleState;
begin
{
QStyleState_None
QStyleState_Enabled
QStyleState_Raised
QStyleState_Sunken
QStyleState_Off
QStyleState_NoChange
QStyleState_On
QStyleState_DownArrow
QStyleState_Horizontal
QStyleState_HasFocus
QStyleState_Top
QStyleState_Bottom
QStyleState_FocusAtBorder
QStyleState_AutoRaise
QStyleState_MouseOver
QStyleState_UpArrow
QStyleState_Selected
QStyleState_Active
QStyleState_Open
QStyleState_Children
QStyleState_Item
QStyleState_Sibling
QStyleState_Editing
QStyleState_KeyboardFocusChange
QStyleState_ReadOnly
}
Result := QStyleState_None;
if not IsDisabled(Details) then
Result := Result or QStyleState_Enabled;
if IsHot(Details) then
Result := Result or QStyleState_MouseOver;
if IsPushed(Details) then
Result := Result or QStyleState_Sunken;
if IsChecked(Details) then
Result := Result or QStyleState_On
else
if IsMixed(Details) then
Result := Result or QStyleState_NoChange;
// specific states
// define orientations
if ((Details.Element = teRebar) and (Details.Part = RP_GRIPPER)) or
((Details.Element = teToolBar) and (Details.Part = TP_SEPARATOR)) then
Result := Result or QStyleState_Horizontal;
end;
function TQtThemeServices.GetDetailSize(Details: TThemedElementDetails): Integer;
begin
case Details.Element of
teRebar :
if Details.Part in [RP_GRIPPER, RP_GRIPPERVERT] then
Result := -1;
else
Result := inherited;
end;
end;
function TQtThemeServices.GetDrawElement(Details: TThemedElementDetails): TQtDrawElement;
const
ButtonMap: array[BP_PUSHBUTTON..BP_USERBUTTON] of QStyleControlElement =
(
{BP_PUSHBUTTON } QStyleCE_PushButton,
{BP_RADIOBUTTON} QStyleCE_RadioButton,
{BP_CHECKBOX } QStyleCE_CheckBox,
{BP_GROUPBOX } QStyleCE_PushButton,
{BP_USERBUTTON } QStyleCE_PushButton
);
begin
Result.DrawVariant := qdvNone;
case Details.Element of
teButton:
begin
if Details.Part <> BP_GROUPBOX then
begin
Result.DrawVariant := qdvControl;
Result.ControlElement := ButtonMap[Details.Part]
end
else
begin
Result.DrawVariant := qdvComplexControl;
Result.ComplexControl := QStyleCC_GroupBox;
Result.SubControls := QStyleSC_GroupBoxFrame;
end;
end;
teHeader:
begin
case Details.Part of
HP_HEADERITEM,
HP_HEADERITEMLEFT,
HP_HEADERITEMRIGHT:
begin
Result.DrawVariant := qdvControl;
Result.ControlElement := QStyleCE_HeaderSection;
end;
HP_HEADERSORTARROW:
begin
Result.DrawVariant := qdvPrimitive;
Result.PrimitiveElement := QStylePE_IndicatorHeaderArrow;
end;
end;
end;
teToolBar:
begin
case Details.Part of
TP_BUTTON,
TP_DROPDOWNBUTTON,
TP_SPLITBUTTON: // there is another positibility to draw TP_SPLITBUTTON by CC_ToolButton
begin
Result.DrawVariant := qdvPrimitive;
Result.PrimitiveElement := QStylePE_PanelButtonTool;
end;
TP_SPLITBUTTONDROPDOWN:
begin
Result.DrawVariant := qdvPrimitive;
Result.PrimitiveElement := QStylePE_IndicatorButtonDropDown;
end;
TP_SEPARATOR,
TP_SEPARATORVERT:
begin
Result.DrawVariant := qdvPrimitive;
Result.PrimitiveElement := QStylePE_IndicatorToolBarSeparator;
end;
end;
end;
teRebar:
begin
case Details.Part of
RP_GRIPPER, RP_GRIPPERVERT: // used in splitter
begin
Result.DrawVariant := qdvControl;
Result.ControlElement := QStyleCE_Splitter;
end;
end;
end;
teWindow:
begin
case Details.Part of
WP_SYSBUTTON: Result.SubControls := QStyleSC_TitleBarSysMenu;
WP_MINBUTTON: Result.SubControls := QStyleSC_TitleBarMinButton;
WP_MAXBUTTON: Result.SubControls := QStyleSC_TitleBarMaxButton;
WP_CLOSEBUTTON: Result.SubControls := QStyleSC_TitleBarCloseButton;
WP_SMALLCLOSEBUTTON: Result.SubControls := QStyleSC_TitleBarCloseButton;
WP_RESTOREBUTTON: Result.SubControls := QStyleSC_TitleBarNormalButton;
WP_HELPBUTTON: Result.SubControls := QStyleSC_TitleBarContextHelpButton;
WP_MDIHELPBUTTON: Result.SubControls := QStyleSC_TitleBarContextHelpButton;
WP_MDIMINBUTTON: Result.SubControls := QStyleSC_MdiMinButton;
WP_MDICLOSEBUTTON: Result.SubControls := QStyleSC_MdiCloseButton;
WP_MDIRESTOREBUTTON: Result.SubControls := QStyleSC_MdiNormalButton;
else
Result.SubControls := QStyleSC_None;
end;
if Result.SubControls >= QStyleSC_MdiMinButton then
Result.ComplexControl := QStyleCC_MdiControls
else
Result.ComplexControl := QStyleCC_TitleBar;
Result.DrawVariant := qdvComplexControl;
{
// maybe through icon
Result.DrawVariant := qdvStandardPixmap;
case Details.Part of
WP_MINBUTTON: Result.StandardPixmap := QStyleSP_TitleBarMinButton;
WP_MDIMINBUTTON: Result.StandardPixmap := QStyleSP_TitleBarMinButton;
WP_MAXBUTTON: Result.StandardPixmap := QStyleSP_TitleBarMaxButton;
WP_CLOSEBUTTON: Result.StandardPixmap := QStyleSP_TitleBarCloseButton;
WP_SMALLCLOSEBUTTON: Result.StandardPixmap := QStyleSP_TitleBarCloseButton;
WP_MDICLOSEBUTTON: Result.StandardPixmap := QStyleSP_TitleBarCloseButton;
WP_RESTOREBUTTON: Result.StandardPixmap := QStyleSP_TitleBarNormalButton;
WP_MDIRESTOREBUTTON: Result.StandardPixmap := QStyleSP_TitleBarNormalButton;
WP_HELPBUTTON: Result.StandardPixmap := QStyleSP_TitleBarContextHelpButton;
WP_MDIHELPBUTTON: Result.StandardPixmap := QStyleSP_TitleBarContextHelpButton;
else
Result.StandardPixmap := QStyleSP_TitleBarCloseButton;
end;
}
end;
end;
end;
end.