{ ------------------------------------------------------------- }
{ Purpose : Next Standard 6                                     }
{ By      : Bojan Nikolic                                       }
{ For     : BergSoft                                            }
{ ------------------------------------------------------------- }
{ Copyright (C) BergSoft.net 2012. All Rights Reserved.         }
{ ------------------------------------------------------------- }
{$I NxSuite6.inc}

unit NxPopupCtrls6;

interface

uses
  { Standard }
  Classes, Types, Windows, Messages, Graphics,
  {$IFDEF UI_TYPES}UITypes,{$ENDIF}
  { System }
  ExtCtrls,
  { Controls }
  Controls, StdCtrls, Forms, Dialogs,
  { Next Standard 6 }
  NxIntf6, NxClasses6, NxConsts6, NxTypes6, NxControls6, NxStyles6;

const
  { Day Size }
  szDayWidth = 16;
  szDayHeight = 16;

const
  szItemHeight = 13;
  coDropDown = 8;

type
  INxPopupControl = interface
    ['{B7D52F81-F7E6-47C5-8D25-4FB0746B6A50}']
    function GetCanvas: TCanvas;
    function GetFont: TFont;
    procedure KeyDown(var Key: Word; Shift: TShiftState);
    procedure Popup(const X, Y: Integer; Anchor: TNxPopupAnchor = paLeft); overload;
    procedure Popup(const Location: TPoint; Anchor: TNxPopupAnchor = paLeft); overload;
    procedure SetDropDown(const Value: INxDropDown);
    procedure UpdatePopup;
    property Canvas: TCanvas read GetCanvas;
    property Font: TFont read GetFont;
  end;

  TNxGraphicButton = class(TGraphicControl)
  private
    FState: TNxButtonState;
    FStyle: TNxAppearanceStyle;
    procedure SetState(const Value: TNxButtonState);
    procedure SetStyle(const Value: TNxAppearanceStyle);
  protected
    { Delphi Messages }
	  procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
    { Virtual Methods }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure Paint; override;

    procedure WndProc(var Message: TMessage); override;
    { Properties }
    property State: TNxButtonState read FState write SetState;
  public
    constructor Create(AOwner: TComponent); override;
  published
    { Properties }
    property Style: TNxAppearanceStyle read FStyle write SetStyle default stNative;
    { Events }
  end;

  { TNxPopupControl6 }

  TNxPopupState = set of (psOpening, psClosing);

  TNxPopupControl6 = class(TNxScrollControl6, INxPopupControl)
  private
    FDropDown: INxDropDown;
    FMouseDown: Boolean;
    FPopupState: TNxPopupState;
    FShowShadow: Boolean;
    function GetControlRect: TRect;
    function GetDropDown: INxDropDown;
    procedure SetDropDown(const Value: INxDropDown);
    procedure SetShowShadow(const Value: Boolean);
  protected
    function GetCanvas: TCanvas;
    function GetFont: TFont;
    procedure AfterPopup; virtual;
    procedure BeforePopup; virtual;
    { Delphi Messages }
	  procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    { Common Virtual Methods }
    procedure CreateParams(var Params: TCreateParams); override;
  	procedure CreateWnd; override;
    procedure UpdatePopup; virtual;
    { Mouse & Keyboard }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Windows Messages }
    procedure WMNCMouseLeave(var Message: TMessage); message WM_NCMOUSELEAVE;
    procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
    { Properties }
    property PopupState: TNxPopupState read FPopupState;
  public
    constructor Create(AOwner: TComponent); override;
    { Methods }
    procedure Close(Value: WideString); virtual;
    procedure Popup(const X, Y: Integer; Anchor: TNxPopupAnchor = paLeft); overload; virtual;
    procedure Popup(const Location: TPoint; Anchor: TNxPopupAnchor = paLeft); overload; virtual;
    { Properties }
    property ControlRect: TRect read GetControlRect;
    property DropDown: INxDropDown read GetDropDown write SetDropDown;
    property Font;
    property Height;
    property ShowShadow: Boolean read FShowShadow write SetShowShadow;
    property Visible;
    property Width;
  end;

  { TNxEditPopupControl6 }

  TNxEditPopupControl6 = class(TNxPopupControl6)
  private
    FEdit: TCustomEdit;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Close(Value: WideString); override;
    { Properties }
    property Edit: TCustomEdit read FEdit;
  end;

  { TNxListPopupControl6 }

  INxListPopup = interface
    ['{4EDB0201-082C-4C68-BCEA-6339AE4B80DA}']
    procedure ScrollDown;
    procedure ScrollUp;
  end;

  TNxListPopupControl6 = class(TNxEditPopupControl6, INxListPopup)
  private
    function GetPageItemCount: Integer;
  protected
    { Virtual Methods }
    function GetCount: Integer; virtual; abstract;
    function GetDropDownCount: Integer; virtual; abstract;
    function GetItemIndex: Integer; virtual; abstract;
    procedure SetItemIndex(const Value: Integer); virtual; abstract;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure Paint; override;
    function PaintCell(const Index: Integer; CellRect: TRect;
      State: TOwnerDrawState): Boolean; virtual;
    procedure ScrollDown;
    procedure ScrollToItem(const Index: Integer);
    procedure ScrollUp;
    procedure UpdateVertScrollBar; virtual;
  public
    property Count: Integer read GetCount;
    property DropDownCount: Integer read GetDropDownCount;
    property ItemIndex: Integer read GetItemIndex write SetItemIndex;
    property PageItemCount: Integer read GetPageItemCount;
  end;

  { TNxStringPopupControl6 }

  TNxStringsPopupControl6 = class(TNxListPopupControl6)
  private
    FHotIndex: Integer;
    function GetItemHeight: Integer;
    function GetItems: TStrings;
    function GetStringsControl: INxStringsControl;
    procedure SetHotIndex(const Value: Integer);
  protected
    procedure AfterPopup; override;
    procedure BeforePopup; override;
    function GetCount: Integer; override;
    function GetDropDownCount: Integer; override;
    function GetItemIndex: Integer; override;
    procedure SetItemIndex(const Value: Integer); override;
    procedure UpdatePopup; override;
    { Mouse & Keyboard Methods }
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Paint Methods }
    procedure Paint; override;
//    function PaintCell(const Index: Integer; CellRect: TRect; Selected: Boolean): Boolean; override;
    procedure RefreshItem(const Index: Integer);
    procedure ScrollContentBy(DeltaX, DeltaY: Integer); override;
    procedure ScrollRect(DeltaX, DeltaY: Integer; Rect, ClipRect: TRect); override;
    procedure UpdateVertScrollBar; override;
    { Windows Messages }

    { Properties }
    property HotIndex: Integer read FHotIndex write SetHotIndex;
    property StringsControl: INxStringsControl read GetStringsControl;
  public
    constructor Create(AOwner: TComponent); override;
    { Properties }
    property ItemHeight: Integer read GetItemHeight;
    property Items: TStrings read GetItems;
  end;

  { TNxCheckPopupControl6 }

  INxCheckPopupOwner = interface
    ['{7ECA25DE-78FF-4B7D-8629-69D452968597}']
    procedure CheckBoxClick(const Index: Integer);
  end;

  TNxCheckPopupControl6 = class(TNxStringsPopupControl6)
  private
    function GetCheckBoxSize: TSize;
  protected
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure RefreshCheckBox(const Index: Integer);
  public
    { Methods }
    function GetCheckBoxAtPos(X, Y: Integer): Integer;
    function GetCheckBoxRect(const Index: Integer): TRect;
    { Properties }
    property CheckBoxSize: TSize read GetCheckBoxSize;
  end;

  { TNxDatePickerView }

  TNxDatePopupControl6 = class;

  TNxDateSelectionMode = (dmDays, dmMonths, dmYears);

  TNxCustomDrawDate = procedure (Sender: TObject; Date: TDateTime; DayRect: TRect) of object;
  TNxGetDateColor = procedure (Sender: TObject; Date: TDateTime; var DayColor: TColor) of object;

  TNxDatePickerView = class(TNxObjectView)
  private
    FColor: TColor;
    FDayHeight: Integer;
    FDayWidth: Integer;
    FDown: Boolean;
    FHotMonth: Integer;
    FHotDay: TDateTime;
    FMonth: Word;
    FOnGetDateColor: TNxGetDateColor;
    FPressedMonth: Integer;
    FSelected: TDateTime;
    FSelectionDateRange: TNxDateRange;
    FSelectionMode: TNxDateSelectionMode;
    FStartDay: TNxStartDayOfWeek;
    FValue: string;
    FYear: Word;
    FOnCustomDrawDate: TNxCustomDrawDate;
    { Property Accessors }
    function GetContentRect: TRect;
    function GetDatePopupControl: TNxDatePopupControl6;
    function GetDayHeight: Integer;
    function GetDaysRect: TRect;
    function GetDayWidth: Integer;
    function GetHeaderTitleRect: TRect;
    function GetMonthSize: TSize;
    function GetMonthsRect: TRect;
    function GetWeekDaysRect: TRect;
    function GetYearSize: TSize;
    procedure SetColor(const Value: TColor);
    procedure SetDayHeight(const Value: Integer);
    procedure SetDayWidth(const Value: Integer);
    procedure SetDown(const Value: Boolean);
    procedure SetHotDay(const Value: TDateTime);
    procedure SetHotMonth(const Value: Integer);
    procedure SetMonth(const Value: Word);
    procedure SetSelected(const Value: TDateTime);
    procedure SetSelectionMode(const Value: TNxDateSelectionMode);
    procedure SetStartDay(const Value: TNxStartDayOfWeek);
    procedure SetYear(const Value: Word);
    procedure SetPressedMonth(const Value: Integer);
  protected
    function GetActualStartDay: TNxStartDayOfWeek;
    function GetDayInWeekText(DayInWeek: Integer): WideString;
    function GetDayOfWeek(Day: TDateTime): Integer;
    function GetHeaderRect: TRect;
    function GetLeftArrowRect: TRect;
    function GetMonthName(Month: Integer): WideString;
    function GetRightArrowRect: TRect;
    { Event Handlers }
    procedure DoCustomDrawDate(Date: TDateTime; DayRect: TRect); dynamic;
    procedure DoGetDateColor(Date: TDateTime; var DayColor: TColor); dynamic;
    procedure PaintCell(const CellRect: TRect; const State: TNxButtonState;
      const Text: string); virtual;
    procedure PaintDay(DayRect: TRect; Day: TDateTime); virtual;
    procedure PaintDaysView(const AContentRect: TRect);
    procedure PaintHeader; virtual;
    procedure PaintMonthsView(const AContentRect: TRect);
    procedure PaintWeekDays(const X, Y: Integer); virtual;
    procedure PaintYearsView(const AContentRect: TRect);
    { Properties }
    property DatePopupControl: TNxDatePopupControl6 read GetDatePopupControl;
  public
    constructor Create;
    { Painting Methods }
    function GetDayAtPos(const X, Y: Integer): TDateTime;
    function GetDayRect(const Date: TDateTime): TRect;
    function GetMonthAtPos(const X, Y: Integer): Integer;
    function GetMonthRect(const AMonth: Integer): TRect;
    function GetYearAtPos(const X, Y: Integer): Integer;
    function IsShown(Date: TDateTime): Boolean;
    class function IsValidDateSelection(const Date: TDateTime; const SelectionDateRange: TNxDateRange): Boolean;
    procedure Changed;
    procedure FillDay(Date: TDateTime; DayRect: TRect; DayColor: TColor);
    procedure Paint; override;
    procedure PaintDays(const X, Y: Integer);
    procedure RefreshDay(const Date: TDateTime);
    procedure RefreshMonth(const AMonth: Integer);
    function TrySelect(const Date: TDateTime): Boolean;
    { INxView }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseLeave; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Properties }
    property Color: TColor read FColor write SetColor;
    property ContentRect: TRect read GetContentRect;
    property DayHeight: Integer read GetDayHeight write SetDayHeight;
    property DaysRect: TRect read GetDaysRect;
    property DayWidth: Integer read GetDayWidth write SetDayWidth;
    property Down: Boolean read FDown write SetDown;
    property HotDay: TDateTime read FHotDay write SetHotDay;
    property HotMonth: Integer read FHotMonth write SetHotMonth;
    property Month: Word read FMonth write SetMonth;
    property HeaderRect: TRect read GetHeaderRect;
    property HeaderTitleRect: TRect read GetHeaderTitleRect;
    property MonthsRect: TRect read GetMonthsRect;
    property MonthSize: TSize read GetMonthSize;
    property PressedMonth: Integer read FPressedMonth write SetPressedMonth;
    property Selected: TDateTime read FSelected write SetSelected;
    property SelectionDateRange: TNxDateRange read FSelectionDateRange write FSelectionDateRange;
    property SelectionMode: TNxDateSelectionMode read FSelectionMode write SetSelectionMode;
    property StartDay: TNxStartDayOfWeek read FStartDay write SetStartDay;
    property Value: string read FValue write FValue;
    property WeekDaysRect: TRect read GetWeekDaysRect;
    property Year: Word read FYear write SetYear;
    property YearSize: TSize read GetYearSize;
    { Events }
    property OnCustomDrawDate: TNxCustomDrawDate read FOnCustomDrawDate write FOnCustomDrawDate;
    property OnGetDateColor: TNxGetDateColor read FOnGetDateColor write FOnGetDateColor;
  end;

  { TNxDatePopupControl6 }

  INxDatePickerOwner = interface
    ['{C1358F28-0410-40DE-9848-28360D078580}']
    procedure DoCustomDrawDate(Sender: TObject; Date: TDateTime; DayRect: TRect);
    procedure DoGetDateColor(Sender: TObject; Date: TDateTime; var DayColor: TColor);
  end;

  INxDateControl = interface
    ['{6EBFA4F7-B1AB-4B9E-A000-99DE8F3C1D9C}']
    procedure SetSelectionDateRange(const Value: TNxDateRange);
    procedure SetStartDayOfWeek(const Value: TNxStartDayOfWeek);
    property SelectionDateRange: TNxDateRange write SetSelectionDateRange;
    property StartDayOfWeek: TNxStartDayOfWeek write SetStartDayOfWeek;
  end;

  TNxDatePopupControl6 = class(TNxEditPopupControl6, INxPopupControl,
    INxDateControl)
  private
    FNoneButton: TNxGraphicButton;
    FSelectionDateRange: TNxDateRange;
    FStartDayOfWeek: TNxStartDayOfWeek;
    FTodayButton: TNxGraphicButton;
    FView: TNxDatePickerView;
    function GetPickerOwner: INxDatePickerOwner;
    procedure SetSelectionDateRange(const Value: TNxDateRange);
    procedure SetStartDayOfWeek(const Value: TNxStartDayOfWeek);
  protected
    procedure DoButtonClick(Sender: TObject);
    procedure DoGetDateColor(Sender: TObject; Date: TDateTime; var DayColor: TColor);
    procedure DoCustomDrawDate(Sender: TObject; Date: TDateTime; DayRect: TRect);
    { Protected Methods }
    procedure Paint; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Methods }
    procedure NextMonth;
    procedure PrevMonth;
    { Properties }
    property PickerOwner: INxDatePickerOwner read GetPickerOwner;
    property StartDayOfWeek: TNxStartDayOfWeek read FStartDayOfWeek write SetStartDayOfWeek;
  end;

  { TNxTimePopupControl6 }

  INxTimeControl = interface
    ['{6A258CB7-694D-410A-8F6F-3429E1DA9349}']
    function GetHoursText: string;
    function GetMinutesText: string;
    procedure SetHoursText(const Value: string);
    procedure SetMinutesText(const Value: string);
    procedure SetOptions(const Value: TNxTimeShowOptions);
    property HoursText: string read GetHoursText write SetHoursText;
    property MinutesText: string read GetMinutesText write SetMinutesText;
  end;

  TNxTimePopupControl6 = class(TNxEditPopupControl6, INxTimeControl)
  private
    { Private Fields }
    FHotCell: TPoint;
    FHoursText: WideString;
    FMinuteText: WideString;
    FNowButton: TNxGraphicButton;
    FOptions: TNxTimeShowOptions;
    FPressedCell: TPoint;
    function GetCellCount: Integer;
    function GetCellsRect: TRect;
    function GetColCount: Integer;
    function GetHour: Word;
    function GetHoursText: string;
    function GetMinute: Word;
    function GetMinutesText: string;
    procedure SetHotCell(const Value: TPoint);
    procedure SetHour(const Value: Word);
    procedure SetHoursText(const Value: string);
    procedure SetMinute(const Value: Word);
    procedure SetMinutesText(const Value: string);
    procedure SetOptions(const Value: TNxTimeShowOptions);
    procedure SetPressedCell(const Value: TPoint);
  protected
    function GetCellSize: TSize;
    function GetContentRect: TRect;
    function GetHeaderRect: TRect;
    function GetHoursRect: TRect;
    function GetMinutesRect: TRect;

    function GetAsString: string; virtual;
    { Event Handlers }
    procedure DoNowButtonClick(Sender: TObject);
    { Input }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Paint }
    procedure Paint; override;
    procedure PaintCell(Value: Integer; CellRect: TRect; CellState: TNxButtonState); virtual;
    procedure PaintContent; virtual;
    procedure PaintHeader(HeaderRect: TRect); virtual;
    procedure UpdateSize; virtual;
    { Properties }
    property CellCount: Integer read GetCellCount;
    property CellsRect: TRect read GetCellsRect;
    property ColCount: Integer read GetColCount;
    property HotCell: TPoint read FHotCell write SetHotCell;
    property PressedCell: TPoint read FPressedCell write SetPressedCell;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Methods }
    function MaxHour: Word;
    function MinHour: Word;
    function GetBestSize: TSize;
    function GetCellAtPos(X, Y: Integer): TPoint;
    function GetCellRect(Col, Row: Integer): TRect;
    function GetCellMinute(Row: Integer): Word;
    procedure SetSelectedCell(Location: TPoint);
    procedure InvalidateCell(Col, Row: Integer);
    { Properties }
    property ContentRect: TRect read GetContentRect;
    property CellSize: TSize read GetCellSize;
    property HeadersRect: TRect read GetHeaderRect;
    property Hour: Word read GetHour write SetHour;
    property Minute: Word read GetMinute write SetMinute;
    property Options: TNxTimeShowOptions read FOptions write SetOptions;
  end;

  { TNxColorPopupControl6 }

  TNxColorLocation = (cloNone, cloAutomatic, cloBasePalette, cloShades, cloStandard);

  TNxColorInfo = record
    Location: TNxColorLocation;
    X, Y: Integer;
    HitRect: TRect;
    Color: TColor;
  end;

  TNxColorGroup = array[0..4] of TColor;

  TNxSetColorValueEvent = procedure (Sender: TObject; Value: TColor) of object;

  TNxColorPopupControl6 = class(TNxEditPopupControl6, INxPopupControl)
  private
    FColors: array[0..9] of TColor;
