struct DropTarget : wxDropTarget
{
    DropTarget(wxDataObject *data) : wxDropTarget(data) {};

    wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def)
    {
        sys->GetSW()->SelectClick(x, y, false);
        return /*sys->selected.g ? wxDragCopy : */wxDragNone;
    }

    bool OnDrop(wxCoord x, wxCoord y)
    {
        return false; //sys->selected.g!=NULL;
    }

    wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
    {
        GetData();
        sys->PasteOrDrop();
        return wxDragCopy;
    }
};

struct CTransparentStaticText : public wxStaticText
{
    DECLARE_DYNAMIC_CLASS (CTransparentStaticText)
    DECLARE_EVENT_TABLE()

public:
    CTransparentStaticText() {};
    virtual bool HasTransparentBackground() { return true; };

    CTransparentStaticText(wxWindow* parent, wxWindowID id, const wxString& label)
    {
        wxStaticText::Create(parent, id, label, wxDefaultPosition, wxDefaultSize, wxTRANSPARENT_WINDOW);
        SetBackgroundColour(parent->GetBackgroundColour());
        SetBackgroundStyle(wxBG_STYLE_COLOUR);
        SetForegroundColour(parent->GetForegroundColour());
        sys->frame->refreshhackinstances++;
    }

    void OnPaint(wxPaintEvent&)
    {
        //sys->frame->tb->ClearBackground();
        wxPaintDC dc(this);
        //dc.Clear();
        dc.SetFont(GetFont());
        dc.DrawText(GetLabel(), 0, 0);

        #ifdef __WXMSW__
            if(++sys->frame->refreshhack>=sys->frame->refreshhackinstances*2)    // FIXME: TERRIBLE HACK: does not draw transparency correctly because BG is not refreshed otherwise
            {
                sys->frame->tb->Refresh();
                sys->frame->refreshhack = 0;
            }
        #endif
    }
};

struct BlinkTimer : wxTimer
{
    void Notify() { sys->Blink(); }
};

struct ThreeChoiceDialog : public wxDialog
{
    ThreeChoiceDialog(wxWindow *parent, const wxString &title, const wxString &msg, const wxString &ch1, const wxString &ch2, const wxString &ch3) : wxDialog(parent, wxID_ANY, title)
    {
        wxBoxSizer *bsv = new wxBoxSizer(wxVERTICAL);
        bsv->Add(new wxStaticText(this, -1, msg), 0, wxALL, 5);
        wxBoxSizer *bsb = new wxBoxSizer(wxHORIZONTAL);
        bsb->Prepend(new wxButton(this, 2, ch3), 0, wxALL, 5);
        bsb->PrependStretchSpacer(1);
        bsb->Prepend(new wxButton(this, 1, ch2), 0, wxALL, 5);
        bsb->PrependStretchSpacer(1);
        bsb->Prepend(new wxButton(this, 0, ch1), 0, wxALL, 5);
        bsv->Add(bsb, 1, wxEXPAND);
        SetSizer(bsv);
        bsv->SetSizeHints(this);
    }

    void OnButton(wxCommandEvent& ce)
    {
        EndModal(ce.GetId());
    }

    int Run()
    {
        return ShowModal();
    }

    DECLARE_EVENT_TABLE()
};


struct ColorPopup : wxVListBoxComboPopup
{
    void OnComboDoubleClick()
    {
        //sys->ColorChange(m_combo->GetId()==A_TEXTCOLOR, GetSelection());
    }
};

struct ColorDropdown : wxOwnerDrawnComboBox
{
    ColorDropdown(wxWindow *parent, wxWindowID id, int sel = 0)
    {
        wxArrayString as;
        as.Add(L"", sizeof(celltextcolors)/sizeof(uint));
        Create(parent, id, L"", wxDefaultPosition, wxSize(60, 20), as, wxCB_READONLY|wxCC_SPECIAL_DCLICK);
        SetPopupControl(new ColorPopup());
        SetSelection(sel);
        SetPopupMaxHeight(1000);
    }

    wxCoord OnMeasureItem     (size_t item) const { return 20; }
    wxCoord OnMeasureItemWidth(size_t item) const { return 40; }

    void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const
    {
        DrawRectangle(dc, item==CUSTOMCOLORIDX ? 0x00000000 : celltextcolors[item], rect.x+1, rect.y+1, rect.width-2, rect.height-2);
        if(item==CUSTOMCOLORIDX)
        {
            sys->ResetFont();
            sys->PickFont(dc, -2, 0);
            dc.DrawText(L"Custom", rect.x+1, rect.y+1);
        }
    }
};