//    FGroups: array[0..9] of TNxColorGroup;
    FHotColor: TNxColorInfo;
    FStandardColors: array[0..9] of TColor;
    FOnSetValue: TNxSetColorValueEvent;
    { Property Accessors }
    function GetAutomaticColor: TColor;
    function GetSelected: TColor;
    function GetText: string;
    procedure SetHotColor(const Value: TNxColorInfo);
  protected
    function ProcColors(Location: TPoint; Operation: TNxProcOperation): TNxColorInfo;
  protected
    procedure DrawColor(Color: TColor; ColorRect: TRect; Selected: Boolean);
    procedure DrawSelection(SelectionRect: TRect);
    procedure Paint; override;
    procedure InitColorPalette;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Delphi Messages }
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Methods }
    { Properties }
    property AutomaticColor: TColor read GetAutomaticColor;
    property HotColor: TNxColorInfo read FHotColor write SetHotColor;
    property Selected: TColor read GetSelected;
    property Text: string read GetText;
    { Events }
    property OnSetValue: TNxSetColorValueEvent read FOnSetValue write FOnSetValue;
  end;

  { TNxIconPopupControl6 }

  INxIconPicker = interface
    ['{0DD5D866-FF69-4F00-A79F-8992EA047668}']
    function GetColCount: Integer;
    function GetImages: TImageList;
    function GetItemIndex: Integer;
    procedure SetItemIndex(const Value: Integer);
    property ColCount: Integer read GetColCount;
    property Images: TImageList read GetImages;
    property ItemIndex: Integer read GetItemIndex write SetItemIndex;
  end;

  TNxIconPopupControl6 = class(TNxEditPopupControl6)
  private
    FHotIcon: Integer;
    FPressedIcon: Integer;
    function GetPicker: INxIconPicker;
    function GetIconSize: TSize;
    procedure SetHotIcon(const Value: Integer);
    procedure SetPressedIcon(const Value: Integer);
    function GetCount: Integer;
  protected
    procedure BeforePopup; override;
    procedure InvalidateIcon(const Index: Integer);
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Methods }
    procedure PaintIcon(const Index: Integer; IconRect: TRect; State: TNxButtonState);
    procedure UpdatePopup; override;
    { Delphi Messages }
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    { Properties }
    property IconSize: TSize read GetIconSize;
  public
    procedure Paint; override;
    function GetIconAtPos(X, Y: Integer): Integer;
    function GetIconRect(const Index: Integer): TRect;
    property Count: Integer read GetCount;
    property Picker: INxIconPicker read GetPicker;
    property HotIcon: Integer read FHotIcon write SetHotIcon;
    property PressedIcon: Integer read FPressedIcon write SetPressedIcon;
  end;

  { TNxFilterPopupControl6 }

  TNxFilterPopupControl6 = class(TNxPopupControl6)
  private
    FButton: TNxGraphicButton;
    FFilter: WideString;
    FFilterEdit: TEdit;
    FOnChange: TNotifyEvent;
    { Property Accessors }
    procedure SetFilter(const Value: WideString);
  protected
    procedure CreateWnd; override;
    procedure DoChange(Sender: TObject); dynamic;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Popup(const X, Y: Integer; Anchor: TNxPopupAnchor = paLeft); overload; override;
    { Properties }
    property Filter: WideString read FFilter write SetFilter;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  { TNxPreviewPopupControl }

  TNxPreviewPopupControl = class(TNxPopupControl6)
  private
    FOnHide: TNotifyEvent;
  protected
    procedure DoHide; dynamic;
    { Vcl Messages }
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure CMRelease(var Msg: TMessage); message CM_RELEASE;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    property Canvas;
    property OnHide: TNotifyEvent read FOnHide write FOnHide;
  end;

  { TNxDictionaryPopupControl }

  TNxGridPickerSetValueEvent = procedure (Sender: TObject; SelectedIndex: Integer; var Value: WideString) of object;

  TNxGridPickerColumn = class(TCollectionItem)
  private
    FCaption: WideString;
    FColor: TColor;
    FWidth: Integer;
  public
    constructor Create(Collection: TCollection); override;
  published
    property Caption: WideString read FCaption write FCaption;
    property Color: TColor read FColor write FColor default clWindow;
    property Width: Integer read FWidth write FWidth default 60;
  end;

  TNxGridPickerColumns = class(TCollection)
    function GetItem(Index: Integer): TNxGridPickerColumn;
    procedure SetItem(Index: Integer; const Value: TNxGridPickerColumn);
  public
    constructor Create(AOwner: TComponent);
    function Add: TNxGridPickerColumn;
    property Items[Index: Integer]: TNxGridPickerColumn read GetItem write SetItem; default;
  end;

  TNxListRow6 = class
  private
    FCells: TStrings;
    function GetCells(const Index: Integer): WideString;
    function GetCount: Integer;
  public
    constructor Create;
    destructor Destroy; override;
  public
    procedure AddCell(const Value: WideString);
    property Cells[const Index: Integer]: WideString read GetCells;
    property Count: Integer read GetCount;
  end;

  INxGridPicker = interface
    ['{64533B10-DFF9-4CC1-A448-0D0005D0F84A}']
    function GetColCount: Integer;
    function GetColumn(const Index: Integer): TNxGridPickerColumn;
    function GetCount: Integer;
    function GetDropDownCount: Integer;
    function GetHeaderHeight: Integer;
    function GetListWidth: Integer;
    function GetRow(const Index: Integer): TNxListRow6;
    function GetRowHeight: Integer;
    function GetSelectedIndex: Integer;
    procedure DoSetValue(SelectedIndex: Integer; var Value: WideString);
    procedure SetSelectedIndex(const Value: Integer);
    property Column[const Index: Integer]: TNxGridPickerColumn read GetColumn;
    property ColCount: Integer read GetColCount;
    property DropDownCount: Integer read GetDropDownCount;
    property HeaderHeight: Integer read GetHeaderHeight;
    property ListWidth: Integer read GetListWidth;
    property RowCount: Integer read GetCount;
    property RowHeight: Integer read GetRowHeight;
    property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex;
  end;

  TNxGridPopupControl = class(TNxPopupControl6)
  private
    FHotIndex: Integer;
    FPicker: INxGridPicker;
    function GetCells(const ACol, ARow: Integer): WideString;
    function GetDataRect: TRect;
    function GetHeaderRect: TRect;
    procedure SetHotIndex(const Value: Integer);
    function GetSelectedIndex: Integer;
    procedure SetSelectedIndex(const Value: Integer);
  protected
    procedure AfterPopup; override;
    procedure BeforePopup; override;
    function GetPageRowCount: Integer;
    { Keyboard & Mouse }
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Paint }
    procedure Paint; override;
    procedure PaintCell(Value: WideString; CellRect: TRect); virtual;
    procedure PaintHeaders;
    { Scroll }
    procedure ScrollContentBy(DeltaX, DeltaY: Integer); override;
    procedure ScrollRect(DeltaX, DeltaY: Integer; Rect, ClipRect: TRect); override;
    procedure UpdateVertScrollBar;
  public
    constructor Create(AOwner: TComponent); override;
    function GetIndexAtPos(X, Y: Integer): Integer;
    property Cells[const ACol, ARow: Integer]: WideString read GetCells;
    property DataRect: TRect read GetDataRect;
    property HeaderRect: TRect read GetHeaderRect;
    property HotIndex: Integer read FHotIndex write SetHotIndex;
    property PageRowCount: Integer read GetPageRowCount;
    property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex;
  end;

implementation

uses
  { Misc. }
  SysUtils, MultiMon, DateUtils, StrUtils, Math,
  { Next Standard 6 }
  NxGraphics6,
{$IFDEF THEMES}
  UxTheme
{$ELSE}
  NxTheme6
{$ENDIF}
;

procedure Unset(var Color: TNxColorInfo); overload;
begin
  Color.Location := cloNone;
  Color.Color := clNone;
  Unset(Color.HitRect);
end;

{ TNxGraphicButton }

procedure TNxGraphicButton.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  State := State + [bsHover];
end;

procedure TNxGraphicButton.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  State := State - [bsHover];
end;

constructor TNxGraphicButton.Create(AOwner: TComponent);
begin
  inherited;
  FStyle := stNative;
  ControlStyle := [csCaptureMouse, csDoubleClicks];
end;

procedure TNxGraphicButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited;
  State := State + [bsPressed];
end;

procedure TNxGraphicButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;
  if bsPressed in State then
  begin
    State := State - [bsPressed];
    Click;
  end;
end;

procedure TNxGraphicButton.Paint;
var
  Theme: HTHEME;
  State: Byte;
  FrameColor, FaceColor: TColor;
  ButtonRect: TRect;
begin
  inherited;

  case FStyle of
    stNative:
    begin
      if IsThemeActive then
      begin
        Theme := OpenThemeData(Parent.Handle, teButton);
        try
          State := tiRadioNormal;
          if bsHover in FState then State := tiRadioHover;
          if bsPressed in FState then State := tiRadioDown;
          DrawThemeBackground(Theme, Canvas.Handle, tcButton, State, ClientRect, nil);
        finally
          CloseThemeData(Theme);
        end;
      end else
      begin
        ButtonRect := ClientRect;

        { Classic button }
        with Canvas do
          if (bsHover in FState) and (bsPressed in FState) then
          begin
            Brush.Color := clBtnFace;
            FillRect(ButtonRect);
            Brush.Color := clBtnShadow;
            FrameRect(ButtonRect);
          end else
          begin
            { Border }
            Brush.Color := clBtnFace;
            FillRect(ButtonRect);
            Frame3D(Canvas, ButtonRect, clBtnHighlight, cl3DDkShadow, 1);

            { Shadow }
            Pen.Color := clBtnShadow;
            InflateRect(ButtonRect, -1, -1);
            Polyline([
              Point(ButtonRect.Right, ButtonRect.Top - 1),
              Point(ButtonRect.Right, ButtonRect.Bottom),
              Point(ButtonRect.Left - 2, ButtonRect.Bottom)]);
          end;
      end;
    end;

    stModern:
    begin

      { Default style }
      FrameColor := ColorOf(seBtnFrame);
      FaceColor := Color;

      if bsHover in FState then
      begin
        FrameColor := ColorOf(seBtnFacePressed);
        FaceColor := ColorOf(seBtnFace);

        if bsPressed in FState then
        begin
          FrameColor := ColorOf(seBtnFramePressed);
          FaceColor := ColorOf(seBtnFacePressed);
        end;
      end;

      Canvas.Pen.Color := FrameColor;
      Canvas.Brush.Color := FaceColor;
      Canvas.Rectangle(ClientRect);
    end;

  end;

  DrawTextRect(Canvas, ClientRect, Classes.taCenter, taVerticalCenter, Caption, wkEllipsis);
end;

procedure TNxGraphicButton.SetState(const Value: TNxButtonState);
begin
  if Value <> FState then
  begin
    FState := Value;

    { Refresh }
    Invalidate;
  end;
end;

procedure TNxGraphicButton.SetStyle(const Value: TNxAppearanceStyle);
begin
  if Value <> FStyle then
  begin
    FStyle := Value;

    { Refresh }
    Invalidate;
  end;
end;

procedure TNxGraphicButton.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
  Message.Result := 1;
end;

procedure TNxGraphicButton.WndProc(var Message: TMessage);
begin
  
  if Owner <> nil then
  inherited;

end;

{ TNxPopupControl6 }

procedure TNxPopupControl6.AfterPopup;
begin

end;

procedure TNxPopupControl6.BeforePopup;
begin

end;

procedure TNxPopupControl6.Close(Value: WideString);
begin
  if Assigned(DropDown)
    and DropDown.AutoClose then
  begin
    { Set State }
    Include(FPopupState, psClosing);

    { Close & Destroy }
    DropDown.DroppedDown := False;
  end;
end;

procedure TNxPopupControl6.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  ReleaseCapture;
end;

procedure TNxPopupControl6.CMMouseLeave(var Message: TMessage);
var
  CursorPos: TPoint;
begin
  inherited;

  GetCursorPos(CursorPos);
  if not PtInRect(BoundsRect, CursorPos) then
  begin
    SetCaptureControl(Self);
  end;
end;

constructor TNxPopupControl6.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csNoDesignVisible, csAcceptsControls];

  Supports(AOwner, INxDropDown, FDropDown);

  FPopupState := [];

  { Init. Fields }
  FMouseDown := False;
  FShowShadow := False;

  { Init. Properties }
  BorderSize := 1;
  ScrollBars := [];
  Visible := False;
end;

procedure TNxPopupControl6.CreateParams(var Params: TCreateParams);
const
  CS_DROPSHADOW = $00020000;
begin
  inherited CreateParams(Params);
  with Params do
  begin
    WndParent := GetDesktopWindow;
    Style := WS_CLIPSIBLINGS or WS_CHILD or WS_TABSTOP;
    ExStyle := WS_EX_TOPMOST or WS_EX_TOOLWINDOW;
    WindowClass.Style := CS_DBLCLKS or CS_SAVEBITS;
  end;

  { Enable drop shadow effect on
    Windows XP & later }
  if ShowShadow then

    if (Win32Platform = VER_PLATFORM_WIN32_NT) and
      ((Win32MajorVersion > 5) or
        ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) then
          Params.WindowClass.Style := Params.WindowClass.Style or
            CS_DROPSHADOW;
end;

procedure TNxPopupControl6.CreateWnd;
begin
  inherited;
  Windows.SetParent(Handle, 0);
end;

function TNxPopupControl6.GetCanvas: TCanvas;
begin
  Result := Canvas;
end;

function TNxPopupControl6.GetControlRect: TRect;
var
  TopLeft, BottomRight: TPoint;
begin
  TopLeft := ScreenToClient(BoundsRect.TopLeft);
  BottomRight := ScreenToClient(BoundsRect.BottomRight);
  Result := Rect(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y);
end;

function TNxPopupControl6.GetDropDown: INxDropDown;
begin
  Result := FDropDown;
end;

function TNxPopupControl6.GetFont: TFont;
begin
  Result := Font;
end;

procedure TNxPopupControl6.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  inherited;

  FMouseDown := True; { Process Clicks }

  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    // Click inside ClientRect
  end
  else if PtInRect(ControlRect, Point(X, Y)) then
  begin

  end
  else
    if Assigned(DropDown) then
      DropDown.DroppedDown := False;
end;

procedure TNxPopupControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;

end;

procedure TNxPopupControl6.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if csDestroying in ComponentState then Exit;
  if psClosing in FPopupState then Exit;

  inherited;

  if FMouseDown and PtInRect(ClientRect, Point(X, Y)) then
  begin
    { Set State }
    Include(FPopupState, psClosing);

    if Assigned(DropDown) then
    begin
      { Close & Destroy }
      DropDown.DroppedDown := False;
      Exit;
    end;
  end
  else if PtInRect(ControlRect, Point(X, Y)) then
  begin

  end
  else SetCaptureControl(Self);

  FMouseDown := False; { ! }
end;

procedure TNxPopupControl6.Popup(const Location: TPoint; Anchor: TNxPopupAnchor = paLeft);
begin
  Popup(Location.X, Location.Y, Anchor);
end;

procedure TNxPopupControl6.SetDropDown(const Value: INxDropDown);
begin
  FDropDown := Value;
end;

procedure TNxPopupControl6.SetShowShadow(const Value: Boolean);
begin
  if Value <> FShowShadow then
  begin
    FShowShadow := Value;

    { Call CreateParams }
    RecreateWnd;
  end;
end;

procedure TNxPopupControl6.UpdatePopup;
begin
  inherited;

end;

procedure TNxPopupControl6.Popup(const X, Y: Integer; Anchor: TNxPopupAnchor = paLeft);
var
  HCurrMonitor: HMONITOR;
  MonitorInf: MONITORINFO;
  PopupRect, MonRect: TRect;
  Ctrl: TControl;
  NX, NY: Integer;
  CursorPos: TPoint;
begin
  { Note: Adjust size
          before show! }
  BeforePopup;

  case Anchor of
    paLeft: PopupRect := Bounds(X, Y, Width, Height);
    paRight: PopupRect := Bounds(X - Width, Y, Width, Height);
  end;

  NX := PopupRect.Left;
  NY := Y;

  HCurrMonitor := MonitorFromRect(@PopupRect, MONITOR_DEFAULTTONEAREST);
  MonitorInf.cbSize := SizeOf(MonitorInf);
  GetMonitorInfo(HCurrMonitor, @MonitorInf);

  MonRect := MonitorInf.rcWork;

  if PopupRect.Left < MonRect.Left then NX := MonRect.Left;
  if PopupRect.Right > MonRect.Right then NX := MonRect.Right - Width;
  if PopupRect.Top < MonRect.Top then NY := MonRect.Top;
  if PopupRect.Bottom > MonRect.Bottom then NY := MonRect.Bottom - Height;

  Ctrl := TControl(Owner);

  if (NY < Y) and (NY + Height > Y + Ctrl.Height) then
  begin
    NY := Y - Height;
    Ny := NY - Ctrl.Height;
  end;


  SetWindowPos(Handle, HWND_TOP, NX, NY, Width, Height, SWP_SHOWWINDOW);

  Visible := True;

  AfterPopup;

  Repaint;

  GetCursorPos(CursorPos);

  if not PtInRect(BoundsRect, CursorPos) then
  begin
    SetCaptureControl(Self);
  end;
end;

procedure TNxPopupControl6.WMNCMouseLeave(var Message: TMessage);
begin
  inherited;
  SetCaptureControl(Self);
end;

procedure TNxPopupControl6.WMNCPaint(var Message: TMessage);
var
  DC: HDC;
  BRUSH: HBRUSH;
  R: TRect;
begin
  DC := GetWindowDC(Handle);
  GetWindowRect(Handle, R);
  OffsetRect(R, -R.Left, -R.Top);
  BRUSH := CreateSolidBrush(ColorToRGB(ColorOf(seWindowFrame)));
  FrameRect(DC, R, BRUSH);
  DeleteObject(BRUSH);
  ReleaseDC(Handle, DC);
end;

{ TNxEditPopupControl6 }

procedure TNxEditPopupControl6.Close(Value: WideString);
begin
  Edit.Text := Value;
  inherited;
end;

constructor TNxEditPopupControl6.Create(AOwner: TComponent);
begin
  inherited;
  FEdit := TCustomEdit(AOwner);
end;

{ TNxListPopupControl6 }

function TNxListPopupControl6.GetPageItemCount: Integer;
begin
  Result := Min(DropDownCount, Count);
end;

procedure TNxListPopupControl6.KeyDown(var Key: Word; Shift: TShiftState);
var
  Index: Integer;
begin
  inherited;
  case Key of
    VK_NEXT:
    begin
      if ItemIndex < VertScrollBar.Position + Pred(PageItemCount)
        then Index := VertScrollBar.Position + Pred(PageItemCount)
        else Index := ItemIndex + PageItemCount;

      ItemIndex := Min(Index, Pred(Count));
    end;
    VK_PRIOR:
    begin
      if ItemIndex > VertScrollBar.Position
        then Index := VertScrollBar.Position
        else Index := ItemIndex - PageItemCount;

      ItemIndex := Max(Index, 0);
    end;
  end;
end;

procedure TNxListPopupControl6.Paint;
begin
  inherited Paint;
  Canvas.Font.Assign(Font);
end;

function TNxListPopupControl6.PaintCell(const Index: Integer; CellRect: TRect;
  State: TOwnerDrawState): Boolean;
var
  Ref: INxStringsControl;
begin
  Result := True;

  if Supports(Edit, INxStringsControl, Ref) then
  begin
    Result := Ref.PaintCell(Index, CellRect, State);
  end;
end;

procedure TNxListPopupControl6.ScrollDown;
begin
  VertScrollBar.Prior;
end;

procedure TNxListPopupControl6.ScrollToItem(const Index: Integer);
begin
  if Index < VertScrollBar.Position then
  begin
    VertScrollBar.MoveBy(Index - VertScrollBar.Position);
  end else if Index > VertScrollBar.Position + Pred(PageItemCount) then
  begin
    VertScrollBar.Position := Succ(Index - DropDownCount);
  end;
end;

procedure TNxListPopupControl6.ScrollUp;
begin
  VertScrollBar.Next;
end;

procedure TNxListPopupControl6.UpdateVertScrollBar;
begin

end;

{ TNxStringsPopupControl6 }

procedure TNxStringsPopupControl6.AfterPopup;
begin
  UpdateVertScrollBar;
end;

procedure TNxStringsPopupControl6.BeforePopup;
begin
  Width := StringsControl.ListWidth;

  if Width = 0 then Width := Edit.Width;

  if Count > 0 then
  begin
    ClientHeight := ItemHeight * Min(DropDownCount, Count);

    UpdateVertScrollBar;

    VertScrollBar.Position := Succ(ItemIndex - DropDownCount);
    HotIndex := ItemIndex;
  end
  else ClientHeight := 2;

end;

constructor TNxStringsPopupControl6.Create(AOwner: TComponent);
begin
  inherited;
  FHotIndex := -1;

  { Initialize }
  ScrollBars := [sbVertical];
  Width := 200;
  Height := 200;
end;

function TNxStringsPopupControl6.GetCount: Integer;
begin
  Result := Items.Count;
end;

function TNxStringsPopupControl6.GetDropDownCount: Integer;
begin
  Result := StringsControl.DropDownCount;
end;

function TNxStringsPopupControl6.GetItemHeight: Integer;
begin
  Result := StringsControl.ItemHeight;
end;

function TNxStringsPopupControl6.GetItemIndex: Integer;
begin
  Result := StringsControl.ItemIndex;
end;

function TNxStringsPopupControl6.GetItems: TStrings;
begin
  Result := StringsControl.Items;
end;

function TNxStringsPopupControl6.GetStringsControl: INxStringsControl;
begin
  Supports(Owner, INxStringsControl, Result);
end;

procedure TNxStringsPopupControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    HotIndex := VertScrollBar.Position + (Y div ItemHeight);
  end;
end;

procedure TNxStringsPopupControl6.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    ItemIndex := VertScrollBar.Position + (Y div ItemHeight);
  end;

  inherited;
end;

procedure TNxStringsPopupControl6.Paint;
var
  i, Y: Integer;
  ItemRect: TRect;
  State: TOwnerDrawState;
begin
  inherited Paint;

  { Start }
  i := VertScrollBar.Position;
  Y := 0;

  if Count = 0
  then EraseBkGnd(ClientRect)
  else
    while i < Count do
    begin
      ItemRect := Bounds(0, Y, ClientWidth, ItemHeight);

      State := [];
      if i = HotIndex then State := State + [odSelected, odHotLight];

      PaintCell(i, ItemRect, State);

      Inc(i);
      Inc(Y, ItemHeight);

      { Done }
      if Y > ClientHeight
        then Break;
    end;

end;

//function TNxStringsPopupControl6.PaintCell(const Index: Integer; CellRect: TRect; Selected: Boolean): Boolean;
//begin
//  { Default, or owned paint? }
//  inherited PaintCell(Index, CellRect, Selected);// then
////    with Canvas do
////    begin
////      { Padding }
////      Inc(CellRect.Left, pdStandard);
////
////      DrawTextRect(Canvas, CellRect, taLeftJustify, taVerticalCenter, Items[Index], wkNone);
////    end;
//end;

procedure TNxStringsPopupControl6.RefreshItem(const Index: Integer);
begin
  if InRange(Index, 0, Pred(Count)) then
    InvalidateRect(Bounds(0, (Index - VertScrollBar.Position) * ItemHeight, ClientWidth, ItemHeight));
end;

procedure TNxStringsPopupControl6.ScrollContentBy(DeltaX, DeltaY: Integer);
begin
  ScrollRect(0, -ItemHeight * DeltaY, ClientRect, ClientRect);
end;

procedure TNxStringsPopupControl6.ScrollRect(DeltaX, DeltaY: Integer; Rect,
  ClipRect: TRect);
begin
{$IFDEF UNSAFE}
  ScrollWindowEx(Handle, DeltaX, DeltaY, @Rect, @ClipRect, 0, nil, SW_INVALIDATE);
{$ELSE}
  ScrollWindowEx(Handle, DeltaX, DeltaY, Rect, ClipRect, 0, nil, SW_INVALIDATE);
{$ENDIF}
end;

procedure TNxStringsPopupControl6.SetHotIndex(const Value: Integer);
var
  T: Integer;
begin
  if Value <> FHotIndex then
  begin
    T := FHotIndex;
    FHotIndex := Value;

    RefreshItem(T);
    RefreshItem(FHotIndex);
  end;
end;

procedure TNxStringsPopupControl6.SetItemIndex(const Value: Integer);
begin
  { Set ItemIndex & call Event }
  StringsControl.TryItemIndex(Value, True);
end;

procedure TNxStringsPopupControl6.UpdatePopup;
begin
  inherited;
  HotIndex := ItemIndex;
  ScrollToItem(ItemIndex);
  Repaint;
end;

procedure TNxStringsPopupControl6.UpdateVertScrollBar;
begin
  VertScrollBar.Max := Pred(Count);
  VertScrollBar.PageSize := PageItemCount;
end;

{ TNxCheckPopupControl6 }

function TNxCheckPopupControl6.GetCheckBoxAtPos(X, Y: Integer): Integer;
begin
  Result := -1;
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    Result := VertScrollBar.Position + (Y div ItemHeight);

    { Not inside checkbox? }
    if not PtInRect(GetCheckBoxRect(Result), Point(X, Y))
      then Result := -1;
  end;
end;

function TNxCheckPopupControl6.GetCheckBoxRect(const Index: Integer): TRect;
var
  Container: TRect;
  CheckBoxLocation: TPoint;
begin
  Container := Bounds(0, (Index - VertScrollBar.Position) * ItemHeight, ClientWidth, ItemHeight);
  Container.Right := Container.Left + CheckBoxSize.cx + pdDouble;

  CheckBoxLocation := PosInRect(CheckBoxSize.cx, CheckBoxSize.cy, Container, Classes.taCenter, taVerticalCenter);

  Result := Bounds(CheckBoxLocation.X, CheckBoxLocation.Y, CheckBoxSize.cx, CheckBoxSize.cy);
end;

function TNxCheckPopupControl6.GetCheckBoxSize: TSize;
const
  BoxSize: array[Boolean] of Integer = (11, 13);
begin
  Result := Size(BoxSize[Themed], BoxSize[Themed]);
end;

procedure TNxCheckPopupControl6.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
  Reference: INxCheckPopupOwner;
begin
  Index := GetCheckBoxAtPos(X, Y);
  if Index <> -1 then
  begin
    if Supports(FEdit, INxCheckPopupOwner, Reference) then
    begin
      Reference.CheckBoxClick(Index);
      RefreshCheckBox(Index);
    end;
  end;

  inherited;
end;

procedure TNxCheckPopupControl6.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  { Not click on checkbox? Then, close }
  if GetCheckBoxAtPos(X, Y) = -1
    then inherited;
end;

procedure TNxCheckPopupControl6.RefreshCheckBox(const Index: Integer);
begin
  { Refresh }
  InvalidateRect(GetCheckBoxRect(Index));
end;

{ TNxDatePickerView }

procedure TNxDatePickerView.Changed;
var
  InvalidationRect: TRect;
begin
  case FSelectionMode of
    dmDays: InvalidationRect := DaysRect;
    dmMonths: InvalidationRect := MonthsRect;
    else InvalidationRect := ContentRect;
  end;
  InvalidateControl(Control.Handle, InvalidationRect);

  InvalidationRect := HeaderTitleRect;
  InvalidateControl(Control.Handle, InvalidationRect);
end;

constructor TNxDatePickerView.Create;
begin
  FDown := False;
  FHotDay := 0;
  FHotMonth := -1;
  FPressedMonth := -1;
  FSelectionDateRange := drAll;
  FSelectionMode := dmDays;
  FValue := '';
end;

procedure TNxDatePickerView.DoCustomDrawDate(Date: TDateTime; DayRect: TRect);
begin
  if Assigned(FOnCustomDrawDate) then FOnCustomDrawDate(Self, Date, DayRect);
end;

procedure TNxDatePickerView.DoGetDateColor(Date: TDateTime;
  var DayColor: TColor);
begin
  if Assigned(FOnGetDateColor) then FOnGetDateColor(DatePopupControl, Date, DayColor);
end;

procedure TNxDatePickerView.FillDay(Date: TDateTime; DayRect: TRect; DayColor: TColor);
begin
  DoGetDateColor(Date, DayColor);
  with Canvas do
  begin
    Brush.Color := DayColor;
    FillRect(DayRect);
  end;
end;

function TNxDatePickerView.GetActualStartDay: TNxStartDayOfWeek;
var
  D: array[0..1] of Char;
begin
  case FStartDay of
    dwSystem:
    begin
      GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, D, SizeOf(D));
      case StrToInt(D) of
        0: Result := dwMonday;
        else Result := dwSunday;
      end;
    end
    else Result := FStartDay;
  end;
end;

function TNxDatePickerView.GetContentRect: TRect;
begin
  Result := ClientRect;
  Result.Top := GetHeaderRect.Bottom;
end;

function TNxDatePickerView.GetDatePopupControl: TNxDatePopupControl6;
begin
  Result := TNxDatePopupControl6(Control);
end;

function TNxDatePickerView.GetDayAtPos(const X, Y: Integer): TDateTime;
var
  Pos: TPoint;
  DayRect: TRect;
  j, i: Integer;
begin
  { Start }
  Pos := DaysRect.TopLeft;

  Result := EncodeDate(Year, Month, 1);

  { Not a first in week }
  if GetDayOfWeek(StartOfAMonth(Year, Month)) > 1 then
  begin
    { 1 - 7 }
    Result := IncDay(Result, -Pred(GetDayOfWeek(StartOfAMonth(Year, Month))));
  end;

  for i := 1 to 6 do
  begin
    for j := 1 to 7 do
    begin
      DayRect := Bounds(Pos.X, Pos.Y, DayWidth, DayHeight);

      { Done? }
      if PtInRect(DayRect, Point(X, Y))
        then Exit;

      Result := IncDay(Result);

      Inc(Pos.X, DayWidth);
    end;

    Inc(Pos.Y, DayHeight);

    Pos.X := DaysRect.Left;
  end;

  { None }
  Result := 0;
end;

function TNxDatePickerView.GetDayHeight: Integer;
begin
  Result := DotToPixel(FDayHeight);
end;

function TNxDatePickerView.GetDayRect(const Date: TDateTime): TRect;
var
  Pos: TPoint;
  Day: TDateTime;
  j, i: Integer;
begin
  { Invalid Date }
  if (Date = 0) or (Year = 0) or (Month = 0) then Exit;

  { Start }
  Pos := DaysRect.TopLeft;

  Day := EncodeDate(Year, Month, 1);

  { Not a first in week }
  if GetDayOfWeek(StartOfAMonth(Year, Month)) > 1 then
  begin
    Day := IncDay(Day, -Pred(GetDayOfWeek(StartOfAMonth(Year, Month))));
  end;

  for i := 1 to 6 do
  begin
    for j := 1 to 7 do
    begin
      Result := Bounds(Pos.X, Pos.Y, DayWidth, DayHeight);

      { Done? }
      if Day = Date
        then Exit;

      Day := IncDay(Day);

      Inc(Pos.X, DayWidth);
    end;

    Inc(Pos.Y, DayHeight);

    Pos.X := DaysRect.Left;
  end;

  { None }
  Result := Bounds(0, 0, 0, 0);
end;

function TNxDatePickerView.GetDaysRect: TRect;
begin
  Result := Bounds(DotToPixel(8), WeekDaysRect.Bottom, DayWidth * 7, DayHeight * 6);
end;

function TNxDatePickerView.GetDayWidth: Integer;
begin
  Result := DotToPixel(FDayWidth);
end;

/// <summary>
/// Gets compete header rectangle including arrows.
/// </summary>
function TNxDatePickerView.GetHeaderRect: TRect;
begin
  Result := Rect(1, 1, ClientRect.Right - 1, DayHeight);
end;

function TNxDatePickerView.GetHeaderTitleRect: TRect;
begin
  Result := Rect(GetLeftArrowRect.Right, HeaderRect.Top, GetRightArrowRect.Left, HeaderRect.Bottom);
end;

function TNxDatePickerView.GetLeftArrowRect: TRect;
begin
  with Result do
  begin
    Left := 0;
    Top := 0;
    Bottom := HeaderRect.Bottom;
    Right := Bottom;
  end;
end;

function TNxDatePickerView.GetMonthAtPos(const X, Y: Integer): Integer;
var
  TopLeft: TPoint;
  c, r: Integer;
begin
  if PtInRect(MonthsRect, Point(X, Y)) then
  begin
    TopLeft := MonthsRect.TopLeft;
    c := ((X - TopLeft.X) div MonthSize.cx) + 1;
    r := (Y - TopLeft.Y) div MonthSize.cy;
    Result := c + r * 4;
  end else Result := -1;
end;

function TNxDatePickerView.GetMonthName(Month: Integer): WideString;
begin
  Result := LocalSettings.LongMonthNames[Month];

//  if Assigned(FMonthNames) and InRange(Month, 1, 12)
//    and (FMonthNames.Count >= 12)
//      then Result := FMonthNames[Month - 1]
//        else Result := LocalSettings.LongMonthNames[Month];

end;

function TNxDatePickerView.GetMonthRect(const AMonth: Integer): TRect;
var
  c, r: Integer;
begin
  r := Pred(AMonth) div 4;
  c := Pred(AMonth) mod 4;
  Result := Bounds(c * MonthSize.cx, r * MonthSize.cy, MonthSize.cx, MonthSize.cy);
  OffsetRect(Result, MonthsRect.Left, MonthsRect.Top);
end;

function TNxDatePickerView.GetMonthSize: TSize;
begin
  with Result do
  begin
    cx := (RectWidth(ContentRect) - DotToPixel(4)) div 4;
    cy := DayHeight * 7 div 3;
  end;
end;

function TNxDatePickerView.GetMonthsRect: TRect;
begin
  Result := Bounds(DotToPixel(3), HeaderRect.Bottom, MonthSize.cx * 4, MonthSize.cy * 4);
end;

function TNxDatePickerView.GetRightArrowRect: TRect;
begin
  with Result do
  begin
    Left := ClientRect.Right - HeaderRect.Bottom;
    Top := 0;
    Right := ClientRect.Right;
    Bottom := HeaderRect.Bottom;
  end;
end;

function TNxDatePickerView.GetWeekDaysRect: TRect;
begin
  Result := Bounds(DotToPixel(8), HeaderRect.Bottom, ClientRect.Right, DayHeight);
end;

function TNxDatePickerView.GetYearAtPos(const X, Y: Integer): Integer;
var
  Offset: TPoint;
  c, r: Integer;
begin
  Result := 0;
  Offset := ContentRect.TopLeft;
  if PtInRect(Bounds(Offset.X, HeaderRect.Bottom, MonthSize.cx * 4, MonthSize.cy * 3), Point(X, Y)) then
  begin
    c := (X - Offset.X) div MonthSize.cx;
    r := (Y - Offset.Y) div MonthSize.cy;

    Result := Year + (c + r * 4) - 1;
  end;
end;

function TNxDatePickerView.GetYearSize: TSize;
begin
  with Result do
  begin
    cx := (RectWidth(ContentRect) - 10) div 4;
    cy := DayHeight * 7 div 3;
  end;
end;

function TNxDatePickerView.IsShown(Date: TDateTime): Boolean;
var
  Day: TDateTime;
  j, i: Integer;
begin
  Result := False;

  Day := EncodeDate(Year, Month, 1);

  { Not a first in week }
  if GetDayOfWeek(StartOfAMonth(Year, Month)) > 1 then
  begin
    { Prev. month }
    Day := IncDay(Day, -GetDayOfWeek(StartOfAMonth(Year, Month)));
  end;

  for i := 1 to 6 do
    for j := 1 to 7 do
    begin
      { Done? }
      if Day = Date then
      begin
        Result := True;

        Exit;
      end;

      Day := IncDay(Day);
    end;
end;

class function TNxDatePickerView.IsValidDateSelection(const Date: TDateTime;
  const SelectionDateRange: TNxDateRange): Boolean;
begin
  case SelectionDateRange of
    drPastOnly: Result := Date <= Today;
    drFutureOnly: Result := Date >= Today;
    else Result := True;
  end;
end;

procedure TNxDatePickerView.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  if PtInRect(GetLeftArrowRect, Point(X, Y)) then
  begin
    DatePopupControl.PrevMonth;
  end;

  if PtInRect(GetRightArrowRect, Point(X, Y)) then
  begin
    DatePopupControl.NextMonth;
  end;

  if PtInRect(GetHeaderTitleRect, Point(X, Y)) then
  begin
    case SelectionMode of
      dmDays: SelectionMode := dmMonths;
      dmMonths: SelectionMode := dmYears;
      else SelectionMode := dmDays;
    end;
  end;

  if PtInRect(ContentRect, Point(X, Y)) then
  begin
    case SelectionMode of
      dmDays: ;
      dmMonths: PressedMonth := GetMonthAtPos(X, Y);
      else ;
    end;
  end;

  Down := True;
end;

procedure TNxDatePickerView.MouseLeave;
begin
  inherited;
  HotDay := 0;
  HotMonth := -1;
end;

procedure TNxDatePickerView.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  case SelectionMode of
    dmDays: HotDay := GetDayAtPos(X, Y);
    dmMonths:
    begin
      HotMonth := GetMonthAtPos(X, Y);
      if Down then PressedMonth := HotMonth;
    end;
    dmYears: ;
  end;
end;

procedure TNxDatePickerView.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  case SelectionMode of
    dmDays:
      { Inside days click? }
      if PtInRect(DaysRect, Point(X, Y))
        and Down then
      begin
        if IsValidDateSelection(HotDay, SelectionDateRange) then
        begin
          { Event }
          DatePopupControl.DropDown.DoSelect;

          { Assign value & close? }
          FValue := DateToStr(HotDay);
        end;
      end;
    dmMonths:
      begin
        if PtInRect(ContentRect, Point(X, Y)) then
        begin
          Month := GetMonthAtPos(X, Y);
          SelectionMode := dmDays;
        end;
        PressedMonth := -1;
      end;
    dmYears: if PtInRect(ContentRect, Point(X, Y)) then Year := GetYearAtPos(X, Y);
  end;
  FDown := False;
end;

function TNxDatePickerView.GetDayInWeekText(DayInWeek: Integer): WideString;
begin
  case GetActualStartDay of
    dwSunday: Result := LeftStr(LocalSettings.LongDayNames[DayInWeek], 2);
    dwMonday: if DayInWeek = 7
      then Result := LeftStr(LocalSettings.LongDayNames[1], 2)
      else Result := LeftStr(LocalSettings.LongDayNames[DayInWeek + 1], 2);
  end;

end;

function TNxDatePickerView.GetDayOfWeek(Day: TDateTime): Integer;
begin
  case GetActualStartDay of
    dwSunday: Result := DayOfWeek(Day);
    else Result := DayOfTheWeek(Day);
  end;
end;

procedure TNxDatePickerView.Paint;
begin
  PaintHeader;
  case FSelectionMode of
    dmDays: PaintDaysView(DaysRect);
    dmMonths: PaintMonthsView(MonthsRect);
    dmYears: PaintYearsView(ContentRect);
  end;
end;

procedure TNxDatePickerView.PaintCell(const CellRect: TRect; const State: TNxButtonState;
  const Text: string);
var
  FillColor: TColor;
  TextRect: TRect;
begin
  with Canvas do
  begin
    FillColor := Color;
    if bsSelected in State then
    begin
      Font.Color := clWhite;
      FillColor := ColorOf(seMenu);
      Brush.Color := FillColor;
      FillRect(CellRect);
    end else
    begin
      Font.Color := clWindowText;
      if bsPressed in State then
      begin
        Brush.Color := ColorOf(seBtnFace);
        FillRect(CellRect);
      end else
      begin
        Brush.Color := FillColor;
        FillRect(CellRect);
        if bsHover in State then
        begin
          Pen.Color := ColorOf(seMenu);
          if bsDisabled in State then Pen.Color := clSilver;
          RoundRect(CellRect.Left, CellRect.Top, CellRect.Right, CellRect.Bottom, 2, 2);
        end;
      end;
    end;
  end;
  TextRect := CellRect;
  Dec(TextRect.Right, pdDouble + 1);
  DrawTextRect(Canvas, TextRect, taRightJustify, taVerticalCenter, Text, wkNone);
end;

procedure TNxDatePickerView.PaintDay(DayRect: TRect; Day: TDateTime);
var
  Yr, Mo, Dy: Word;
  TxtRect: TRect;
  FillColor: TColor;
  ValidDateSelection: Boolean;
begin
  with Canvas do
  begin
    ValidDateSelection := IsValidDateSelection(Day, SelectionDateRange);
    if Day = Today then
    begin
      Font.Color := clWhite;
      FillDay(Day, DayRect, ColorOf(seMenu));
    end else
    begin
      Font.Color := clWindowText;

      if MonthOf(Day) <> Month
        then Font.Color := clGrayText;

      if not IsValidDateSelection(Day, SelectionDateRange)
        then Font.Color := clSilver;

      FillColor := Color;
      if Down then
      begin
        if Day = HotDay then
        begin
          FillColor := IfThen(ValidDateSelection, ColorOf(seBtnFace), clBtnFace);
        end;

      end else
      begin
        if Day = Selected then FillColor := ColorOf(seBtnFace);
      end;

      FillDay(Day, DayRect, FillColor);

      if (Day = HotDay) and not Down then
      begin
        Pen.Color := ColorOf(seMenu);
        if not ValidDateSelection then Pen.Color := clSilver;
        RoundRect(DayRect.Left, DayRect.Top, DayRect.Right, DayRect.Bottom, 2, 2);
      end;

    end;

    DecodeDate(Day, Yr, Mo, Dy);

    { Right Margin }
    TxtRect := DayRect;
    Dec(TxtRect.Right, pdDouble + 1);

    DrawTextRect(Canvas, TxtRect, taRightJustify, taVerticalCenter, IntToStr(Dy), wkNone);

    DoCustomDrawDate(Day, DayRect);
  end;
end;

procedure TNxDatePickerView.PaintDays(const X, Y: Integer);
var
  Pos: TPoint;
  DayRect: TRect;
  Day: TDateTime;
  j, i: Integer;
begin
  Pos := Point(X, Y);

  Day := EncodeDate(Year, Month, 1);

  { Not first in week? }
  if GetDayOfWeek(StartOfAMonth(Year, Month)) > 1 then
  begin
    { 1 - 7 }
    Day := IncDay(Day, -Pred(GetDayOfWeek(StartOfAMonth(Year, Month))));
  end;

  for i := 1 to 6 do
  begin
    for j := 1 to 7 do
    begin
      DayRect := Bounds(Pos.X, Pos.Y, DayWidth, DayHeight);

      PaintDay(DayRect, Day);

      Day := IncDay(Day);

      Inc(Pos.X, DayWidth);
    end;

    Inc(Pos.Y, DayHeight);

    Pos.X := X;
  end;

end;

procedure TNxDatePickerView.PaintDaysView(const AContentRect: TRect);
var
  Pos: TPoint;
begin
  { Days of week }
  Pos := WeekDaysRect.TopLeft;
  PaintWeekDays(Pos.X, Pos.Y);

  { Days }
  Pos := DaysRect.TopLeft;
  PaintDays(Pos.X, Pos.Y);
end;

procedure TNxDatePickerView.PaintHeader;
var
  R: TRect;
  Mid: Integer;
begin
  R := HeaderRect;

  with Canvas do
  begin
    Brush.Color := $00f0f0f0;
    FillRect(R);
    Font.Color := clWindowText;
    Font.Style := [fsBold];

    { Title }
    DrawTextRect(Canvas, R, Classes.taCenter, taVerticalCenter, GetMonthName(Month) + ' ' + IntToStr(Year), wkNone);
    Font.Style := [];

    Brush.Color := $00444444;
    Pen.Color := Brush.Color;

    { Shape Rect }
    R := Bounds(0, 0, DotToPixel(8 div 2), DotToPixel(8));

    { Left arrow }
    R := CenteredRect(GetLeftArrowRect, R);
    with R do
    begin
      Mid := Top + RectHeight(R) div 2;
      Polygon([
        Point(Left, Mid),
        Point(Right, Top),
        Point(Right, Bottom)
      ]);
    end;

    { Right arrow }
    R := CenteredRect(GetRightArrowRect, R);
    with R do
    begin
      Polygon([
        Point(Left, Top),
        Point(Right, Mid),
        Point(Left, Bottom)
      ]);
    end;

  end;
end;

procedure TNxDatePickerView.PaintMonthsView(const AContentRect: TRect);
var
  i, X, Y: Integer;
  MonthRect: TRect;
  State: TNxButtonState;
  S: string;
begin
  X := AContentRect.Left;
  Y := AContentRect.Top;
  for i := 1 to 12 do
  begin
    MonthRect := Bounds(X, Y, MonthSize.cx, MonthSize.cy);

    S := GetMonthName(i);
    S := LeftStr(S, 3);

    State := [];
    if i = Month then Include(State, bsSelected);
    if i = HotMonth then Include(State, bsHover);
    if i = PressedMonth then Include(State, bsPressed);

    PaintCell(MonthRect, State, S);

    Inc(X, MonthSize.cx);
    if i mod 4 = 0 then
    begin
      X := AContentRect.Left;
      Inc(Y, MonthSize.cy);
    end;
  end;
end;

procedure TNxDatePickerView.PaintWeekDays(const X, Y: Integer);
var
  i: Integer;
  Pos: TPoint;
  DayRect, TxtRect: TRect;
begin
  { Start }
  Pos := Point(X, Y);

  { Dim font }
  Canvas.Font.Color := clGrayText;

  for i := 1 to 7 do
  begin
    DayRect := Bounds(Pos.X, Pos.Y, DayWidth, DayHeight);

    TxtRect := DayRect;
    Dec(TxtRect.Right, pdDouble + 1);

    DrawTextRect(Canvas, TxtRect, taRightJustify, taVerticalCenter, WideUpperCase(GetDayInWeekText(i)), wkNone);

    Inc(Pos.X, DayWidth);
  end;
end;

procedure TNxDatePickerView.PaintYearsView(const AContentRect: TRect);
var
  i, X, Y, yr: Integer;
  YearRect: TRect;
  State: TNxButtonState;
  S: string;
begin
  yr := Year - 1;
  X := AContentRect.Left;
  Y := AContentRect.Top;
  for i := 1 to 12 do
  begin
    YearRect := Bounds(X, Y, YearSize.cx, YearSize.cy);

    S := IntToStr(yr);

    State := [];
    if yr = Year then Include(State, bsSelected);

    PaintCell(YearRect, State, S);

    Inc(yr);

    Inc(X, YearSize.cx);
    if i mod 4 = 0 then
    begin
      X := AContentRect.Left;
      Inc(Y, YearSize.cy);
    end;

  end;
end;

procedure TNxDatePickerView.RefreshDay(const Date: TDateTime);
var
  R: TRect;
begin
  if IsShown(Date) then
  begin
    R := GetDayRect(Date);
    InvalidateControl(Control.Handle, R);
  end;
end;

procedure TNxDatePickerView.RefreshMonth(const AMonth: Integer);
begin
  if InRange(AMonth, 1, 12) then InvalidateRect(GetMonthRect(AMonth));
end;

procedure TNxDatePickerView.SetColor(const Value: TColor);
begin
  FColor := Value;
end;

procedure TNxDatePickerView.SetDayHeight(const Value: Integer);
begin
  FDayHeight := Value;
end;

procedure TNxDatePickerView.SetDayWidth(const Value: Integer);
begin
  FDayWidth := Value;
end;

procedure TNxDatePickerView.SetDown(const Value: Boolean);
begin
  if Value <> FDown then
  begin
    FDown := Value;
    RefreshDay(Selected);
    RefreshDay(FHotDay);
  end;
end;

procedure TNxDatePickerView.SetHotDay(const Value: TDateTime);
var
  T: TDateTime;
begin
  if Value <> FHotDay then
  begin
    T := FHotDay;
    FHotDay := Value;
    RefreshDay(T);
    RefreshDay(FHotDay);
  end;
end;

procedure TNxDatePickerView.SetHotMonth(const Value: Integer);
begin
  if Value <> FHotMonth then
  begin
    if InRange(FHotMonth, -1, 12) then InvalidateRect(GetMonthRect(FHotMonth));
    if InRange(Value, -1, 12) then
    begin
      FHotMonth := Value;
      if FHotMonth <> -1 then InvalidateRect(GetMonthRect(FHotMonth));
    end;
  end;
end;

procedure TNxDatePickerView.SetMonth(const Value: Word);
begin
  if Value <> FMonth then
  begin
    FMonth := Value;
    if FMonth < 1 then
    begin
      FMonth := 12;
      Dec(FYear);
    end;
    if FMonth > 12 then
    begin
      FMonth := 1;
      Inc(FYear);
    end;

    { Refresh }
    Changed;
  end;
end;

procedure TNxDatePickerView.SetPressedMonth(const Value: Integer);
begin
  if Value <> FPressedMonth then
  begin
    RefreshMonth(FPressedMonth);
    FPressedMonth := Value;
    RefreshMonth(FPressedMonth);
  end;
end;

procedure TNxDatePickerView.SetSelected(const Value: TDateTime);
var
  R1, R2: TRect;
begin
  if Value <> FSelected then
  begin
    R1 := GetDayRect(FSelected);

    FSelected := Value;

    if (MonthOf(FSelected) <> Month)
      or (YearOf(FSelected) <> Year) then
    begin
      Month := MonthOf(FSelected);
      Year := YearOf(FSelected);
    end;

    R2 := GetDayRect(FSelected);

    InvalidateRect(R1);
    InvalidateRect(R2);
  end;
end;

procedure TNxDatePickerView.SetSelectionMode(const Value: TNxDateSelectionMode);
begin
  if Value <> FSelectionMode then
  begin
    FSelectionMode := Value;
    InvalidateRect(ContentRect);
  end;
end;

procedure TNxDatePickerView.SetStartDay(const Value: TNxStartDayOfWeek);
begin
  FStartDay := Value;
end;

procedure TNxDatePickerView.SetYear(const Value: Word);
begin
  if Value <> FYear then
  begin
    FYear := Value;
    Changed;
  end;
end;

function TNxDatePickerView.TrySelect(const Date: TDateTime): Boolean;
begin
  Result := False;
  if IsValidDateSelection(Date, SelectionDateRange) then
  begin
    Selected := Date;
    Result := True;
  end;
end;

{ TNxDatePopupControl6 }

constructor TNxDatePopupControl6.Create(AOwner: TComponent);
var
  Year, Month, Day: Word;
begin
  inherited;

  { Init. Buttons }
  FTodayButton := TNxGraphicButton.Create(Self);
  FTodayButton.Caption := 'Today';
  FTodayButton.Font.Assign(Font);
  FTodayButton.Style := stModern;
  FTodayButton.Parent := Self;
  FTodayButton.OnClick := DoButtonClick;
  FTodayButton.SetBounds(DotToPixel(20), DotToPixel(179),
    DotToPixel(60), DotToPixel(26));

  FNoneButton := TNxGraphicButton.Create(Self);
  FNoneButton.Caption := 'None';
  FNoneButton.Font.Assign(Font);
  FNoneButton.Style := stModern;
  FNoneButton.Parent := Self;
  FNoneButton.OnClick := DoButtonClick;
  FNoneButton.SetBounds(DotToPixel(100), DotToPixel(179),
    DotToPixel(60), DotToPixel(26));

  FView := TNxDatePickerView.Create;
  FView.Control := Self;
  FView.SelectionDateRange := FSelectionDateRange;
  FView.StartDay := dwSystem;
  FView.Color := Color;

  FView.FSelected := StrToDateDef(Edit.Text, Today);
  DecodeDate(FView.Selected, Year, Month, Day);
  FView.Year := Year;
  FView.Month := Month;

  FView.Canvas := Canvas;
  FView.OnGetDateColor := DoGetDateColor;
  FView.OnCustomDrawDate := DoCustomDrawDate;

  { Init. Properties }
  Height := DotToPixel(212);
  Width := DotToPixel(180);
end;

destructor TNxDatePopupControl6.Destroy;
begin
  FreeAndNil(FNoneButton);
  FreeAndNil(FTodayButton);
  FreeAndNil(FView);
  inherited;
end;

procedure TNxDatePopupControl6.DoButtonClick(Sender: TObject);
begin
  if Sender = FNoneButton then Close(EmptyStr);
  if Sender = FTodayButton then Close(DateToStr(Today));
end;

procedure TNxDatePopupControl6.DoCustomDrawDate(Sender: TObject; Date: TDateTime; DayRect: TRect);
begin
  PickerOwner.DoCustomDrawDate(Self, Date, DayRect);
end;

procedure TNxDatePopupControl6.DoGetDateColor(Sender: TObject; Date: TDateTime;
  var DayColor: TColor);
begin
  PickerOwner.DoGetDateColor(Self, Date, DayColor);
end;

function TNxDatePopupControl6.GetPickerOwner: INxDatePickerOwner;
begin
  Supports(Edit, INxDatePickerOwner, Result);
end;

procedure TNxDatePopupControl6.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  case Key of
    VK_LEFT:
      if ssShift in Shift then NextMonth else
        FView.TrySelect(IncDay(FView.Selected, -1));
    VK_RIGHT:
      if ssShift in Shift then PrevMonth else
        FView.TrySelect(IncDay(FView.Selected, 1));
    VK_UP: FView.TrySelect(IncWeek(FView.Selected, -1));
    VK_DOWN: FView.TrySelect(IncWeek(FView.Selected, 1));
  end;
end;

procedure TNxDatePopupControl6.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    FView.MouseDown(Button, Shift, X, Y);
  end;
  inherited;
end;

procedure TNxDatePopupControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  FView.MouseMove(Shift, X, Y);
end;

procedure TNxDatePopupControl6.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    if FMouseDown then FView.MouseUp(Button, Shift, X, Y);

    if FView.Value <> ''
      then Close(FView.Value);

  end else inherited;
end;

procedure TNxDatePopupControl6.NextMonth;
begin
  FView.Month := FView.Month + 1;
end;

procedure TNxDatePopupControl6.Paint;
begin
  inherited;

  FView.DayHeight := 21;
  FView.DayWidth := 23;

  try
    { Prepare }
    FView.ClientRect := ClientRect;

    with Canvas do
    begin
      Font.Assign(Self.Font);
      Brush.Color := clWindow;

      try
        { Prevent flickering }
        ExcludeClipRect(Canvas, FView.DaysRect);

        { Fill all excluding days }
        FillRect(ClientRect);
      finally
        SetClipRect(Canvas, ClientRect);
      end;
    end;

    { Paint }
    FView.Paint;
  except

  end;
end;

procedure TNxDatePopupControl6.PrevMonth;
begin
  FView.Month := FView.Month - 1;
end;

procedure TNxDatePopupControl6.SetSelectionDateRange(const Value: TNxDateRange);
begin
  FSelectionDateRange := Value;
  FView.SelectionDateRange := FSelectionDateRange;
end;

procedure TNxDatePopupControl6.SetStartDayOfWeek(
  const Value: TNxStartDayOfWeek);
begin
  FStartDayOfWeek := Value;
  FView.StartDay := FStartDayOfWeek;
end;

{ TNxTimePopupControl6 }

constructor TNxTimePopupControl6.Create(AOwner: TComponent);
begin
  inherited;
  FHotCell := Point(-1, -1);
  FHoursText := 'H';
  FMinuteText := 'M';
  FOptions := [to24HourDay, toMinutes];
  FPressedCell := Point(-1, -1);

  FNowButton := TNxGraphicButton.Create(Self);
  FNowButton.Font.Assign(Font);
  FNowButton.Style := stModern;
  FNowButton.Parent := Self;
  FNowButton.Caption := 'Now';
  FNowButton.SetBounds(22, 280, 60, 26);
  FNowButton.OnClick := DoNowButtonClick;
end;

function TNxTimePopupControl6.GetColCount: Integer;
begin
  Result := 1;
  if to24HourDay in Options then Inc(Result);
  if toMinutes in Options then Inc(Result);
end;

function TNxTimePopupControl6.GetContentRect: TRect;
begin
  Result := ClientRect;
  InflateRect(Result, -1, -1);
end;

function TNxTimePopupControl6.GetHour: Word;
var
  DateTime: TDateTime;
begin
  DateTime := StrToDateTimeDef(Edit.Text, Now);
  Result := HourOf(DateTime);
end;

function TNxTimePopupControl6.GetHoursRect: TRect;
begin
  Result := HeadersRect;
  Result.Right := Result.Left + (2 * RectWidth(Result) div ColCount);
end;

function TNxTimePopupControl6.GetHoursText: string;
begin
  Result := FHoursText;
end;

function TNxTimePopupControl6.GetMinute: Word;
var
  DateTime: TDateTime;
begin
  DateTime := StrToDateTimeDef(Edit.Text, Now);
  Result := MinuteOf(DateTime);
end;

function TNxTimePopupControl6.GetMinutesRect: TRect;
begin
  Result := HeadersRect;
  Result.Left := GetHoursRect.Right;
end;

function TNxTimePopupControl6.GetMinutesText: string;
begin
  Result := FMinuteText;
end;

function TNxTimePopupControl6.GetHeaderRect: TRect;
begin
  Result := Bounds(ContentRect.Left, ContentRect.Top, RectWidth(ContentRect), 21);
end;

destructor TNxTimePopupControl6.Destroy;
begin
  FreeAndNil(FNowButton);
  inherited;
end;

procedure TNxTimePopupControl6.DoNowButtonClick(Sender: TObject);
begin
  Close(TimeToStr(Now));
end;

/// <summary>
///  Update Hour and Minute properties based on cell
/// </summary>
procedure TNxTimePopupControl6.SetSelectedCell(Location: TPoint);
begin
  case Location.X of
    0: Hour := Location.Y;
    1: if to24HourDay in FOptions then Hour := 12 + Location.Y;
    2: if toMinutes in FOptions then Minute := Location.Y * 5;
  end;
end;

procedure TNxTimePopupControl6.InvalidateCell(Col, Row: Integer);
var
  InvalidationRect: TRect;
begin
  if InRange(Col, 0, 2) and InRange(Row, 0, 11) then
  begin
    InvalidationRect := GetCellRect(Col, Row);
    InvalidateRect(InvalidationRect);
  end;
end;

function TNxTimePopupControl6.GetAsString: string;
begin
  Result := TimeToStr(EncodeTime(Hour, Minute, 0, 0));
end;

function TNxTimePopupControl6.GetBestSize: TSize;
begin
  with Result do
  begin
    cx := ColCount * CellSize.cx;
    Inc(cx, pdStandard);
    cx := DotToPixel(cx);

    cy := 12 * CellSize.cy;
    Inc(cy, pdStandard);
    Inc(cy, 26);
    Inc(cy, 26 + pdDouble);
    cy := DotToPixel(cy);
  end;
end;

function TNxTimePopupControl6.GetCellAtPos(X, Y: Integer): TPoint;
begin
  Unset(Result);
  Result.X := (X - CellsRect.Left) div CellSize.cx;
  Result.Y := (Y - CellsRect.Top) div CellSize.cy;
end;

function TNxTimePopupControl6.GetCellCount: Integer;
begin
  { 12 Hours, 12 Minutes }
  Result := 12 * 2;
  { 12 Hours or AM/PM }
  if to24HourDay in Options then Inc(Result, 12) else Inc(Result, 2);
end;

function TNxTimePopupControl6.GetCellMinute(Row: Integer): Word;
begin
  Result := 60 div 5 * Row;
end;

function TNxTimePopupControl6.GetCellRect(Col, Row: Integer): TRect;
begin
  if InRange(Col, 0, 2) and InRange(Row, 0, 11) then
  begin
    Result := Bounds(Col * CellSize.cx, Row * CellSize.cy, CellSize.cx, CellSize.cy);
    OffsetRect(Result, CellsRect.Left, CellsRect.Top);
  end;
end;

function TNxTimePopupControl6.GetCellSize: TSize;
begin
  Result := Size(33, 21);
end;

function TNxTimePopupControl6.GetCellsRect: TRect;
begin
  Result := HeadersRect;
  OffsetRect(Result, 0, RectHeight(HeadersRect) + pdStandard);
end;

function TNxTimePopupControl6.MaxHour: Word;
begin
  Result := 12;
  if to24HourDay in Options then Result := 23;
end;

function TNxTimePopupControl6.MinHour: Word;
begin
  Result := 1;
  if to24HourDay in Options then Result := 0;
end;

procedure TNxTimePopupControl6.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    PressedCell := GetCellAtPos(X, Y);

    SetSelectedCell(PressedCell);
  end;
  inherited;
end;

procedure TNxTimePopupControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  HotCell := GetCellAtPos(X, Y);
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    if IsSet(PressedCell) then
    begin
      PressedCell := HotCell;
      SetSelectedCell(PressedCell);
    end;
  end;
  inherited;
end;

procedure TNxTimePopupControl6.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  CellPoint: TPoint;
begin
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    CellPoint := GetCellAtPos(X, Y);

    FPressedCell := Point(-1, -1);

    { Assign to TEdit control and Close }
    Close(GetAsString);


  end else inherited;
end;

procedure TNxTimePopupControl6.Paint;
begin
  inherited;
  PaintContent;
end;

procedure TNxTimePopupControl6.PaintContent;
var
  p, r: Integer;
  CellRect: TRect;
  h: Word;
  CellState: TNxButtonState;
begin
  inherited;
  PaintHeader(GetHeaderRect);

  p := 0;
  h := Hour;

  with Canvas do
  begin
    Font.Assign(Self.Font);

    CellRect := Bounds(CellsRect.Left, CellsRect.Top,
      CellSize.cx, CellSize.cy);
    CellState := [];

    { First 12 Hours }

    while p < 12 do
    begin
      CellState := [];
      if (FHotCell.X = 0) and (FHotCell.Y = p) then Include(CellState, bsHover);
      if (FPressedCell.X = 0) and (FPressedCell.Y = p) then Include(CellState, bsPressed);
      if h = p then Include(CellState, bsSelected);

      PaintCell(p, CellRect, CellState);

      OffsetRect(CellRect, 0, RectHeight(CellsRect));

      Inc(p);
    end;

    r := 0;

    { Next 24 Hours }

    if to24HourDay in Options then
    begin
      CellRect := Bounds(CellRect.Right, CellsRect.Top,
        CellSize.cx, CellSize.cy);

      while p < 24 do
      begin
        CellState := [];
        if (FHotCell.X = 1) and (FHotCell.Y = r) then Include(CellState, bsHover);
        if (FPressedCell.X = 1) and (FPressedCell.Y = r) then Include(CellState, bsPressed);
        if Hour = p then Include(CellState, bsSelected);

        PaintCell(p, CellRect, CellState);

        OffsetRect(CellRect, 0, RectHeight(CellsRect));

        Inc(p);
        Inc(r);
      end;
    end;

    { Minutes }
    p := 0;

    r := 0;

    CellRect := Bounds(CellRect.Right, CellsRect.Top,
      CellSize.cx, CellSize.cy);

    while p < 60 do
    begin
      CellState := [];
      if (HotCell.X = 2) and (HotCell.Y = r) then Include(CellState, bsHover);
      if (PressedCell.X = 2) and (PressedCell.Y = r) then Include(CellState, bsPressed);
      if Minute = p then Include(CellState, bsSelected);

      PaintCell(p, CellRect, CellState);

      OffsetRect(CellRect, 0, RectHeight(CellsRect));

      Inc(p, 5);
      Inc(r);
    end;
  end;
end;

procedure TNxTimePopupControl6.PaintHeader(HeaderRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := $00f0f0f0;
    FillRect(HeaderRect);

    Font.Style := [fsBold];
    DrawTextRect(Canvas, GetHoursRect, Classes.taCenter, taVerticalCenter, FHoursText, wkNone);
    DrawTextRect(Canvas, GetMinutesRect, Classes.taCenter, taVerticalCenter, FMinuteText, wkNone);
  end;
end;

procedure TNxTimePopupControl6.PaintCell(Value: Integer; CellRect: TRect;
  CellState: TNxButtonState);
var
  TxtRect: TRect;
  FillColor: TColor;
begin
  with Canvas do
  begin
    FillColor := Color;
    Font.Color := clWindowText;

    if bsSelected in CellState then
    begin
      FillColor := ColorOf(seMenu);
      if not(bsPressed in CellState) then Font.Color := clWhite;
    end;

    if bsPressed in CellState then
    begin
      FillColor := ColorOf(seBtnFace);
    end;

    Brush.Color := FillColor;
    FillRect(CellRect);

    if (bsHover in CellState) and not (bsPressed in CellState) then
    begin
      Pen.Color := ColorOf(seMenu);
      RoundRect(CellRect.Left, CellRect.Top, CellRect.Right, CellRect.Bottom, 2, 2);
    end;

    { Right Margin }
    TxtRect := CellRect;
    Dec(TxtRect.Right, pdDouble + 1);
    DrawTextRect(Canvas, TxtRect, taRightJustify, taVerticalCenter, IntToStr(Value), wkNone);
  end;
end;

procedure TNxTimePopupControl6.SetHotCell(const Value: TPoint);
begin
  if not PointsEqual(Value, FHotCell) then
  begin
    InvalidateCell(FHotCell.X, FHotCell.Y);
    FHotCell := Value;
    InvalidateCell(FHotCell.X, FHotCell.Y);
  end;
end;

procedure TNxTimePopupControl6.SetHour(const Value: Word);
var
  ATime: TDateTime;
begin
  if InRange(Value, MinHour, MaxHour) then
  begin
    ATime := EncodeTime(Value, Minute, 0, 0);
    Edit.Text := TimeToStr(ATime);
  end;
end;

procedure TNxTimePopupControl6.SetHoursText(const Value: string);
begin
  FHoursText := Value;
end;

procedure TNxTimePopupControl6.SetMinute(const Value: Word);
var
  ATime: TDateTime;
begin
  if (Value <> Minute) and InRange(Value, 0, 59) then
  begin
    Invalidate;
    ATime := EncodeTime(Hour, Value, 0, 0);
    Edit.Text := TimeToStr(ATime);
  end;
end;

procedure TNxTimePopupControl6.SetMinutesText(const Value: string);
begin
  FMinuteText := Value;
end;

procedure TNxTimePopupControl6.SetOptions(const Value: TNxTimeShowOptions);
begin
  FOptions := Value;
  UpdateSize;
end;

procedure TNxTimePopupControl6.SetPressedCell(const Value: TPoint);
begin
  if not PointsEqual(Value, FPressedCell) then
  begin
    InvalidateCell(FPressedCell.X, FPressedCell.Y);
    FPressedCell := Value;
    InvalidateCell(FPressedCell.X, FPressedCell.Y);
  end;
end;

procedure TNxTimePopupControl6.UpdateSize;
begin
  with GetBestSize do
  begin
    ClientWidth := cx;
    ClientHeight := cy;
  end;
end;

{ TNxColorPopupControl6 }

procedure TNxColorPopupControl6.CMMouseLeave(var Message: TMessage);
var
  AColor: TNxColorInfo;
begin
  inherited;
  Unset(AColor);
  HotColor := AColor;
end;

constructor TNxColorPopupControl6.Create(AOwner: TComponent);
begin
  inherited;
  InitColorPalette;

  { Init. Fields }
  Unset(FHotColor);

  { Init. Properties }
  Height := 166;
  Width := 172;
end;

destructor TNxColorPopupControl6.Destroy;
begin

  inherited;
end;

procedure TNxColorPopupControl6.DrawColor(Color: TColor; ColorRect: TRect;
  Selected: Boolean);
begin
  with Canvas do
  begin
    Brush.Color := Color;
    FillRect(ColorRect);
  end;
end;

procedure TNxColorPopupControl6.DrawSelection(SelectionRect: TRect);
begin
  with Canvas do
  begin
    InflateRect(SelectionRect, 1, 1);

    Brush.Color := ColorOf(seBtnFacePressed);
    FrameRect(SelectionRect);

    InflateRect(SelectionRect, -1, -1);

    Brush.Color := ColorOf(seBtnFace);
    FrameRect(SelectionRect);
  end;
end;

function TNxColorPopupControl6.GetAutomaticColor: TColor;
begin
  Result := clNone;
end;

function TNxColorPopupControl6.GetSelected: TColor;
begin
  { NxGraphics6 utility }
  Result := StrToColor(Edit.Text);
end;

function TNxColorPopupControl6.GetText: string;
begin
  Result := 'Automatic';
end;

procedure TNxColorPopupControl6.InitColorPalette;
begin
  FColors[0] := $00FFFFFF;
  FColors[1] := $00000000;
  FColors[2] := $00e1ecee;
  FColors[3] := $007d491f;
  FColors[4] := $00bd814f;
  FColors[5] := $004d50c0;
  FColors[6] := $0059bb9b;
  FColors[7] := $00a26480;
  FColors[8] := $00c6ac4b;
  FColors[9] := $004696f7;

  FStandardColors[0] := $000000c0;
  FStandardColors[1] := $000000ff;
  FStandardColors[2] := $0000ffc0;
  FStandardColors[3] := $0000ffff;
  FStandardColors[4] := $0050d092;
  FStandardColors[5] := $0050b000;
  FStandardColors[6] := $00f0b000;
  FStandardColors[7] := $00c07000;
  FStandardColors[8] := $00602000;
  FStandardColors[9] := $00a03070;
end;

procedure TNxColorPopupControl6.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;

end;

procedure TNxColorPopupControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  AColor: TNxColorInfo;
begin
  inherited;
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    HotColor := ProcColors(Point(X, Y), [poHitTest]);
  end
  else
  begin
    Unset(AColor);
    HotColor := AColor;
  end;
end;

procedure TNxColorPopupControl6.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Ref: INxColorControl;
begin
  if HotColor.Location <> cloNone then
    if Supports(Edit, INxColorControl, Ref) then
      case Ref.ColorKind of
        ckDelphi: Edit.Text := ColorToString(HotColor.Color);
        ckWeb: Edit.Text := ColorToWebColor(HotColor.Color);
      end;

  inherited;
end;

procedure TNxColorPopupControl6.Paint;
begin
  inherited;
  ProcColors(Point(0, 0), [poPaint]);
end;

function TNxColorPopupControl6.ProcColors(Location: TPoint;
  Operation: TNxProcOperation): TNxColorInfo;
var
  PaintPos: TPoint;
  H, i, j: Integer;
  ColorRect, BorderRect: TRect;
  Color: TColor;
begin
  inherited;
  Color := clBlack;

  { Default, if nothing is hit }
  Result.Color := Self.Selected;
  Result.Location := cloNone;
  Unset(Result.HitRect);

  Canvas.Font.Assign(Font);

  { Start }
  PaintPos := Point(2, 29);

  { Automatic color }

  with Canvas do
  begin
    ColorRect := Bounds(5, 5, 16, 16);

    if poPaint in Operation then
    begin
      Brush.Color := ColorOf(seDivider);
      FrameRect(ColorRect);
    end;

    InflateRect(ColorRect, -1, -1);

    if poHitTest in Operation then
    begin
      Result.HitRect := ColorRect;

      if PtInRect(Result.HitRect, Location) then
      begin
        Result.Location := cloAutomatic;
        Result.Color := AutomaticColor;

        Exit;
      end;
    end;

    if poPaint in Operation then
    begin
      DrawColor(AutomaticColor, ColorRect, False);

      Font.Color := clWindowText;
      DrawTextRect(Canvas, Bounds(33, 5, 100, 16), taLeftJustify, taVerticalCenter, Text, wkNone);

      { Divider }
      Pen.Color := ColorOf(seDivider);
      Polyline([
        Point(20, 26),
        Point(ClientWidth - 5, 26)
      ]);
    end;
  end;

  { Base palette }
  for i := Low(FColors) to High(FColors) do
  begin
    with Canvas do
    begin
      ColorRect := Bounds(PaintPos.X, PaintPos.Y, 13, 13);

      if poPaint in Operation then
      begin
        Brush.Color := ColorOf(seDivider);
        FrameRect(ColorRect);
      end;

      InflateRect(ColorRect, -1, -1);

      if poHitTest in Operation then
      begin
        Result.HitRect := ColorRect;

        if PtInRect(Result.HitRect, Location) then
        begin
          Result.Location := cloBasePalette;
          Result.Color := FColors[i];

          Exit;
        end;
      end;

//      Selected := (FHotColor.Location = cloBasePalette)
//        and (FHotColor.Color = FColors[i]);

      if poPaint in Operation
        then DrawColor(FColors[i], ColorRect, False);

      Inc(PaintPos.X, 17);
    end;
  end;

  PaintPos := Point(2, 46);

  { Shades of bases }
  for i := Low(FColors) to High(FColors) do
    with Canvas do
    begin

      BorderRect := Bounds(PaintPos.X, PaintPos.Y, 13, 13 * 3 + 12 * 2 + 2);

      if poPaint in Operation then
      begin
        Brush.Color := ColorOf(seDivider);
        FrameRect(BorderRect);
      end;

      Inc(PaintPos.Y);

      for j := 1 to 5 do
      begin

        case j of
          1, 5: H := 12;
          else H := 13;
        end;

      if ColorBrightness(FColors[i]) > ColorBrightness(DarkerColor($00FFFFFF, 20)) then
          case j of
            1: Color := DarkerColor(FColors[i], 10);
            2: Color := DarkerColor(FColors[i], 25);
            3: Color := DarkerColor(FColors[i], 50);
            4: Color := DarkerColor(FColors[i], 75);
            5: Color := DarkerColor(FColors[i], 90);
          end
       else
          case j of
            1: Color := LighterColor(FColors[i], 80);
            2: Color := LighterColor(FColors[i], 60);
            3: Color := LighterColor(FColors[i], 40);
            4: Color := DarkerColor(FColors[i], 25);
            5: Color := DarkerColor(FColors[i], 50);
          end;

        ColorRect := Bounds(PaintPos.X + 1, PaintPos.Y, 11, H);

        if poHitTest in Operation then
        begin
          Result.HitRect := ColorRect;

          if PtInRect(Result.HitRect, Location) then
          begin
            Result.Location := cloShades;
            Result.Color := Color;

            Exit;
          end;
        end;

//        Selected := (FHotColor.Location = cloShades)
//          and (FHotColor.Color = Color);

        if poPaint in Operation
          then DrawColor(Color, ColorRect, False);

        Inc(PaintPos.Y, H);
      end;

      Inc(PaintPos.X, 17);
      PaintPos.Y := 46;
    end;

  { Standard colors }

  with Canvas do
  begin

    { Title }
    if poPaint in Operation then
    begin
      Brush.Color := clBtnFace;
      FillRect(Rect(0, 113, ClientWidth, 147));

      Font.Style := [fsBold];
      TextOut(5, 126, 'Standard Colors');
    end;

    PaintPos := Point(2, 149);

    { Colors }

    for i := Low(FStandardColors) to High(FStandardColors) do
    begin
      ColorRect := Bounds(PaintPos.X, PaintPos.Y, 13, 13);

      if poPaint in Operation then
      begin
        Brush.Color := ColorOf(seDivider);

        FrameRect(ColorRect);
      end;

      InflateRect(ColorRect, -1, -1);

      if poHitTest in Operation then
      begin
        Result.HitRect := ColorRect;

        if PtInRect(Result.HitRect, Location) then
        begin
          Result.Location := cloStandard;
          Result.Color := FStandardColors[i];

          Exit;
        end;
      end;

      if poPaint in Operation
        then DrawColor(FStandardColors[i], ColorRect, False);

      { Shift to next }
      Inc(PaintPos.X, 17);
    end;
  end;

end;

procedure TNxColorPopupControl6.SetHotColor(const Value: TNxColorInfo);
var
  R: TRect;
begin
  if not EqualRect(FHotColor.HitRect, Value.HitRect)
    or (FHotColor.Location <> Value.Location) then
  begin

    if FHotColor.Location <> cloNone then
    begin
      R := FHotColor.HitRect;
      InflateRect(R, 1, 1);
      InvalidateRect(R);
    end;

    { Assign }
    FHotColor := Value;
    if FHotColor.Location <> cloNone
      then DrawSelection(FHotColor.HitRect);
  end;
end;

{ TNxIconPopupControl6 }

procedure TNxIconPopupControl6.BeforePopup;
begin
  inherited;
  FHotIcon := -1;
  FPressedIcon := -1;

  if Assigned(Picker.Images) then
    with Picker do
    begin
      ClientWidth := IconSize.cx * Min(ColCount, Picker.Images.Count);
      ClientHeight := IconSize.cy * Ceil(Images.Count / ColCount);
    end;
end;

procedure TNxIconPopupControl6.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  HotIcon := -1;
end;

function TNxIconPopupControl6.GetCount: Integer;
begin
  if Assigned(Picker.Images) then Result := Picker.Images.Count else Result := -1;
end;

function TNxIconPopupControl6.GetIconAtPos(X, Y: Integer): Integer;
var
  c, r: Integer;
begin
  Result := -1;
  if Assigned(Picker.Images) then
  begin
    c := X div IconSize.cx;
    r := Y div IconSize.cy;

    Result := c + r * Picker.ColCount;
  end;
end;

function TNxIconPopupControl6.GetIconSize: TSize;
begin
  Result := Size(Picker.Images.Width + pdDouble * 2, Picker.Images.Height + pdDouble * 2);
end;

function TNxIconPopupControl6.GetIconRect(const Index: Integer): TRect;
var
  c, r: Integer;
begin
  Result := Bounds(0, 0, IconSize.cx, IconSize.cy);
  r := Index div Picker.ColCount;
  c := Index - r * Picker.ColCount;
  OffsetRect(Result, c * IconSize.cx, r * IconSize.cy);
end;

function TNxIconPopupControl6.GetPicker: INxIconPicker;
var
  Ref: INxIconPicker;
begin
  if Supports(Edit, INxIconPicker, Ref) then
  begin
    Result := Ref;
  end
  else Result := nil;
end;

procedure TNxIconPopupControl6.InvalidateIcon(const Index: Integer);
begin
  if InRange(Index, 0, Pred(Picker.Images.Count))
    then InvalidateRect(GetIconRect(Index));
end;

procedure TNxIconPopupControl6.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  PressedIcon := GetIconAtPos(X, Y);
  inherited;
end;

procedure TNxIconPopupControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(ClientRect, Point(X, Y)) then
  begin
    HotIcon := GetIconAtPos(X, Y);
  end
  else HotIcon := -1;
end;

procedure TNxIconPopupControl6.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  if (GetIconAtPos(X, Y) = PressedIcon)
    and InRange(PressedIcon, 0, Pred(Count)) then
  begin
    Picker.ItemIndex := PressedIcon;

    { Event }
    DropDown.DoSelect;
  end;
  PressedIcon := -1;

  inherited;
end;

procedure TNxIconPopupControl6.Paint;
var
  i, c: Integer;
  Position: TPoint;
  IconRect: TRect;
  State: TNxButtonState;
begin
  inherited;

  if Picker.Images = nil then Exit;

  Position := Point(0, 0);
  c := 0;

  with Picker do
    for i := 0 to Pred(Images.Count) do
    begin
      IconRect := Bounds(Position.X, Position.Y, IconSize.cx, IconSize.cy);

      State := [];
      if i = FHotIcon then Include(State, bsHover);
      if i = FPressedIcon then Include(State, bsPressed);
      if i = Picker.ItemIndex then Include(State, bsChecked);

      PaintIcon(i, IconRect, State);

      OffsetPoint(Position, IconSize.cx, 0);
      Inc(c);

      if c > Pred(ColCount) then
      begin
        c := 0;
        Position.X := 0;
        Inc(Position.Y, IconSize.cy);
      end;

    end;
end;

procedure TNxIconPopupControl6.PaintIcon(const Index: Integer; IconRect: TRect;
  State: TNxButtonState);
var
  BackColor: TColor;
begin
  BackColor := Color;

  if bsChecked in State then BackColor := ColorOf(seBtnFaceChecked);
  if bsHover in State then
  begin
    BackColor := ColorOf(seBtnFace);
    if bsPressed in State then BackColor := ColorOf(seBtnFacePressed);
  end;

  Canvas.Brush.Color := BackColor;
  Canvas.FillRect(IconRect);

  Picker.Images.Draw(Canvas, IconRect.Left + pdDouble, IconRect.Top + pdDouble, Index);
end;

procedure TNxIconPopupControl6.SetHotIcon(const Value: Integer);
var
  Old: Integer;
begin
  if Value <> FHotIcon then
  begin
    Old := FHotIcon;
    FHotIcon := Value;
    InvalidateIcon(Old);
    InvalidateIcon(FHotIcon);
  end;
end;

procedure TNxIconPopupControl6.SetPressedIcon(const Value: Integer);
begin
  FPressedIcon := Value;
  Invalidate;
end;

procedure TNxIconPopupControl6.UpdatePopup;
begin
  inherited;
  Repaint;
end;

{ TNxFilterPopupControl6 }

constructor TNxFilterPopupControl6.Create(AOwner: TComponent);
begin
  inherited;

  FFilter := EmptyStr;
  Width := 160;
  Height := 120;

//  Parent := TWinControl(Owner);

  FButton := TNxGraphicButton.Create(Self);
  FButton.SetBounds(10,10,100,20);
  FButton.Parent := Self;

  FFilterEdit := TEdit.Create(Self);
  FFilterEdit.SetBounds(8, 64, 100, 21);
  FFilterEdit.Parent := Self;

//  Parent := nil;

//  InsertControl(FFilterEdit);

end;

procedure TNxFilterPopupControl6.CreateWnd;
begin
  inherited;
  Repaint;
  Refresh;
end;

procedure TNxFilterPopupControl6.DoChange(Sender: TObject);
begin
  if Assigned(FOnChange) then FOnChange(Sender);
end;

procedure TNxFilterPopupControl6.Popup(const X, Y: Integer;
  Anchor: TNxPopupAnchor);
begin
  inherited;
//  FFilterEdit := TEdit.Create(Self);
//  FFilterEdit.SetBounds(8, 24, 100, 21);
//  FFilterEdit.OnChange := DoChange;
//  FFilterEdit.Visible := True;
//  FFilterEdit.Parent := Self;
//  FFilterEdit.Refresh;
  SetForegroundWindow(Handle);
SetFocus;
  FFilterEdit.SetFocus;
end;

procedure TNxFilterPopupControl6.SetFilter(const Value: WideString);
begin
  FFilter := Value;
end;

{ TNxPreviewPopupControl }

procedure TNxPreviewPopupControl.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  DoHide;
end;

procedure TNxPreviewPopupControl.CMRelease(var Msg: TMessage);
begin
  Free;
end;

constructor TNxPreviewPopupControl.Create(AOwner: TComponent);
begin
  inherited;
  ShowShadow := True;
end;

procedure TNxPreviewPopupControl.DoHide;
begin
  ReleaseCapture;
  if Assigned(FOnHide) then FOnHide(Self);
  PostMessage(Handle, CM_RELEASE, 0, 0);
end;

procedure TNxPreviewPopupControl.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if not PtInRect(ClientRect, Point(X, Y)) then
  begin
    DoHide;
  end;
end;

{ TNxGridPickerColumn }

constructor TNxGridPickerColumn.Create(Collection: TCollection);
begin
  inherited;
  FColor := clWindow;
  FWidth := 60;
end;

{ TNxGridPickerColumns }

function TNxGridPickerColumns.Add: TNxGridPickerColumn;
begin
  Result := TNxGridPickerColumn(inherited Add);
end;

constructor TNxGridPickerColumns.Create(AOwner: TComponent);
begin
  inherited Create(TNxGridPickerColumn);
end;

function TNxGridPickerColumns.GetItem(Index: Integer): TNxGridPickerColumn;
begin
  Result := TNxGridPickerColumn(inherited GetItem(Index));
end;

procedure TNxGridPickerColumns.SetItem(Index: Integer; const Value: TNxGridPickerColumn);
begin
  inherited SetItem(Index, Value);
end;

{ TNxListRow6 }

procedure TNxListRow6.AddCell(const Value: WideString);
begin
  FCells.Add(Value);
end;

constructor TNxListRow6.Create;
begin
  FCells := TStringList.Create;
end;

destructor TNxListRow6.Destroy;
begin
  FreeAndNil(FCells);
  inherited;
end;

function TNxListRow6.GetCells(const Index: Integer): WideString;
begin
  Result := FCells[Index];
end;

function TNxListRow6.GetCount: Integer;
begin
  Result := FCells.Count
end;

{ TNxDictionaryPopupControl }

procedure TNxGridPopupControl.AfterPopup;
begin
  UpdateVertScrollBar;
end;

procedure TNxGridPopupControl.BeforePopup;

  function GetFitSize: Integer;
  var
    i: Integer;
  begin
    Result := GetSystemMetrics(SM_CXVSCROLL);
    for i := 0 to Pred(FPicker.ColCount) do
    begin
      Inc(Result, FPicker.Column[i].Width);
    end;
  end;
begin
  Width := FPicker.ListWidth;

  if Width = 0 then Width := GetFitSize;

  with FPicker do
  begin
    if RowCount > 0 then
    begin
      ClientHeight := HeaderHeight + RowHeight * Min(DropDownCount, RowCount);
      UpdateVertScrollBar;

      VertScrollBar.Position := Succ(FPicker.SelectedIndex - DropDownCount);
      HotIndex := FPicker.SelectedIndex;
    end
    else ClientHeight := FPicker.HeaderHeight;

  end;

end;

constructor TNxGridPopupControl.Create(AOwner: TComponent);
begin
  inherited;
  Assert(Supports(AOwner, INxGridPicker, FPicker), 'INxDictionaryDataSource expected.');

  FHotIndex := -1;

  { Initialize }
  ScrollBars := [sbVertical];
  Width := 200;
  Height := 200;

  VertScrollBar.Position := 0;
  VertScrollBar.Max := 100;
end;

function TNxGridPopupControl.GetCells(const ACol, ARow: Integer): WideString;
begin
  Result := FPicker.GetRow(ARow).FCells[ACol];
end;

function TNxGridPopupControl.GetDataRect: TRect;
var
  i: Integer;
begin
  Result := ClientRect;
  Inc(Result.Top, FPicker.HeaderHeight);
  Result.Right := 0;
  for i := 0 to Pred(FPicker.GetColCount) do Inc(Result.Right, FPicker.Column[i].Width);
end;

function TNxGridPopupControl.GetHeaderRect: TRect;
begin
  Result := ClientRect;
  Result.Bottom := Result.Top + FPicker.HeaderHeight;
end;

function TNxGridPopupControl.GetIndexAtPos(X, Y: Integer): Integer;
begin
  Result := -1;
  if PtInRect(DataRect, Point(X, Y)) then
  begin
    Result := VertScrollBar.Position + ((Y - FPicker.HeaderHeight) div FPicker.RowHeight);
  end;
end;

function TNxGridPopupControl.GetPageRowCount: Integer;
begin
  Result := Min(FPicker.DropDownCount, FPicker.RowCount);
end;

function TNxGridPopupControl.GetSelectedIndex: Integer;
begin
  Result := FPicker.SelectedIndex;
end;

procedure TNxGridPopupControl.KeyDown(var Key: Word; Shift: TShiftState);
var
  Index: Integer;
begin
  inherited;
  case Key of
    VK_NEXT:
    begin
      if SelectedIndex < VertScrollBar.Position + Pred(PageRowCount)
        then Index := VertScrollBar.Position + Pred(PageRowCount)
        else Index := SelectedIndex + PageRowCount;

      SelectedIndex := Min(Index, Pred(FPicker.RowCount));
    end;
    VK_PRIOR:
    begin
      if SelectedIndex > VertScrollBar.Position
        then Index := VertScrollBar.Position
        else Index := SelectedIndex - PageRowCount;

      SelectedIndex := Max(Index, 0);
    end;
  end;

end;

procedure TNxGridPopupControl.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(DataRect, Point(X, Y)) then
  begin
    HotIndex := GetIndexAtPos(X, Y);
  end;
end;

procedure TNxGridPopupControl.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
  Value: WideString;
begin
  Index := GetIndexAtPos(X, Y);
  if InRange(Index, 0, Pred(FPicker.RowCount)) then
  begin
    Value := Cells[0, Index];

    FPicker.SelectedIndex := Index;

    { Event }
    FPicker.DoSetValue(Index, Value);

    { Event }
    DropDown.DoSelect;

    inherited;
  end;
end;

procedure TNxGridPopupControl.Paint;
var
  i, j, X, Y: Integer;
  CellRect, RowRect: TRect;
  Column: TNxGridPickerColumn;
begin
  inherited;
  Canvas.Font.Assign(Font);
  PaintHeaders;
  X := 0;
  Y := GetHeaderRect.Bottom;
  for i := VertScrollBar.Position to Pred(FPicker.RowCount) do
  begin
    RowRect := Bounds(0, Y, DataRect.Right, FPicker.RowHeight);

    for j := 0 to FPicker.GetRow(i).Count - 1 do
    begin
      Column := FPicker.Column[j];

    if i = FHotIndex then
    begin
      Canvas.Brush.Color := clHighlight;
      Canvas.Font.Color := clHighlightText;
    end else
    begin
      Canvas.Brush.Color := Column.Color;
      Canvas.Font.Color := clWindowText;
    end;

      CellRect := Bounds(X, Y, Column.Width, FPicker.RowHeight);

      Canvas.FillRect(CellRect);

      PaintCell(Cells[j, i], CellRect);
      Inc(X, Column.Width);
    end;
    Inc(Y, FPicker.RowHeight);
    X := 0;
  end;
end;

procedure TNxGridPopupControl.PaintCell(Value: WideString; CellRect: TRect);
var
  TextRect: TRect;
begin
  TextRect := CellRect;
  Inc(TextRect.Left, pdStandard);
  DrawTextRect(Canvas, TextRect, taLeftJustify, taVerticalCenter, Value, wkEllipsis);
end;

procedure TNxGridPopupControl.PaintHeaders;
var
  i, X: Integer;
  HeadRect, TextRect: TRect;
  Column: TNxGridPickerColumn;
begin
  X := 0;
  for i := 0 to Pred(FPicker.GetColCount) do
  begin
    Column := FPicker.Column[i];

    HeadRect := Bounds(X, 0, Column.Width, HeaderRect.Bottom);
    TNxHeaderStyle6.Paint(Canvas, Handle, HeadRect, [], [soNativeStyles, soVCLStyles]);

    { Caption }
    TextRect := HeadRect;
    InflateRect(TextRect, -pdStandard, 0);
    DrawTextRect(Canvas, TextRect, taLeftJustify, taVerticalCenter, Column.Caption, wkEllipsis);

    Inc(X, Column.Width);
  end;
end;

procedure TNxGridPopupControl.ScrollContentBy(DeltaX, DeltaY: Integer);
begin
  ScrollRect(0, -FPicker.RowHeight * DeltaY, DataRect, DataRect);
end;

procedure TNxGridPopupControl.ScrollRect(DeltaX, DeltaY: Integer; Rect, ClipRect: TRect);
begin
{$IFDEF UNSAFE}
  ScrollWindowEx(Handle, DeltaX, DeltaY, @Rect, @ClipRect, 0, nil, SW_INVALIDATE);
{$ELSE}
  ScrollWindowEx(Handle, DeltaX, DeltaY, Rect, ClipRect, 0, nil, SW_INVALIDATE);
{$ENDIF}
end;

procedure TNxGridPopupControl.SetHotIndex(const Value: Integer);
begin
  if Value <> FHotIndex then
  begin
    FHotIndex := Value;
    Invalidate;
  end;
end;

procedure TNxGridPopupControl.SetSelectedIndex(const Value: Integer);
begin
  FPicker.SelectedIndex := Value;
end;

procedure TNxGridPopupControl.UpdateVertScrollBar;
begin
  VertScrollBar.Max := Pred(FPicker.RowCount);
  VertScrollBar.PageSize := GetPageRowCount;
end;

end.
