~ubuntu-branches/ubuntu/lucid/codelite/lucid

« back to all changes in this revision

Viewing changes to sdk/wxpropgrid/src/editors.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2009-02-10 02:27:55 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090210022755-m5692nfc1t5uf1w9
Tags: 1.0.2759+dfsg-0ubuntu1
* New upstream release (LP: #327216).
* debian/patches/series, debian/patches/00_fix-ia64-build.patch:
  + Dropped, applied upstream already.
* debian/patches/02_fix-desktop.patch,
  debian/patches/03_fix-sh.patch:
  + Refreshed to patch cleanly.
* debian/rules:
  + Make get-orig-source honour UPSTREAM_VERSION if set.
* debian/ctags-le.1,
  debian/codelite_indexer.1,
  debian/codelite.manpages:
  + Dropped ctags-le manpage, since ctags-le was replaced by
    codelite_indexer.
  + Added codelite_indexer manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        editors.cpp
 
3
// Purpose:     wxPropertyGrid editors
 
4
// Author:      Jaakko Salli
 
5
// Modified by:
 
6
// Created:     Apr-14-2007
 
7
// RCS-ID:      $Id:
 
8
// Copyright:   (c) Jaakko Salli
 
9
// Licence:     wxWindows license
 
10
/////////////////////////////////////////////////////////////////////////////
 
11
 
 
12
// For compilers that support precompilation, includes "wx/wx.h".
 
13
#include "wx/wxprec.h"
 
14
 
 
15
#ifdef __BORLANDC__
 
16
    #pragma hdrstop
 
17
#endif
 
18
 
 
19
#ifndef WX_PRECOMP
 
20
    #include "wx/defs.h"
 
21
    #include "wx/object.h"
 
22
    #include "wx/hash.h"
 
23
    #include "wx/string.h"
 
24
    #include "wx/log.h"
 
25
    #include "wx/event.h"
 
26
    #include "wx/window.h"
 
27
    #include "wx/panel.h"
 
28
    #include "wx/dc.h"
 
29
    #include "wx/dcclient.h"
 
30
    #include "wx/dcmemory.h"
 
31
    #include "wx/button.h"
 
32
    #include "wx/pen.h"
 
33
    #include "wx/brush.h"
 
34
    #include "wx/cursor.h"
 
35
    #include "wx/dialog.h"
 
36
    #include "wx/settings.h"
 
37
    #include "wx/msgdlg.h"
 
38
    #include "wx/choice.h"
 
39
    #include "wx/stattext.h"
 
40
    #include "wx/scrolwin.h"
 
41
    #include "wx/dirdlg.h"
 
42
    #include "wx/layout.h"
 
43
    #include "wx/sizer.h"
 
44
    #include "wx/textdlg.h"
 
45
    #include "wx/filedlg.h"
 
46
    #include "wx/statusbr.h"
 
47
    #include "wx/intl.h"
 
48
    #include "wx/frame.h"
 
49
#endif
 
50
 
 
51
 
 
52
#include "wx/timer.h"
 
53
#include "wx/dcbuffer.h"
 
54
#include "wx/bmpbuttn.h"
 
55
 
 
56
 
 
57
// This define is necessary to prevent macro clearing
 
58
#define __wxPG_SOURCE_FILE__
 
59
 
 
60
#include <wx/propgrid/propgrid.h>
 
61
#include <wx/propgrid/propdev.h>
 
62
#include <wx/propgrid/editors.h>
 
63
#include <wx/propgrid/props.h>
 
64
 
 
65
#ifdef __WXPYTHON__
 
66
    #include <wx/propgrid/advprops.h>
 
67
    #include <wx/propgrid/extras.h>
 
68
#endif
 
69
 
 
70
#if wxPG_USE_RENDERER_NATIVE
 
71
    #include <wx/renderer.h>
 
72
#endif
 
73
 
 
74
// How many pixels between textctrl and button
 
75
#ifdef __WXMAC__
 
76
    #define wxPG_TEXTCTRL_AND_BUTTON_SPACING        8
 
77
#else
 
78
    #define wxPG_TEXTCTRL_AND_BUTTON_SPACING        2
 
79
#endif 
 
80
 
 
81
#define wxPG_BUTTON_SIZEDEC                         0
 
82
 
 
83
#if wxPG_USING_WXOWNERDRAWNCOMBOBOX
 
84
    #include <wx/odcombo.h>
 
85
#else
 
86
    #include <wx/propgrid/odcombo.h>
 
87
#endif
 
88
 
 
89
#ifdef __WXMSW__
 
90
    #include <wx/msw/private.h>
 
91
#endif
 
92
 
 
93
// -----------------------------------------------------------------------
 
94
 
 
95
#if defined(__WXMSW__)
 
96
    // tested
 
97
    #define wxPG_NAT_TEXTCTRL_BORDER_X          0 // Unremovable border of native textctrl.
 
98
    #define wxPG_NAT_TEXTCTRL_BORDER_Y          0 // Unremovable border of native textctrl.
 
99
 
 
100
    #define wxPG_NAT_BUTTON_BORDER_ANY          1
 
101
    #define wxPG_NAT_BUTTON_BORDER_X            1
 
102
    #define wxPG_NAT_BUTTON_BORDER_Y            1
 
103
 
 
104
    #define wxPG_CHECKMARK_XADJ                 1
 
105
    #define wxPG_CHECKMARK_YADJ                 (-1)
 
106
    #define wxPG_CHECKMARK_WADJ                 0
 
107
    #define wxPG_CHECKMARK_HADJ                 0
 
108
    #define wxPG_CHECKMARK_DEFLATE              0
 
109
 
 
110
    #define wxPG_TEXTCTRLYADJUST                (m_spacingy+0)
 
111
 
 
112
#elif defined(__WXGTK__)
 
113
    // tested
 
114
    #define wxPG_CHECKMARK_XADJ                 0
 
115
    #define wxPG_CHECKMARK_YADJ                 0
 
116
    #define wxPG_CHECKMARK_WADJ                 (-1)
 
117
    #define wxPG_CHECKMARK_HADJ                 (-1)
 
118
    #define wxPG_CHECKMARK_DEFLATE              3
 
119
 
 
120
    #define wxPG_NAT_TEXTCTRL_BORDER_X      3 // Unremovable border of native textctrl.
 
121
    #define wxPG_NAT_TEXTCTRL_BORDER_Y      3 // Unremovable border of native textctrl.
 
122
 
 
123
    #define wxPG_NAT_BUTTON_BORDER_ANY      1
 
124
    #define wxPG_NAT_BUTTON_BORDER_X        1
 
125
    #define wxPG_NAT_BUTTON_BORDER_Y        1
 
126
 
 
127
    #define wxPG_TEXTCTRLYADJUST            0
 
128
 
 
129
#elif defined(__WXMAC__)
 
130
    // *not* tested
 
131
    #define wxPG_CHECKMARK_XADJ                 0
 
132
    #define wxPG_CHECKMARK_YADJ                 0
 
133
    #define wxPG_CHECKMARK_WADJ                 0
 
134
    #define wxPG_CHECKMARK_HADJ                 0
 
135
    #define wxPG_CHECKMARK_DEFLATE              0
 
136
 
 
137
    #define wxPG_NAT_TEXTCTRL_BORDER_X      0 // Unremovable border of native textctrl.
 
138
    #define wxPG_NAT_TEXTCTRL_BORDER_Y      0 // Unremovable border of native textctrl.
 
139
 
 
140
    #define wxPG_NAT_BUTTON_BORDER_ANY      0
 
141
    #define wxPG_NAT_BUTTON_BORDER_X        0
 
142
    #define wxPG_NAT_BUTTON_BORDER_Y        0
 
143
 
 
144
    #define wxPG_TEXTCTRLYADJUST            3
 
145
 
 
146
#else
 
147
    // defaults
 
148
    #define wxPG_CHECKMARK_XADJ                 0
 
149
    #define wxPG_CHECKMARK_YADJ                 0
 
150
    #define wxPG_CHECKMARK_WADJ                 0
 
151
    #define wxPG_CHECKMARK_HADJ                 0
 
152
    #define wxPG_CHECKMARK_DEFLATE              0
 
153
 
 
154
    #define wxPG_NAT_TEXTCTRL_BORDER_X      0 // Unremovable border of native textctrl.
 
155
    #define wxPG_NAT_TEXTCTRL_BORDER_Y      0 // Unremovable border of native textctrl.
 
156
 
 
157
    #define wxPG_NAT_BUTTON_BORDER_ANY      0
 
158
    #define wxPG_NAT_BUTTON_BORDER_X        0
 
159
    #define wxPG_NAT_BUTTON_BORDER_Y        0
 
160
 
 
161
    #define wxPG_TEXTCTRLYADJUST            0
 
162
 
 
163
#endif
 
164
 
 
165
#if (!wxPG_NAT_TEXTCTRL_BORDER_X && !wxPG_NAT_TEXTCTRL_BORDER_Y)
 
166
    #define wxPG_ENABLE_CLIPPER_WINDOW      0
 
167
#else
 
168
    #define wxPG_ENABLE_CLIPPER_WINDOW      1
 
169
#endif
 
170
 
 
171
 
 
172
// for odcombo
 
173
#define wxPG_CHOICEXADJUST           0
 
174
#define wxPG_CHOICEYADJUST           0
 
175
 
 
176
#define ODCB_CUST_PAINT_MARGIN               6  // Number added to image width for SetCustomPaintWidth
 
177
 
 
178
// Milliseconds to wait for two mouse-ups after focus inorder
 
179
// to trigger a double-click.
 
180
#define DOUBLE_CLICK_CONVERSION_TRESHOLD        500
 
181
 
 
182
// -----------------------------------------------------------------------
 
183
// wxPGEditor
 
184
// -----------------------------------------------------------------------
 
185
 
 
186
IMPLEMENT_ABSTRACT_CLASS(wxPGEditor, wxObject)
 
187
 
 
188
wxPGEditor::~wxPGEditor()
 
189
{
 
190
}
 
191
 
 
192
 
 
193
/*wxPGCellRenderer* wxPGEditor::GetCellRenderer() const
 
194
{
 
195
    return &g_wxPGDefaultRenderer;
 
196
}*/
 
197
 
 
198
void wxPGEditor::DrawValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& text ) const
 
199
{
 
200
    if ( !property->IsValueUnspecified() )
 
201
        dc.DrawText( text, rect.x+wxPG_XBEFORETEXT, rect.y );
 
202
}
 
203
 
 
204
#ifdef __WXPYTHON__
 
205
bool wxPGEditor::GetValueFromControl( wxVariant&, wxPGProperty*, wxWindow* ) const
 
206
{
 
207
    return false;
 
208
}
 
209
 
 
210
wxPGVariantAndBool wxPGEditor::PyGetValueFromControl( wxPGProperty* property, wxWindow* ctrl ) const
 
211
{
 
212
    wxPGVariantAndBool vab;
 
213
    vab.m_result = GetValueFromControl(vab.m_value, property, ctrl);
 
214
    if ( vab.m_result )
 
215
        vab.m_valueValid = true;
 
216
    return vab;
 
217
}
 
218
#endif
 
219
 
 
220
void wxPGEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow*, const wxString& ) const
 
221
{
 
222
}
 
223
 
 
224
 
 
225
void wxPGEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow*, int ) const
 
226
{
 
227
}
 
228
 
 
229
 
 
230
int wxPGEditor::InsertItem( wxWindow*, const wxString&, int ) const
 
231
{
 
232
    return -1;
 
233
}
 
234
 
 
235
 
 
236
void wxPGEditor::DeleteItem( wxWindow*, int ) const
 
237
{
 
238
    return;
 
239
}
 
240
 
 
241
 
 
242
void wxPGEditor::OnFocus( wxPGProperty*, wxWindow* ) const
 
243
{
 
244
}
 
245
 
 
246
 
 
247
bool wxPGEditor::CanContainCustomImage() const
 
248
{
 
249
    return false;
 
250
}
 
251
 
 
252
// -----------------------------------------------------------------------
 
253
// wxPGClipperWindow
 
254
// -----------------------------------------------------------------------
 
255
 
 
256
 
 
257
#if wxPG_ENABLE_CLIPPER_WINDOW
 
258
 
 
259
//
 
260
// Clipper window is used to "remove" borders from controls
 
261
// which otherwise insist on having them despite of supplied
 
262
// wxNO_BORDER window style.
 
263
//
 
264
class wxPGClipperWindow : public wxWindow
 
265
{
 
266
    DECLARE_CLASS(wxPGClipperWindow)
 
267
public:
 
268
 
 
269
    wxPGClipperWindow()
 
270
        : wxWindow()
 
271
    {
 
272
        wxPGClipperWindow::Init();
 
273
    }
 
274
 
 
275
    wxPGClipperWindow(wxWindow* parent,
 
276
                      wxWindowID id,
 
277
                      const wxPoint& pos = wxDefaultPosition,
 
278
                      const wxSize& size = wxDefaultSize)
 
279
    {
 
280
        Init();
 
281
        Create(parent,id,pos,size);
 
282
    }
 
283
 
 
284
    void Create(wxWindow* parent,
 
285
                wxWindowID id,
 
286
                const wxPoint& pos = wxDefaultPosition,
 
287
                const wxSize& size = wxDefaultSize);
 
288
 
 
289
    virtual ~wxPGClipperWindow();
 
290
 
 
291
    virtual bool ProcessEvent(wxEvent& event);
 
292
 
 
293
    inline wxWindow* GetControl() const { return m_ctrl; }
 
294
 
 
295
    // This is called before wxControl is constructed.
 
296
    void GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz );
 
297
 
 
298
    // This is caleed after wxControl has been constructed.
 
299
    void SetControl( wxWindow* ctrl );
 
300
 
 
301
    virtual void Refresh( bool eraseBackground = true,
 
302
                          const wxRect *rect = (const wxRect *) NULL );
 
303
    virtual void SetFocus();
 
304
 
 
305
    virtual bool SetFont(const wxFont& font);
 
306
 
 
307
    inline int GetXClip() const { return m_xadj; }
 
308
 
 
309
    inline int GetYClip() const { return m_yadj; }
 
310
 
 
311
protected:
 
312
    wxWindow*       m_ctrl;
 
313
 
 
314
    int             m_xadj; // Horizontal border clip.
 
315
 
 
316
    int             m_yadj; // Vertical border clip.
 
317
 
 
318
private:
 
319
    void Init ()
 
320
    {
 
321
        m_ctrl = (wxWindow*) NULL;
 
322
    }
 
323
};
 
324
 
 
325
 
 
326
IMPLEMENT_CLASS(wxPGClipperWindow,wxWindow)
 
327
 
 
328
 
 
329
// This is called before wxControl is constructed.
 
330
void wxPGClipperWindow::GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz )
 
331
{
 
332
    m_xadj = xadj;
 
333
    m_yadj = yadj;
 
334
    pt.x = -xadj;
 
335
    pt.y = -yadj;
 
336
    wxSize own_size = GetSize();
 
337
    sz.x = own_size.x+(xadj*2);
 
338
    sz.y = own_size.y+(yadj*2);
 
339
}
 
340
 
 
341
 
 
342
// This is caleed after wxControl has been constructed.
 
343
void wxPGClipperWindow::SetControl( wxWindow* ctrl )
 
344
{
 
345
    m_ctrl = ctrl;
 
346
 
 
347
    // GTK requires this.
 
348
    ctrl->SetSizeHints(3,3);
 
349
 
 
350
    // Correct size of this window to match the child.
 
351
    wxSize sz = GetSize();
 
352
    wxSize chsz = ctrl->GetSize();
 
353
 
 
354
    int hei_adj = chsz.y - (sz.y+(m_yadj*2));
 
355
    if ( hei_adj )
 
356
        SetSize(sz.x,chsz.y-(m_yadj*2));
 
357
 
 
358
}
 
359
 
 
360
 
 
361
void wxPGClipperWindow::Refresh( bool eraseBackground, const wxRect *rect )
 
362
{
 
363
    wxWindow::Refresh(false,rect);
 
364
    if ( m_ctrl )
 
365
        m_ctrl->Refresh(eraseBackground);
 
366
}
 
367
 
 
368
 
 
369
// Pass focus to control
 
370
void wxPGClipperWindow::SetFocus()
 
371
{
 
372
    if ( m_ctrl )
 
373
        m_ctrl->SetFocus();
 
374
    else
 
375
        wxWindow::SetFocus();
 
376
}
 
377
 
 
378
 
 
379
bool wxPGClipperWindow::SetFont(const wxFont& font)
 
380
{
 
381
    bool res = wxWindow::SetFont(font);
 
382
    if ( m_ctrl )
 
383
        return m_ctrl->SetFont(font);
 
384
    return res;
 
385
}
 
386
 
 
387
 
 
388
void wxPGClipperWindow::Create(wxWindow* parent,
 
389
                               wxWindowID id,
 
390
                               const wxPoint& pos,
 
391
                               const wxSize& size )
 
392
{
 
393
    wxWindow::Create(parent,id,pos,size);
 
394
}
 
395
 
 
396
 
 
397
wxPGClipperWindow::~wxPGClipperWindow()
 
398
{
 
399
}
 
400
 
 
401
 
 
402
bool wxPGClipperWindow::ProcessEvent(wxEvent& event)
 
403
{
 
404
    if ( event.GetEventType() == wxEVT_SIZE )
 
405
    {
 
406
        if ( m_ctrl )
 
407
        {
 
408
            // Maintain correct size relationship.
 
409
            wxSize sz = GetSize();
 
410
            m_ctrl->SetSize(sz.x+(m_xadj*2),sz.y+(m_yadj*2));
 
411
            event.Skip();
 
412
            return false;
 
413
        }
 
414
    }
 
415
    return wxWindow::ProcessEvent(event);
 
416
}
 
417
 
 
418
#endif // wxPG_ENABLE_CLIPPER_WINDOW
 
419
 
 
420
/*wxWindow* wxPropertyGrid::GetActualEditorControl( wxWindow* ctrl )
 
421
{
 
422
#if wxPG_ENABLE_CLIPPER_WINDOW
 
423
    // Pass real control instead of clipper window
 
424
    if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
 
425
    {
 
426
        return ((wxPGClipperWindow*)ctrl)->GetControl();
 
427
    }
 
428
#else
 
429
    return ctrl;
 
430
#endif
 
431
}*/
 
432
 
 
433
// -----------------------------------------------------------------------
 
434
// wxPGTextCtrlEditor
 
435
// -----------------------------------------------------------------------
 
436
 
 
437
// Clipper window support macro (depending on whether it is used
 
438
// for this editor or not)
 
439
#if wxPG_NAT_TEXTCTRL_BORDER_X || wxPG_NAT_TEXTCTRL_BORDER_Y
 
440
    #define wxPG_NAT_TEXTCTRL_BORDER_ANY    1
 
441
#else
 
442
    #define wxPG_NAT_TEXTCTRL_BORDER_ANY    0
 
443
#endif
 
444
 
 
445
 
 
446
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrl,wxPGTextCtrlEditor,wxPGEditor)
 
447
 
 
448
 
 
449
wxPGWindowList wxPGTextCtrlEditor::CreateControls( wxPropertyGrid* propGrid,
 
450
                                                   wxPGProperty* property,
 
451
                                                   const wxPoint& pos,
 
452
                                                   const wxSize& sz ) const
 
453
{
 
454
    wxString text;
 
455
 
 
456
    //
 
457
    // If has children, and limited editing is specified, then don't create.
 
458
    if ( (property->GetFlags() & wxPG_PROP_NOEDITOR) &&
 
459
         property->GetChildCount() )
 
460
        return (wxWindow*) NULL;
 
461
 
 
462
    if ( !property->IsValueUnspecified() )
 
463
        text = property->GetValueString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
 
464
 
 
465
    int flags = 0;
 
466
    if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
 
467
         property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
 
468
        flags |= wxTE_PASSWORD;
 
469
 
 
470
    wxWindow* wnd = propGrid->GenerateEditorTextCtrl(pos,sz,text,(wxWindow*)NULL,flags,
 
471
                                                     property->GetMaxLength());
 
472
 
 
473
    return wnd;
 
474
}
 
475
 
 
476
#if 0
 
477
void wxPGTextCtrlEditor::DrawValue( wxDC& dc, wxPGProperty* property, const wxRect& rect ) const
 
478
{
 
479
    if ( !property->IsValueUnspecified() )
 
480
    {
 
481
        wxString drawStr = property->GetDisplayedString();
 
482
 
 
483
        // Code below should no longer be needed, as the obfuscation
 
484
        // is now done in GetValueAsString.
 
485
        /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
 
486
             property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
 
487
        {
 
488
            size_t a = drawStr.length();
 
489
            drawStr.Empty();
 
490
            drawStr.Append(wxT('*'),a);
 
491
        }*/
 
492
        dc.DrawText( drawStr, rect.x+wxPG_XBEFORETEXT, rect.y );
 
493
    }
 
494
}
 
495
#endif
 
496
 
 
497
void wxPGTextCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
 
498
{
 
499
    wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
 
500
 
 
501
    wxString s;
 
502
 
 
503
    if ( tc->HasFlag(wxTE_PASSWORD) )
 
504
        s = property->GetValueAsString(wxPG_FULL_VALUE);
 
505
    else
 
506
        s = property->GetDisplayedString();
 
507
 
 
508
    tc->SetValue(s);    
 
509
}
 
510
 
 
511
 
 
512
// Provided so that, for example, ComboBox editor can use the same code
 
513
// (multiple inheritance would get way too messy).
 
514
bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid* propGrid,
 
515
                                          wxPGProperty* WXUNUSED(property),
 
516
                                          wxWindow* ctrl,
 
517
                                          wxEvent& event )
 
518
{
 
519
    if ( !ctrl )
 
520
        return false;
 
521
 
 
522
    if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
 
523
    {
 
524
        if ( propGrid->IsEditorsValueModified() )
 
525
        {
 
526
            return true;
 
527
        }
 
528
    }
 
529
    else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
 
530
    {
 
531
        //
 
532
        // Pass this event outside wxPropertyGrid so that,
 
533
        // if necessary, program can tell when user is editing
 
534
        // a textctrl.
 
535
        // FIXME: Is it safe to change event id in the middle of event
 
536
        //        processing (seems to work, but...)?
 
537
        event.Skip();
 
538
        event.SetId(propGrid->GetId());
 
539
 
 
540
        propGrid->EditorsValueWasModified();
 
541
    }
 
542
    return false;
 
543
}
 
544
 
 
545
 
 
546
bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid* propGrid,
 
547
                                  wxPGProperty* property,
 
548
                                  wxWindow* ctrl,
 
549
                                  wxEvent& event ) const
 
550
{
 
551
    return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,ctrl,event);
 
552
}
 
553
 
 
554
 
 
555
bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl )
 
556
{
 
557
    wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
 
558
    wxString textVal = tc->GetValue();
 
559
 
 
560
    if ( property->UsesAutoUnspecified() && !textVal.length() )
 
561
    {
 
562
        variant.MakeNull();
 
563
        return true;
 
564
    }
 
565
 
 
566
    bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
 
567
 
 
568
    // Changing unspecified always causes event (returning
 
569
    // true here should be enough to trigger it).
 
570
    // TODO: Move to propgrid.cpp
 
571
    if ( !res && variant.IsNull() )
 
572
        res = true;
 
573
 
 
574
    return res;
 
575
}
 
576
 
 
577
 
 
578
bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
 
579
{
 
580
    return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant, property, ctrl);
 
581
}
 
582
 
 
583
 
 
584
void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty* property, wxWindow* ctrl ) const
 
585
{
 
586
    wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
 
587
 
 
588
    wxPropertyGrid* pg = property->GetGrid();
 
589
    wxASSERT(pg);  // Really, property grid should exist if editor does
 
590
    if ( pg )
 
591
        tc->SetValue(wxT(""));
 
592
}
 
593
 
 
594
 
 
595
void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty* property, wxWindow* ctrl, const wxString& txt ) const
 
596
{
 
597
    wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
 
598
 
 
599
    wxPropertyGrid* pg = property->GetGrid();
 
600
    wxASSERT(pg);  // Really, property grid should exist if editor does
 
601
    if ( pg )
 
602
        tc->SetValue(txt);
 
603
}
 
604
 
 
605
 
 
606
void wxPGTextCtrlEditor::OnFocus( wxPGProperty*, wxWindow* wnd ) const
 
607
{
 
608
    wxTextCtrl* tc = wxStaticCast(wnd, wxTextCtrl);
 
609
 
 
610
    tc->SetSelection(-1,-1);
 
611
}
 
612
 
 
613
 
 
614
wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
 
615
 
 
616
 
 
617
// -----------------------------------------------------------------------
 
618
// wxPGChoiceEditor
 
619
// -----------------------------------------------------------------------
 
620
 
 
621
 
 
622
WX_PG_IMPLEMENT_EDITOR_CLASS(Choice,wxPGChoiceEditor,wxPGEditor)
 
623
 
 
624
 
 
625
// This is a special enhanced double-click processor class.
 
626
// In essence, it allows for double-clicks for which the
 
627
// first click "created" the control.
 
628
class wxPGDoubleClickProcessor : public wxEvtHandler
 
629
{
 
630
public:
 
631
 
 
632
    wxPGDoubleClickProcessor( wxPGOwnerDrawnComboBox* combo )
 
633
        : wxEvtHandler()
 
634
    {
 
635
        m_timeLastMouseUp = 0;
 
636
        m_combo = combo;
 
637
        m_downReceived = false;
 
638
    }
 
639
 
 
640
protected:
 
641
 
 
642
    void OnMouseEvent( wxMouseEvent& event )
 
643
    {
 
644
        wxLongLong t = ::wxGetLocalTimeMillis();
 
645
        int evtType = event.GetEventType();
 
646
 
 
647
        if ( m_combo->HasFlag(wxPGCC_DCLICK_CYCLES) &&
 
648
             !m_combo->IsPopupShown() )
 
649
        {
 
650
            // Just check that it is in the text area
 
651
            wxPoint pt = event.GetPosition();
 
652
            if ( m_combo->GetTextRect().wxPGRectContains(pt) )
 
653
            {
 
654
                if ( evtType == wxEVT_LEFT_DOWN )
 
655
                {
 
656
                    // Set value to avoid up-events without corresponding downs
 
657
                    m_downReceived = true;
 
658
                }
 
659
                else if ( evtType == wxEVT_LEFT_DCLICK )
 
660
                {
 
661
                    // We'll make our own double-clicks
 
662
                    event.SetEventType(0);
 
663
                    return;
 
664
                }
 
665
                else if ( evtType == wxEVT_LEFT_UP )
 
666
                {
 
667
                    if ( m_downReceived || m_timeLastMouseUp == 1 )
 
668
                    {
 
669
                        wxLongLong timeFromLastUp = (t-m_timeLastMouseUp);
 
670
 
 
671
                        if ( timeFromLastUp < DOUBLE_CLICK_CONVERSION_TRESHOLD )
 
672
                        {
 
673
                            event.SetEventType(wxEVT_LEFT_DCLICK);
 
674
                            m_timeLastMouseUp = 1;
 
675
                        }
 
676
                        else
 
677
                        {
 
678
                            m_timeLastMouseUp = t;
 
679
                        }
 
680
                    }
 
681
                }
 
682
            }
 
683
        }
 
684
 
 
685
        event.Skip();
 
686
    }
 
687
 
 
688
    void OnSetFocus( wxFocusEvent& event )
 
689
    {
 
690
        m_timeLastMouseUp = ::wxGetLocalTimeMillis();
 
691
        event.Skip();
 
692
    }
 
693
 
 
694
private:
 
695
    wxLongLong                  m_timeLastMouseUp;
 
696
    wxPGOwnerDrawnComboBox*     m_combo;
 
697
    bool                        m_downReceived;
 
698
 
 
699
    DECLARE_EVENT_TABLE()
 
700
};
 
701
 
 
702
BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor, wxEvtHandler)
 
703
    EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent)
 
704
    EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus)
 
705
END_EVENT_TABLE()
 
706
 
 
707
 
 
708
 
 
709
class wxPGComboBox : public wxPGOwnerDrawnComboBox
 
710
{
 
711
public:
 
712
 
 
713
    wxPGComboBox()
 
714
        : wxPGOwnerDrawnComboBox()
 
715
    {
 
716
        m_dclickProcessor = (wxPGDoubleClickProcessor*) NULL;
 
717
        m_sizeEventCalled = false;
 
718
    }
 
719
 
 
720
    ~wxPGComboBox()
 
721
    {
 
722
        if ( m_dclickProcessor )
 
723
        {
 
724
            RemoveEventHandler(m_dclickProcessor);
 
725
            delete m_dclickProcessor;
 
726
        }
 
727
    }
 
728
 
 
729
    bool Create(wxWindow *parent,
 
730
                wxWindowID id,
 
731
                const wxString& value,
 
732
                const wxPoint& pos,
 
733
                const wxSize& size,
 
734
                const wxArrayString& choices,
 
735
                long style = 0,
 
736
                const wxValidator& validator = wxDefaultValidator,
 
737
                const wxString& name = wxT("wxOwnerDrawnComboBox"))
 
738
    {
 
739
        if ( !wxPGOwnerDrawnComboBox::Create( parent,
 
740
                                              id,
 
741
                                              value,
 
742
                                              pos,
 
743
                                              size,
 
744
                                              choices,
 
745
                                              style,
 
746
                                              validator,
 
747
                                              name ) )
 
748
            return false;
 
749
 
 
750
        m_dclickProcessor = new wxPGDoubleClickProcessor(this);
 
751
 
 
752
        PushEventHandler(m_dclickProcessor);
 
753
 
 
754
        return true;
 
755
    }
 
756
 
 
757
#if wxPG_USING_WXOWNERDRAWNCOMBOBOX
 
758
    virtual void OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
 
759
#else
 
760
    virtual bool OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
 
761
#endif
 
762
    {
 
763
        wxPropertyGrid* pg = GetGrid();
 
764
        pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,dc,(wxRect&)rect,flags);
 
765
#if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
 
766
        return true;
 
767
#endif    
 
768
    }
 
769
    virtual wxCoord OnMeasureItem( size_t item ) const
 
770
    {
 
771
        wxPropertyGrid* pg = GetGrid();
 
772
        wxRect rect;
 
773
        rect.x = -1;
 
774
        rect.width = 0;
 
775
        pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,*((wxDC*)NULL),rect,0);
 
776
        return rect.height;
 
777
    }
 
778
 
 
779
    wxPropertyGrid* GetGrid() const
 
780
    {
 
781
        wxPropertyGrid* pg = wxDynamicCast(GetParent()->GetParent(),wxPropertyGrid);
 
782
        wxASSERT(pg);
 
783
        return pg;
 
784
    }
 
785
 
 
786
    virtual wxCoord OnMeasureItemWidth( size_t item ) const
 
787
    {
 
788
        wxPropertyGrid* pg = GetGrid();
 
789
        wxRect rect;
 
790
        rect.x = -1;
 
791
        rect.width = -1;
 
792
        pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,*((wxDC*)NULL),rect,0);
 
793
        return rect.width;
 
794
    }
 
795
 
 
796
    virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust), int WXUNUSED(textCtrlYAdjust) )
 
797
    {
 
798
        wxPropertyGrid* pg = GetGrid();
 
799
        wxPGOwnerDrawnComboBox::PositionTextCtrl(
 
800
            wxPG_TEXTCTRLXADJUST - (wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1) - 1,
 
801
            pg->GetSpacingY() + 2
 
802
        );
 
803
    }
 
804
 
 
805
private:
 
806
    wxPGDoubleClickProcessor*   m_dclickProcessor;
 
807
    bool                        m_sizeEventCalled;
 
808
};
 
809
 
 
810
 
 
811
void wxPropertyGrid::OnComboItemPaint( wxPGCustomComboControl* pCc,
 
812
                                       int item,
 
813
                                       wxDC& dc,
 
814
                                       wxRect& rect,
 
815
                                       int flags )
 
816
{
 
817
    wxPGComboBox* pCb = (wxPGComboBox*)pCc;
 
818
 
 
819
    // Sanity check
 
820
    wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
 
821
 
 
822
    wxPGProperty* p = m_selected;
 
823
    wxString text;
 
824
 
 
825
    const wxPGChoices* pChoices = &p->GetChoices();
 
826
    const wxPGCommonValue* comVal = NULL;
 
827
    int choiceCount = p->GetChoiceCount();
 
828
    int comVals = p->GetDisplayedCommonValueCount();
 
829
    int comValIndex = -1;
 
830
    if ( item >= choiceCount && comVals > 0 )
 
831
    {
 
832
        comValIndex = item - choiceCount;
 
833
        comVal = GetCommonValue(comValIndex);
 
834
        if ( !p->IsValueUnspecified() )
 
835
            text = comVal->GetLabel();
 
836
    }
 
837
    else
 
838
    {
 
839
        if ( !(flags & wxPGCC_PAINTING_CONTROL) )
 
840
        {
 
841
            text = pCb->GetString(item);
 
842
        }
 
843
        else
 
844
        {
 
845
            if ( !p->IsValueUnspecified() )
 
846
                text = p->GetValueString(0);
 
847
        }
 
848
    }
 
849
 
 
850
    if ( item < 0 )
 
851
        return;
 
852
 
 
853
#if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
 
854
    // Add wxPGCC_PAINTING_SELECTED
 
855
    if ( !(flags & wxPGCC_PAINTING_CONTROL) &&
 
856
         wxDynamicCast(pCb->GetPopup()->GetControl(),wxVListBox)->GetSelection() == item )
 
857
         flags |= wxPGCC_PAINTING_SELECTED;
 
858
#endif
 
859
 
 
860
    wxSize cis;
 
861
 
 
862
    const wxBitmap* itemBitmap = NULL;
 
863
 
 
864
    if ( item >= 0 && pChoices && pChoices->Item(item).GetBitmap().Ok() && comValIndex == -1 )
 
865
        itemBitmap = &pChoices->Item(item).GetBitmap();
 
866
 
 
867
    //
 
868
    // Decide what custom image size to use
 
869
    if ( itemBitmap )
 
870
    {
 
871
        cis.x = itemBitmap->GetWidth();
 
872
        cis.y = itemBitmap->GetHeight();
 
873
    }
 
874
    else
 
875
    {
 
876
        cis = GetImageSize(p, item);
 
877
    }
 
878
 
 
879
    if ( rect.x < 0 )
 
880
    {
 
881
        // Default measure behaviour (no flexible, custom paint image only)
 
882
        if ( rect.width < 0 )
 
883
        {
 
884
            wxCoord x, y;
 
885
            GetTextExtent(text, &x, &y, 0, 0, &m_font);
 
886
            rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9 + x;
 
887
        }
 
888
 
 
889
        rect.height = cis.y + 2;
 
890
        return;
 
891
    }
 
892
 
 
893
    wxPGPaintData paintdata;
 
894
    paintdata.m_parent = NULL;
 
895
    paintdata.m_choiceItem = item;
 
896
 
 
897
    // This is by the current (1.0.0b) spec - if painting control, item is -1
 
898
    if ( (flags & wxPGCC_PAINTING_CONTROL) )
 
899
        paintdata.m_choiceItem = -1;
 
900
 
 
901
    if ( &dc )
 
902
        dc.SetBrush(*wxWHITE_BRUSH);
 
903
 
 
904
    if ( rect.x >= 0 )
 
905
    {
 
906
        //
 
907
        // DrawItem call
 
908
 
 
909
        wxPoint pt(rect.x + wxPG_CONTROL_MARGIN - wxPG_CHOICEXADJUST - 1,
 
910
                   rect.y + 1);
 
911
 
 
912
        int renderFlags = 0;
 
913
 
 
914
        if ( flags & wxPGCC_PAINTING_CONTROL )
 
915
            renderFlags |= wxPGCellRenderer::Control;
 
916
 
 
917
        if ( flags & wxPGCC_PAINTING_SELECTED )
 
918
            renderFlags |= wxPGCellRenderer::Selected;
 
919
 
 
920
        if ( cis.x > 0 && (p->HasFlag(wxPG_PROP_CUSTOMIMAGE) || !(flags & wxPGCC_PAINTING_CONTROL)) &&
 
921
             ( !p->m_valueBitmap || item == pCb->GetSelection() ) &&
 
922
             ( item >= 0 || (flags & wxPGCC_PAINTING_CONTROL) ) &&
 
923
             !itemBitmap
 
924
           )
 
925
        {
 
926
            pt.x += wxCC_CUSTOM_IMAGE_MARGIN1;
 
927
            wxRect r(pt.x,pt.y,cis.x,cis.y);
 
928
 
 
929
            if ( flags & wxPGCC_PAINTING_CONTROL )
 
930
            {
 
931
                //r.width = cis.x;
 
932
                r.height = wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight);
 
933
            }
 
934
 
 
935
            paintdata.m_drawnWidth = r.width;
 
936
 
 
937
            dc.SetPen(m_colPropFore);
 
938
            if ( comValIndex >= 0 )
 
939
            {
 
940
                const wxPGCommonValue* cv = GetCommonValue(comValIndex);
 
941
                wxPGCellRenderer* renderer = cv->GetRenderer();
 
942
                r.width = rect.width;
 
943
                renderer->Render( dc, r, this, p, m_selColumn, comValIndex, renderFlags );
 
944
                return;
 
945
            }
 
946
            else if ( item >= 0 )
 
947
            {
 
948
                p->OnCustomPaint( dc, r, paintdata );
 
949
            }
 
950
            else
 
951
            {
 
952
                dc.DrawRectangle( r );
 
953
            }
 
954
 
 
955
            pt.x += paintdata.m_drawnWidth + wxCC_CUSTOM_IMAGE_MARGIN2 - 1;
 
956
        }
 
957
        else
 
958
        {
 
959
            // TODO: This aligns text so that it seems to be horizontally
 
960
            //       on the same line as property values. Not really
 
961
            //       sure if its needed, but seems to not cause any harm.
 
962
            pt.x -= 1;
 
963
 
 
964
            if ( item < 0 && (flags & wxPGCC_PAINTING_CONTROL) )
 
965
                item = pCb->GetSelection();
 
966
 
 
967
            if ( pChoices && item >= 0 && comValIndex < 0 )
 
968
            {
 
969
                const wxPGChoiceEntry& cell = pChoices->Item(item);
 
970
                wxPGCellRenderer* renderer = wxPGGlobalVars->m_defaultRenderer;
 
971
                int imageOffset = renderer->PreDrawCell( dc, rect, cell, renderFlags );
 
972
                if ( imageOffset )
 
973
                    imageOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
 
974
                pt.x += imageOffset;
 
975
            }
 
976
        }
 
977
 
 
978
        //
 
979
        // Draw text
 
980
        //
 
981
 
 
982
        pt.y += (rect.height-m_fontHeight)/2 - 1;
 
983
 
 
984
        pt.x += 1;
 
985
 
 
986
        dc.DrawText( text, pt.x + wxPG_XBEFORETEXT, pt.y );
 
987
    }
 
988
    else
 
989
    {
 
990
        //
 
991
        // MeasureItem call
 
992
 
 
993
        p->OnCustomPaint( dc, rect, paintdata );
 
994
        rect.height = paintdata.m_drawnHeight + 2;
 
995
        rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9;
 
996
    }
 
997
}
 
998
 
 
999
bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid* propGrid, wxPGComboBox* cb, int cmnVal )
 
1000
{
 
1001
    wxPGProperty* property = propGrid->GetSelectedProperty();
 
1002
    wxASSERT( property );
 
1003
 
 
1004
    if ( cmnVal >= 0 )
 
1005
    {
 
1006
        // Yes, a common value is being selected
 
1007
        property->SetCommonValue( cmnVal );
 
1008
        wxSize imageSize = propGrid->GetCommonValue(cmnVal)->
 
1009
                            GetRenderer()->GetImageSize(property, 1, cmnVal);
 
1010
        if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
 
1011
        cb->SetCustomPaintWidth( imageSize.x );
 
1012
        return false;
 
1013
    }
 
1014
    else
 
1015
    {
 
1016
        wxSize imageSize = propGrid->GetImageSize(property, -1);
 
1017
        if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
 
1018
        cb->SetCustomPaintWidth( imageSize.x );
 
1019
        return true;
 
1020
    }
 
1021
}
 
1022
 
 
1023
// CreateControls calls this with CB_READONLY in extraStyle
 
1024
wxWindow* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid* propGrid,
 
1025
                                                wxPGProperty* property,
 
1026
                                                const wxPoint& pos,
 
1027
                                                const wxSize& sz,
 
1028
                                                long extraStyle ) const
 
1029
{
 
1030
    wxString        defString;
 
1031
 
 
1032
    // Get choices.
 
1033
    int index = property->GetChoiceInfo( NULL );
 
1034
 
 
1035
    bool isUnspecified = property->IsValueUnspecified();
 
1036
 
 
1037
    if ( isUnspecified )
 
1038
        index = -1;
 
1039
    else
 
1040
        defString = property->GetDisplayedString();
 
1041
 
 
1042
    const wxPGChoices& choices = property->GetChoices();
 
1043
 
 
1044
    wxArrayString labels = choices.GetLabels();
 
1045
 
 
1046
    wxPGComboBox* cb;
 
1047
 
 
1048
    wxPoint po(pos);
 
1049
    wxSize si(sz);
 
1050
    po.y += wxPG_CHOICEYADJUST;
 
1051
    si.y -= (wxPG_CHOICEYADJUST*2);
 
1052
 
 
1053
    po.x += wxPG_CHOICEXADJUST;
 
1054
    si.x -= wxPG_CHOICEXADJUST;
 
1055
    wxWindow* ctrlParent = propGrid->GetPanel();
 
1056
 
 
1057
    int odcbFlags = extraStyle | wxNO_BORDER | wxPGCC_PROCESS_ENTER | wxPGCC_ALT_KEYS;
 
1058
 
 
1059
    if ( (property->GetFlags() & wxPG_PROP_USE_DCC) &&
 
1060
         (property->IsKindOf(CLASSINFO(wxBoolProperty)) ) )
 
1061
        odcbFlags |= wxPGCC_DCLICK_CYCLES;
 
1062
 
 
1063
    //
 
1064
    // If common value specified, use appropriate index
 
1065
    unsigned int cmnVals = property->GetDisplayedCommonValueCount();
 
1066
    if ( cmnVals )
 
1067
    {
 
1068
        if ( !isUnspecified )
 
1069
        {
 
1070
            int cmnVal = property->GetCommonValue();
 
1071
            if ( cmnVal >= 0 )
 
1072
            {
 
1073
                index = labels.size() + cmnVal;
 
1074
            }
 
1075
        }
 
1076
 
 
1077
        unsigned int i;
 
1078
        for ( i=0; i<cmnVals; i++ )
 
1079
            labels.Add(propGrid->GetCommonValueLabel(i));
 
1080
    }
 
1081
 
 
1082
    cb = new wxPGComboBox();
 
1083
#ifdef __WXMSW__
 
1084
    cb->Hide();
 
1085
#endif
 
1086
    cb->Create(ctrlParent,
 
1087
               wxPG_SUBID1,
 
1088
               wxString(),
 
1089
               po,
 
1090
               si,
 
1091
               labels,
 
1092
               odcbFlags);
 
1093
 
 
1094
    //int extRight = propGrid->GetClientSize().x - (po.x+si.x);
 
1095
    //int extRight =  - (po.x+si.x);
 
1096
 
 
1097
    cb->SetButtonPosition(si.y,0,wxRIGHT);
 
1098
    //cb->SetPopupExtents( 1, extRight );
 
1099
    cb->SetTextIndent(wxPG_XBEFORETEXT-1);
 
1100
 
 
1101
    wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, property->GetCommonValue() );
 
1102
    /*if ( property->GetFlags() & wxPG_PROP_CUSTOMIMAGE )
 
1103
    {
 
1104
        wxSize imageSize = propGrid->GetImageSize(property, index);
 
1105
        if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
 
1106
        cb->SetCustomPaintWidth( imageSize.x );
 
1107
    }*/
 
1108
 
 
1109
    if ( index >= 0 && index < (int)cb->GetCount() )
 
1110
    {
 
1111
        cb->SetSelection( index );
 
1112
        if ( defString.length() )
 
1113
            cb->SetText( defString );
 
1114
    }
 
1115
    else if ( !(extraStyle & wxCB_READONLY) && defString.length() )
 
1116
        cb->SetValue( defString );
 
1117
    else
 
1118
        cb->SetSelection( -1 );
 
1119
 
 
1120
#ifdef __WXMSW__
 
1121
    cb->Show();
 
1122
#endif
 
1123
 
 
1124
    return (wxWindow*) cb;
 
1125
}
 
1126
 
 
1127
 
 
1128
void wxPGChoiceEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
 
1129
{
 
1130
    wxASSERT( ctrl );
 
1131
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1132
    wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
 
1133
    int ind = property->GetChoiceInfo( (wxPGChoiceInfo*)NULL );
 
1134
    cb->SetSelection(ind);
 
1135
}
 
1136
 
 
1137
wxPGWindowList wxPGChoiceEditor::CreateControls( wxPropertyGrid* propGrid, wxPGProperty* property,
 
1138
        const wxPoint& pos, const wxSize& sz ) const
 
1139
{
 
1140
    return CreateControlsBase(propGrid,property,pos,sz,wxCB_READONLY);
 
1141
}
 
1142
 
 
1143
 
 
1144
int wxPGChoiceEditor::InsertItem( wxWindow* ctrl, const wxString& label, int index ) const
 
1145
{
 
1146
    wxASSERT( ctrl );
 
1147
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1148
    wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
 
1149
 
 
1150
    if (index < 0)
 
1151
        index = cb->GetCount();
 
1152
 
 
1153
    return cb->Insert(label,index);
 
1154
}
 
1155
 
 
1156
 
 
1157
void wxPGChoiceEditor::DeleteItem( wxWindow* ctrl, int index ) const
 
1158
{
 
1159
    wxASSERT( ctrl );
 
1160
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1161
    wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
 
1162
 
 
1163
    cb->Delete(index);
 
1164
}
 
1165
 
 
1166
bool wxPGChoiceEditor::OnEvent( wxPropertyGrid* propGrid, wxPGProperty* property,
 
1167
    wxWindow* ctrl, wxEvent& event ) const
 
1168
{
 
1169
    if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
 
1170
    {
 
1171
        wxPGComboBox* cb = (wxPGComboBox*)ctrl;
 
1172
        int index = cb->GetSelection();
 
1173
        int cmnValIndex = -1;
 
1174
        int cmnVals = property->GetDisplayedCommonValueCount();
 
1175
        int items = cb->GetCount();
 
1176
 
 
1177
        if ( index >= (items-cmnVals) )
 
1178
        {
 
1179
            // Yes, a common value is being selected
 
1180
            cmnValIndex = index - (items-cmnVals);
 
1181
            property->SetCommonValue( cmnValIndex );
 
1182
 
 
1183
            // Truly set value to unspecified?
 
1184
            if ( propGrid->GetUnspecifiedCommonValue() == cmnValIndex )
 
1185
            {
 
1186
                if ( !property->IsValueUnspecified() )
 
1187
                    propGrid->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT);
 
1188
                property->SetValueToUnspecified();
 
1189
                if ( !cb->HasFlag(wxCB_READONLY) )
 
1190
                    cb->GetTextCtrl()->SetValue(wxEmptyString);
 
1191
                return false;
 
1192
            }
 
1193
        }
 
1194
        return wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, cmnValIndex );        
 
1195
    }
 
1196
    return false;
 
1197
}
 
1198
 
 
1199
 
 
1200
bool wxPGChoiceEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
 
1201
{
 
1202
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1203
 
 
1204
    int index = cb->GetSelection();
 
1205
 
 
1206
    if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
 
1207
        // Changing unspecified always causes event (returning
 
1208
        // true here should be enough to trigger it).
 
1209
         property->IsValueUnspecified()
 
1210
       )
 
1211
    {
 
1212
        return property->ActualIntToValue( variant, index, 0 );
 
1213
    }
 
1214
    return false;
 
1215
}
 
1216
 
 
1217
 
 
1218
void wxPGChoiceEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, const wxString& txt ) const
 
1219
{
 
1220
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1221
    wxASSERT( cb );
 
1222
    cb->SetValue(txt);
 
1223
}
 
1224
 
 
1225
 
 
1226
void wxPGChoiceEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
 
1227
{
 
1228
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1229
    wxASSERT( cb );
 
1230
    cb->SetSelection(value);
 
1231
}
 
1232
 
 
1233
 
 
1234
void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
 
1235
{
 
1236
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1237
    cb->SetSelection(-1);
 
1238
}
 
1239
 
 
1240
 
 
1241
bool wxPGChoiceEditor::CanContainCustomImage() const
 
1242
{
 
1243
    return true;
 
1244
}
 
1245
 
 
1246
 
 
1247
wxPGChoiceEditor::~wxPGChoiceEditor() { }
 
1248
 
 
1249
 
 
1250
// -----------------------------------------------------------------------
 
1251
// wxPGComboBoxEditor
 
1252
// -----------------------------------------------------------------------
 
1253
 
 
1254
 
 
1255
WX_PG_IMPLEMENT_EDITOR_CLASS(ComboBox,wxPGComboBoxEditor,wxPGChoiceEditor)
 
1256
 
 
1257
 
 
1258
void wxPGComboBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
 
1259
{
 
1260
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1261
    cb->SetValue(property->GetValueString(wxPG_EDITABLE_VALUE));
 
1262
 
 
1263
    // TODO: If string matches any selection, then select that.
 
1264
}
 
1265
 
 
1266
 
 
1267
wxPGWindowList wxPGComboBoxEditor::CreateControls( wxPropertyGrid* propGrid,
 
1268
                                                   wxPGProperty* property,
 
1269
                                                   const wxPoint& pos,
 
1270
                                                   const wxSize& sz ) const
 
1271
{
 
1272
    return CreateControlsBase(propGrid,property,pos,sz,0);
 
1273
}
 
1274
 
 
1275
 
 
1276
bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid* propGrid,
 
1277
                                  wxPGProperty* property,
 
1278
                                  wxWindow* ctrl,
 
1279
                                  wxEvent& event ) const
 
1280
{
 
1281
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*) NULL;
 
1282
    wxWindow* textCtrl = (wxWindow*) NULL;
 
1283
 
 
1284
    if ( ctrl )
 
1285
    {
 
1286
        cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1287
        textCtrl = cb->GetTextCtrl();
 
1288
    }
 
1289
 
 
1290
    if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,textCtrl,event) )
 
1291
        return true;
 
1292
 
 
1293
    return wxPGChoiceEditor::OnEvent(propGrid,property,ctrl,event);
 
1294
}
 
1295
 
 
1296
 
 
1297
bool wxPGComboBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
 
1298
{
 
1299
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1300
    wxString textVal = cb->GetValue();
 
1301
 
 
1302
    if ( property->UsesAutoUnspecified() && !textVal.length() )
 
1303
    {
 
1304
        variant.MakeNull();
 
1305
        return true;
 
1306
    }
 
1307
 
 
1308
    bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
 
1309
 
 
1310
    // Changing unspecified always causes event (returning
 
1311
    // true here should be enough to trigger it).
 
1312
    if ( !res && variant.IsNull() )
 
1313
        res = true;
 
1314
 
 
1315
    return res;
 
1316
}
 
1317
 
 
1318
 
 
1319
void wxPGComboBoxEditor::OnFocus( wxPGProperty*, wxWindow* ctrl ) const
 
1320
{
 
1321
    wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
 
1322
    cb->GetTextCtrl()->SetSelection(-1,-1);
 
1323
}
 
1324
 
 
1325
 
 
1326
wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
 
1327
 
 
1328
 
 
1329
// -----------------------------------------------------------------------
 
1330
// wxPGChoiceAndButtonEditor
 
1331
// -----------------------------------------------------------------------
 
1332
 
 
1333
 
 
1334
// This simpler implement_editor macro doesn't define class body.
 
1335
WX_PG_IMPLEMENT_EDITOR_CLASS(ChoiceAndButton,wxPGChoiceAndButtonEditor,wxPGChoiceEditor)
 
1336
 
 
1337
 
 
1338
wxPGWindowList wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
 
1339
                                                          wxPGProperty* property,
 
1340
                                                          const wxPoint& pos,
 
1341
                                                          const wxSize& sz ) const
 
1342
{
 
1343
    // Use one two units smaller to match size of the combo's dropbutton.
 
1344
    // (normally a bigger button is used because it looks better)
 
1345
    int bt_wid = sz.y;
 
1346
    bt_wid -= 2;
 
1347
    wxSize bt_sz(bt_wid,bt_wid);
 
1348
 
 
1349
    // Position of button.
 
1350
    wxPoint bt_pos(pos.x+sz.x-bt_sz.x,pos.y);
 
1351
#ifdef __WXMAC__
 
1352
    bt_pos.y -= 1;
 
1353
#else
 
1354
    bt_pos.y += 1;
 
1355
#endif
 
1356
 
 
1357
    wxWindow* bt = propGrid->GenerateEditorButton( bt_pos, bt_sz );
 
1358
 
 
1359
    // Size of choice.
 
1360
    wxSize ch_sz(sz.x-bt->GetSize().x,sz.y);
 
1361
 
 
1362
#ifdef __WXMAC__
 
1363
    ch_sz.x -= wxPG_TEXTCTRL_AND_BUTTON_SPACING;
 
1364
#endif
 
1365
 
 
1366
    wxWindow* ch = wxPG_EDITOR(Choice)->CreateControls(propGrid,property,
 
1367
        pos,ch_sz).m_primary;
 
1368
 
 
1369
#ifdef __WXMSW__
 
1370
    bt->Show();
 
1371
#endif
 
1372
 
 
1373
    return wxPGWindowList(ch, bt);
 
1374
}
 
1375
 
 
1376
 
 
1377
wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
 
1378
 
 
1379
 
 
1380
// -----------------------------------------------------------------------
 
1381
// wxPGTextCtrlAndButtonEditor
 
1382
// -----------------------------------------------------------------------
 
1383
 
 
1384
 
 
1385
// This simpler implement_editor macro doesn't define class body.
 
1386
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrlAndButton,wxPGTextCtrlAndButtonEditor,wxPGTextCtrlEditor)
 
1387
 
 
1388
 
 
1389
wxPGWindowList wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
 
1390
                                                            wxPGProperty* property,
 
1391
                                                            const wxPoint& pos,
 
1392
                                                            const wxSize& sz ) const
 
1393
{
 
1394
    wxWindow* wnd2;
 
1395
    wxWindow* wnd = propGrid->GenerateEditorTextCtrlAndButton( pos, sz, &wnd2,
 
1396
        property->GetFlags() & wxPG_PROP_NOEDITOR, property);
 
1397
 
 
1398
    return wxPGWindowList(wnd, wnd2);
 
1399
}
 
1400
 
 
1401
 
 
1402
wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
 
1403
 
 
1404
 
 
1405
// -----------------------------------------------------------------------
 
1406
// wxPGCheckBoxEditor
 
1407
// -----------------------------------------------------------------------
 
1408
 
 
1409
#if wxPG_INCLUDE_CHECKBOX
 
1410
 
 
1411
WX_PG_IMPLEMENT_EDITOR_CLASS(CheckBox,wxPGCheckBoxEditor,wxPGEditor)
 
1412
 
 
1413
 
 
1414
// state argument: 0x01 = set if checked
 
1415
//                 0x02 = set if rectangle should be bold
 
1416
static void DrawSimpleCheckBox( wxDC& dc, const wxRect& rect, int box_hei, int state, const wxColour& linecol )
 
1417
{
 
1418
 
 
1419
    // Box rectangle.
 
1420
    wxRect r(rect.x+wxPG_XBEFORETEXT,rect.y+((rect.height-box_hei)/2),box_hei,box_hei);
 
1421
 
 
1422
    // Draw check mark first because it is likely to overdraw the
 
1423
    // surrounding rectangle.
 
1424
    if ( state & 1 )
 
1425
    {
 
1426
        wxRect r2(r.x+wxPG_CHECKMARK_XADJ,
 
1427
                  r.y+wxPG_CHECKMARK_YADJ,
 
1428
                  r.width+wxPG_CHECKMARK_WADJ,
 
1429
                  r.height+wxPG_CHECKMARK_HADJ);
 
1430
    #if wxPG_CHECKMARK_DEFLATE
 
1431
        r2.Deflate(wxPG_CHECKMARK_DEFLATE);
 
1432
    #endif
 
1433
        dc.DrawCheckMark(r2);
 
1434
 
 
1435
        // This would draw a simple cross check mark.
 
1436
        // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
 
1437
        // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
 
1438
 
 
1439
    }
 
1440
 
 
1441
    if ( !(state & 2) )
 
1442
    {
 
1443
        // Pen for thin rectangle.
 
1444
        dc.SetPen(linecol);
 
1445
    }
 
1446
    else
 
1447
    {
 
1448
        // Pen for bold rectangle.
 
1449
        wxPen linepen(linecol,2,wxSOLID);
 
1450
        linepen.SetJoin(wxJOIN_MITER); // This prevents round edges.
 
1451
        dc.SetPen(linepen);
 
1452
        r.x++;
 
1453
        r.y++;
 
1454
        r.width--;
 
1455
        r.height--;
 
1456
    }
 
1457
 
 
1458
    dc.SetBrush(*wxTRANSPARENT_BRUSH);
 
1459
 
 
1460
    dc.DrawRectangle(r);
 
1461
    dc.SetPen(*wxTRANSPARENT_PEN);
 
1462
}
 
1463
 
 
1464
//
 
1465
// Real simple custom-drawn checkbox-without-label class.
 
1466
//
 
1467
class wxSimpleCheckBox : public wxControl
 
1468
{
 
1469
public:
 
1470
 
 
1471
    void SetValue( int value );
 
1472
 
 
1473
    wxSimpleCheckBox( wxWindow* parent,
 
1474
                      wxWindowID id,
 
1475
                      const wxPoint& pos = wxDefaultPosition,
 
1476
                      const wxSize& size = wxDefaultSize )
 
1477
        : wxControl(parent,id,pos,size,wxNO_BORDER|wxWANTS_CHARS)
 
1478
    {
 
1479
        // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
 
1480
        SetFont( parent->GetFont() );
 
1481
 
 
1482
        m_state = 0;
 
1483
        wxPropertyGrid* pg = (wxPropertyGrid*) parent->GetParent();
 
1484
        wxASSERT( pg->IsKindOf(CLASSINFO(wxPropertyGrid)) );
 
1485
        m_boxHeight = pg->GetFontHeight();
 
1486
        SetBackgroundStyle( wxBG_STYLE_COLOUR );
 
1487
    }
 
1488
 
 
1489
    virtual ~wxSimpleCheckBox();
 
1490
 
 
1491
    virtual bool ProcessEvent(wxEvent& event);
 
1492
 
 
1493
    int m_state;
 
1494
    int m_boxHeight;
 
1495
 
 
1496
    static wxBitmap* ms_doubleBuffer;
 
1497
 
 
1498
};
 
1499
 
 
1500
wxSimpleCheckBox::~wxSimpleCheckBox()
 
1501
{
 
1502
    delete ms_doubleBuffer;
 
1503
    ms_doubleBuffer = NULL;
 
1504
}
 
1505
 
 
1506
 
 
1507
wxBitmap* wxSimpleCheckBox::ms_doubleBuffer = (wxBitmap*) NULL;
 
1508
 
 
1509
// value = 2 means toggle (sorry, too lazy to do constants)
 
1510
void wxSimpleCheckBox::SetValue( int value )
 
1511
{
 
1512
    if ( value > 1 )
 
1513
    {
 
1514
        m_state++;
 
1515
        if ( m_state > 1 ) m_state = 0;
 
1516
    }
 
1517
    else
 
1518
    {
 
1519
        m_state = value;
 
1520
    }
 
1521
    Refresh();
 
1522
 
 
1523
    wxCommandEvent evt(wxEVT_COMMAND_CHECKBOX_CLICKED,GetParent()->GetId());
 
1524
 
 
1525
    wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
 
1526
    wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
 
1527
    propGrid->OnCustomEditorEvent(evt);
 
1528
}
 
1529
 
 
1530
 
 
1531
bool wxSimpleCheckBox::ProcessEvent(wxEvent& event)
 
1532
{
 
1533
    wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
 
1534
    wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
 
1535
 
 
1536
    if ( event.GetEventType() == wxEVT_NAVIGATION_KEY )
 
1537
    {
 
1538
        //wxLogDebug(wxT("wxEVT_NAVIGATION_KEY"));
 
1539
        //SetFocusFromKbd();
 
1540
        //event.Skip();
 
1541
        //return wxControl::ProcessEvent(event);
 
1542
    }
 
1543
    else
 
1544
    if ( ( (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK)
 
1545
          && ((wxMouseEvent&)event).m_x > (wxPG_XBEFORETEXT-2)
 
1546
          && ((wxMouseEvent&)event).m_x <= (wxPG_XBEFORETEXT-2+m_boxHeight) )
 
1547
       )
 
1548
    {
 
1549
        SetValue(2);
 
1550
        return true;
 
1551
    }
 
1552
    else if ( event.GetEventType() == wxEVT_PAINT )
 
1553
    {
 
1554
        wxSize clientSize = GetClientSize();
 
1555
        wxPaintDC dc(this);
 
1556
 
 
1557
        /*
 
1558
        // Buffered paint DC doesn't seem to do much good
 
1559
        if ( !ms_doubleBuffer ||
 
1560
             clientSize.x > ms_doubleBuffer->GetWidth() ||
 
1561
             clientSize.y > ms_doubleBuffer->GetHeight() )
 
1562
        {
 
1563
            delete ms_doubleBuffer;
 
1564
            ms_doubleBuffer = new wxBitmap(clientSize.x+25,clientSize.y+25);
 
1565
        }
 
1566
 
 
1567
        wxBufferedPaintDC dc(this,*ms_doubleBuffer);
 
1568
        */
 
1569
 
 
1570
        wxRect rect(0,0,clientSize.x,clientSize.y);
 
1571
        //rect.x -= 1;
 
1572
        rect.y += 1;
 
1573
        rect.width += 1;
 
1574
 
 
1575
        m_boxHeight = propGrid->GetFontHeight();
 
1576
 
 
1577
        wxColour bgcol = GetBackgroundColour();
 
1578
        dc.SetBrush( bgcol );
 
1579
        dc.SetPen( bgcol );
 
1580
        dc.DrawRectangle( rect );
 
1581
 
 
1582
        wxColour txcol = GetForegroundColour();
 
1583
 
 
1584
        int state = m_state;
 
1585
        if ( m_font.GetWeight() == wxBOLD )
 
1586
            state |= 2;
 
1587
 
 
1588
        DrawSimpleCheckBox(dc,rect,m_boxHeight,state,txcol);
 
1589
 
 
1590
        // If focused, indicate it somehow.
 
1591
        /*
 
1592
        if ( wxWindow::FindFocus() == this )
 
1593
        {
 
1594
            rect.x += 1;
 
1595
            rect.width -= 1;
 
1596
 
 
1597
            wxPGDrawFocusRect(dc,rect);
 
1598
        }
 
1599
        */
 
1600
 
 
1601
        return true;
 
1602
    }
 
1603
    else if ( event.GetEventType() == wxEVT_SIZE ||
 
1604
              event.GetEventType() == wxEVT_SET_FOCUS ||
 
1605
              event.GetEventType() == wxEVT_KILL_FOCUS
 
1606
            )
 
1607
    {
 
1608
        Refresh();
 
1609
    }
 
1610
    else if ( event.GetEventType() == wxEVT_KEY_DOWN )
 
1611
    {
 
1612
        wxKeyEvent& keyEv = (wxKeyEvent&) event;
 
1613
 
 
1614
        if ( keyEv.GetKeyCode() == WXK_TAB )
 
1615
        {
 
1616
            propGrid->SendNavigationKeyEvent( keyEv.ShiftDown()?0:1 );
 
1617
            return true;
 
1618
        }
 
1619
        else
 
1620
        if ( keyEv.GetKeyCode() == WXK_SPACE )
 
1621
        {
 
1622
            SetValue(2);
 
1623
            return true;
 
1624
        }
 
1625
    }
 
1626
    return wxControl::ProcessEvent(event);
 
1627
}
 
1628
 
 
1629
 
 
1630
wxPGWindowList wxPGCheckBoxEditor::CreateControls( wxPropertyGrid* propGrid,
 
1631
                                                   wxPGProperty* property,
 
1632
                                                   const wxPoint& pos,
 
1633
                                                   const wxSize& size ) const
 
1634
{
 
1635
    wxPoint pt = pos;
 
1636
    pt.x -= wxPG_XBEFOREWIDGET;
 
1637
    wxSize sz = size;
 
1638
    sz.x = propGrid->GetFontHeight() + (wxPG_XBEFOREWIDGET*2) + 4;
 
1639
 
 
1640
    wxSimpleCheckBox* cb = new wxSimpleCheckBox(propGrid->GetPanel(),wxPG_SUBID1,pt,sz);
 
1641
 
 
1642
    cb->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
 
1643
 
 
1644
    cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DOWN,
 
1645
            (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
 
1646
            &wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
 
1647
 
 
1648
    cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DCLICK,
 
1649
            (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
 
1650
            &wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
 
1651
 
 
1652
    if ( property->GetChoiceInfo((wxPGChoiceInfo*)NULL) &&
 
1653
         !property->IsValueUnspecified() )
 
1654
        cb->m_state = 1;
 
1655
 
 
1656
    // If mouse cursor was on the item, toggle the value now.
 
1657
    if ( propGrid->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK )
 
1658
    {
 
1659
        wxPoint pt = cb->ScreenToClient(::wxGetMousePosition());
 
1660
        if ( pt.x <= (wxPG_XBEFORETEXT-2+cb->m_boxHeight) )
 
1661
        {
 
1662
            cb->m_state++;
 
1663
 
 
1664
            if ( cb->m_state > 1 )
 
1665
                cb->m_state = 0;
 
1666
 
 
1667
            // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial click 
 
1668
            propGrid->ChangePropertyValue(property, wxPGVariant_Bool(cb->m_state));
 
1669
        }
 
1670
    }
 
1671
 
 
1672
    propGrid->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR );
 
1673
 
 
1674
    return cb;
 
1675
}
 
1676
 
 
1677
/*
 
1678
class wxPGCheckBoxRenderer : public wxPGDefaultRenderer
 
1679
{
 
1680
public:
 
1681
 
 
1682
    virtual void Render( wxDC& dc, const wxRect& rect,
 
1683
                         const wxPropertyGrid* WXUNUSED(propertyGrid), wxPGProperty* property,
 
1684
                         int WXUNUSED(column), int WXUNUSED(item), int WXUNUSED(flags) ) const
 
1685
    {
 
1686
        int state = 0;
 
1687
        if ( !(property->GetFlags() & wxPG_PROP_UNSPECIFIED) )
 
1688
        {
 
1689
            state = ((wxPGProperty*)property)->GetChoiceInfo((wxPGChoiceInfo*)NULL);
 
1690
            if ( dc.GetFont().GetWeight() == wxBOLD ) state |= 2;
 
1691
        }
 
1692
        DrawSimpleCheckBox(dc,rect,dc.GetCharHeight(),state,dc.GetTextForeground());
 
1693
    }
 
1694
 
 
1695
protected:
 
1696
};
 
1697
 
 
1698
wxPGCheckBoxRenderer g_wxPGCheckBoxRenderer;
 
1699
 
 
1700
wxPGCellRenderer* wxPGCheckBoxEditor::GetCellRenderer() const
 
1701
{
 
1702
    return &g_wxPGCheckBoxRenderer;
 
1703
}
 
1704
*/
 
1705
 
 
1706
void wxPGCheckBoxEditor::DrawValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& WXUNUSED(text) ) const
 
1707
{
 
1708
    int state = 0;
 
1709
    if ( !property->IsValueUnspecified() )
 
1710
    {
 
1711
        state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
 
1712
        if ( dc.GetFont().GetWeight() == wxBOLD ) state |= 2;
 
1713
    }
 
1714
    DrawSimpleCheckBox(dc,rect,dc.GetCharHeight(),state,dc.GetTextForeground());
 
1715
}
 
1716
 
 
1717
void wxPGCheckBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
 
1718
{
 
1719
    wxASSERT( ctrl );
 
1720
    ((wxSimpleCheckBox*)ctrl)->m_state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
 
1721
    ctrl->Refresh();
 
1722
}
 
1723
 
 
1724
 
 
1725
bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* WXUNUSED(property),
 
1726
    wxWindow* WXUNUSED(ctrl), wxEvent& event ) const
 
1727
{
 
1728
    if ( event.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED )
 
1729
    {
 
1730
        return true;
 
1731
    }
 
1732
    return false;
 
1733
}
 
1734
 
 
1735
 
 
1736
bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
 
1737
{
 
1738
    wxSimpleCheckBox* cb = (wxSimpleCheckBox*)ctrl;
 
1739
 
 
1740
    int index = cb->m_state;
 
1741
 
 
1742
    if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
 
1743
         // Changing unspecified always causes event (returning
 
1744
         // true here should be enough to trigger it).
 
1745
         property->IsValueUnspecified()
 
1746
       )
 
1747
    {
 
1748
        return property->ActualIntToValue(variant, index, 0);
 
1749
    }
 
1750
    return false;
 
1751
}
 
1752
 
 
1753
 
 
1754
void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
 
1755
{
 
1756
    if ( value != 0 ) value = 1;
 
1757
    ((wxSimpleCheckBox*)ctrl)->m_state = value;
 
1758
    ctrl->Refresh();
 
1759
}
 
1760
 
 
1761
 
 
1762
void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
 
1763
{
 
1764
    ((wxSimpleCheckBox*)ctrl)->m_state = 0;
 
1765
    ctrl->Refresh();
 
1766
}
 
1767
 
 
1768
 
 
1769
wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
 
1770
 
 
1771
 
 
1772
#endif // wxPG_INCLUDE_CHECKBOX
 
1773
 
 
1774
// -----------------------------------------------------------------------
 
1775
 
 
1776
wxWindow* wxPropertyGrid::GetEditorControl() const
 
1777
{
 
1778
    wxWindow* ctrl = m_wndEditor;
 
1779
 
 
1780
    if ( !ctrl )
 
1781
        return ctrl;
 
1782
 
 
1783
    // If it's clipper window, return its child instead
 
1784
#if wxPG_ENABLE_CLIPPER_WINDOW
 
1785
    if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
 
1786
    {
 
1787
        return ((wxPGClipperWindow*)ctrl)->GetControl();
 
1788
    }
 
1789
#endif
 
1790
 
 
1791
    return ctrl;
 
1792
}
 
1793
 
 
1794
// -----------------------------------------------------------------------
 
1795
 
 
1796
void wxPropertyGrid::CorrectEditorWidgetSizeX()
 
1797
{
 
1798
    if ( m_selColumn == -1 )
 
1799
        return;
 
1800
 
 
1801
    int secWid = 0;
 
1802
    int newSplitterx = m_pState->DoGetSplitterPosition(m_selColumn-1);
 
1803
    int newWidth = newSplitterx + m_pState->m_colWidths[m_selColumn];
 
1804
 
 
1805
    if ( m_wndEditor2 )
 
1806
    {
 
1807
        // if width change occurred, move secondary wnd by that amount
 
1808
        wxRect r = m_wndEditor2->GetRect();
 
1809
        secWid = r.width;
 
1810
        r.x = newWidth - secWid;
 
1811
 
 
1812
        m_wndEditor2->SetSize( r );
 
1813
 
 
1814
        // if primary is textctrl, then we have to add some extra space
 
1815
#ifdef __WXMAC__
 
1816
        if ( m_wndEditor )
 
1817
#else
 
1818
        if ( m_wndEditor && m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) )
 
1819
#endif
 
1820
            secWid += wxPG_TEXTCTRL_AND_BUTTON_SPACING;
 
1821
    }
 
1822
 
 
1823
    if ( m_wndEditor )
 
1824
    {
 
1825
        wxRect r = m_wndEditor->GetRect();
 
1826
 
 
1827
        r.x = newSplitterx+m_ctrlXAdjust;
 
1828
 
 
1829
        if ( !(m_iFlags & wxPG_FL_FIXED_WIDTH_EDITOR) )
 
1830
            r.width = newWidth - r.x - secWid;
 
1831
 
 
1832
        m_wndEditor->SetSize(r);
 
1833
    }
 
1834
 
 
1835
    if ( m_wndEditor2 )
 
1836
        m_wndEditor2->Refresh();
 
1837
}
 
1838
 
 
1839
// -----------------------------------------------------------------------
 
1840
 
 
1841
void wxPropertyGrid::CorrectEditorWidgetPosY()
 
1842
{
 
1843
    if ( m_selected && (m_wndEditor || m_wndEditor2) ) 
 
1844
    {
 
1845
        wxRect r = GetEditorWidgetRect(m_selected, m_selColumn);
 
1846
 
 
1847
        if ( m_wndEditor )
 
1848
        {
 
1849
            wxPoint pos = m_wndEditor->GetPosition();
 
1850
 
 
1851
            // Calculate y offset
 
1852
            int offset = pos.y % m_lineHeight;
 
1853
 
 
1854
            m_wndEditor->Move(pos.x, r.y + offset);
 
1855
        }
 
1856
 
 
1857
        if ( m_wndEditor2 )
 
1858
        {
 
1859
            wxPoint pos = m_wndEditor2->GetPosition();
 
1860
 
 
1861
            m_wndEditor2->Move(pos.x, r.y);
 
1862
        }
 
1863
    }
 
1864
}
 
1865
 
 
1866
// -----------------------------------------------------------------------
 
1867
 
 
1868
bool wxPropertyGrid::AdjustPosForClipperWindow( wxWindow* topCtrlWnd, int* x, int* y )
 
1869
{
 
1870
#if wxPG_ENABLE_CLIPPER_WINDOW
 
1871
    // Take clipper window into account
 
1872
    if (topCtrlWnd->GetPosition().x < 1 &&
 
1873
        !topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)))
 
1874
    {
 
1875
        topCtrlWnd = topCtrlWnd->GetParent();
 
1876
        wxASSERT( topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)) );
 
1877
        *x -= ((wxPGClipperWindow*)topCtrlWnd)->GetXClip();
 
1878
        *y -= ((wxPGClipperWindow*)topCtrlWnd)->GetYClip();
 
1879
        return true;
 
1880
    }
 
1881
#else
 
1882
    wxUnusedVar(topCtrlWnd);
 
1883
    wxUnusedVar(x);
 
1884
    wxUnusedVar(y);
 
1885
#endif
 
1886
    return false;
 
1887
}
 
1888
 
 
1889
// -----------------------------------------------------------------------
 
1890
 
 
1891
// Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
 
1892
// fits into that category as well).
 
1893
void wxPropertyGrid::FixPosForTextCtrl( wxWindow* ctrl, const wxPoint& offset )
 
1894
{
 
1895
    // Center the control vertically
 
1896
    wxRect finalPos = ctrl->GetRect();
 
1897
    int y_adj = (m_lineHeight - finalPos.height)/2 + wxPG_TEXTCTRLYADJUST;
 
1898
 
 
1899
    // Prevent over-sized control
 
1900
    int sz_dec = (y_adj + finalPos.height) - m_lineHeight;
 
1901
    if ( sz_dec < 0 ) sz_dec = 0;
 
1902
 
 
1903
    finalPos.y += y_adj;
 
1904
    finalPos.height -= (y_adj+sz_dec);
 
1905
 
 
1906
    const int textCtrlXAdjust = wxPG_TEXTCTRLXADJUST;
 
1907
 
 
1908
    finalPos.x += textCtrlXAdjust;
 
1909
    finalPos.width -= textCtrlXAdjust;
 
1910
 
 
1911
    finalPos.x += offset.x;
 
1912
    finalPos.y += offset.y;
 
1913
 
 
1914
    ctrl->SetSize(finalPos);
 
1915
}
 
1916
 
 
1917
// -----------------------------------------------------------------------
 
1918
 
 
1919
wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
 
1920
                                                  const wxSize& sz,
 
1921
                                                  const wxString& value,
 
1922
                                                  wxWindow* secondary,
 
1923
                                                  int extraStyle,
 
1924
                                                  int maxLen )
 
1925
{
 
1926
    wxPGProperty* selected = m_selected;
 
1927
    wxASSERT(selected);
 
1928
 
 
1929
    int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
 
1930
 
 
1931
    if ( selected->HasFlag(wxPG_PROP_READONLY) )
 
1932
        tcFlags |= wxTE_READONLY;
 
1933
 
 
1934
    wxPoint p(pos.x,pos.y);
 
1935
    wxSize s(sz.x,sz.y);
 
1936
 
 
1937
   // Need to reduce width of text control on Mac
 
1938
#if defined(__WXMAC__)
 
1939
   s.x -= 8;
 
1940
#endif
 
1941
 
 
1942
     // Take button into acccount
 
1943
    if ( secondary )
 
1944
    {
 
1945
        s.x -= (secondary->GetSize().x + wxPG_TEXTCTRL_AND_BUTTON_SPACING);
 
1946
        m_iFlags &= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE);
 
1947
    }
 
1948
 
 
1949
    // If the height is significantly higher, then use border, and fill the rect exactly.
 
1950
    bool hasSpecialSize = false;
 
1951
 
 
1952
    if ( (sz.y - m_lineHeight) > 5 )
 
1953
        hasSpecialSize = true;
 
1954
 
 
1955
#if wxPG_NAT_TEXTCTRL_BORDER_ANY
 
1956
 
 
1957
    // Create clipper window
 
1958
    wxPGClipperWindow* wnd = new wxPGClipperWindow();
 
1959
#if defined(__WXMSW__)
 
1960
    wnd->Hide();
 
1961
#endif
 
1962
    wnd->Create(GetPanel(),wxPG_SUBID1,p,s);
 
1963
 
 
1964
    // This generates rect of the control inside the clipper window
 
1965
    if ( !hasSpecialSize )
 
1966
        wnd->GetControlRect(wxPG_NAT_TEXTCTRL_BORDER_X, wxPG_NAT_TEXTCTRL_BORDER_Y, p, s);
 
1967
    else
 
1968
        wnd->GetControlRect(0, 0, p, s);
 
1969
 
 
1970
    wxWindow* ctrlParent = wnd;
 
1971
 
 
1972
#else
 
1973
 
 
1974
    wxWindow* ctrlParent = GetPanel();
 
1975
 
 
1976
    if ( !hasSpecialSize )
 
1977
        tcFlags |= wxNO_BORDER;
 
1978
 
 
1979
#endif
 
1980
 
 
1981
    wxTextCtrl* tc = new wxTextCtrl();
 
1982
 
 
1983
#if defined(__WXMSW__) && !wxPG_NAT_TEXTCTRL_BORDER_ANY
 
1984
    tc->Hide();
 
1985
#endif
 
1986
    SetupTextCtrlValue(value);
 
1987
    tc->Create(ctrlParent,wxPG_SUBID1,value, p, s,tcFlags);
 
1988
 
 
1989
#if wxPG_NAT_TEXTCTRL_BORDER_ANY
 
1990
    wxWindow* ed = wnd;
 
1991
    wnd->SetControl(tc);
 
1992
#else
 
1993
    wxWindow* ed = tc;
 
1994
#endif
 
1995
 
 
1996
    // Center the control vertically
 
1997
    if ( !hasSpecialSize )
 
1998
        FixPosForTextCtrl(ed);
 
1999
 
 
2000
#ifdef __WXMSW__
 
2001
    ed->Show();
 
2002
    if ( secondary )
 
2003
        secondary->Show();
 
2004
#endif
 
2005
 
 
2006
    // Set maximum length
 
2007
    if ( maxLen > 0 )
 
2008
        tc->SetMaxLength( maxLen );
 
2009
 
 
2010
    return (wxWindow*) ed;
 
2011
}
 
2012
 
 
2013
// -----------------------------------------------------------------------
 
2014
 
 
2015
wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
 
2016
{
 
2017
    wxPGProperty* selected = m_selected;
 
2018
    wxASSERT(selected);
 
2019
 
 
2020
#ifdef __WXMAC__
 
2021
   // Decorations are chunky on Mac, and we can't make the button square, so
 
2022
   // do things a bit differently on this platform.
 
2023
 
 
2024
   wxPoint p(pos.x+sz.x,
 
2025
             pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
 
2026
   wxSize s(25, -1);
 
2027
 
 
2028
   wxButton* but = new wxButton();
 
2029
   but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
 
2030
 
 
2031
   // Now that we know the size, move to the correct position
 
2032
   p.x = pos.x + sz.x - but->GetSize().x - 2;
 
2033
   but->Move(p);
 
2034
 
 
2035
#else 
 
2036
    wxSize s(sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2),
 
2037
        sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2));
 
2038
 
 
2039
    // Reduce button width to lineheight
 
2040
    if ( s.x > m_lineHeight )
 
2041
        s.x = m_lineHeight;
 
2042
 
 
2043
#ifdef __WXGTK__
 
2044
    // On wxGTK, take fixed button margins into account
 
2045
    if ( s.x < 25 )
 
2046
        s.x = 25;
 
2047
#endif
 
2048
 
 
2049
    wxPoint p(pos.x+sz.x-s.x,
 
2050
        pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
 
2051
 
 
2052
    wxButton* but = new wxButton();
 
2053
  #ifdef __WXMSW__
 
2054
    but->Hide();
 
2055
  #endif
 
2056
    but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
 
2057
 
 
2058
  #ifdef __WXGTK__
 
2059
    wxFont font = GetFont();
 
2060
    font.SetPointSize(font.GetPointSize()-2);
 
2061
    but->SetFont(font);
 
2062
  #else
 
2063
    but->SetFont(GetFont());
 
2064
  #endif
 
2065
#endif
 
2066
 
 
2067
    if ( selected->HasFlag(wxPG_PROP_READONLY) )
 
2068
        but->Disable();
 
2069
 
 
2070
    return but;
 
2071
}
 
2072
 
 
2073
// -----------------------------------------------------------------------
 
2074
 
 
2075
wxWindow* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint& pos,
 
2076
                                                           const wxSize& sz,
 
2077
                                                           wxWindow** psecondary,
 
2078
                                                           int limitedEditing,
 
2079
                                                           wxPGProperty* property )
 
2080
{
 
2081
    wxButton* but = (wxButton*)GenerateEditorButton(pos,sz);
 
2082
    *psecondary = (wxWindow*)but;
 
2083
 
 
2084
    if ( limitedEditing )
 
2085
    {
 
2086
    #ifdef __WXMSW__
 
2087
        // There is button Show in GenerateEditorTextCtrl as well
 
2088
        but->Show();
 
2089
    #endif
 
2090
        return (wxWindow*) NULL;
 
2091
    }
 
2092
 
 
2093
    wxString text;
 
2094
 
 
2095
    if ( !property->IsValueUnspecified() )
 
2096
        text = property->GetValueString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
 
2097
 
 
2098
    return GenerateEditorTextCtrl(pos,sz,text,but,property->m_maxLen);
 
2099
}
 
2100
 
 
2101
// -----------------------------------------------------------------------
 
2102
 
 
2103
wxTextCtrl* wxPropertyGrid::GetEditorTextCtrl() const
 
2104
{
 
2105
    wxWindow* wnd = GetEditorControl();
 
2106
 
 
2107
    if ( !wnd )
 
2108
        return NULL;
 
2109
 
 
2110
    if ( wnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
 
2111
        return wxStaticCast(wnd, wxTextCtrl);
 
2112
 
 
2113
    if ( wnd->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)) )
 
2114
    {
 
2115
        wxPGOwnerDrawnComboBox* cb = wxStaticCast(wnd, wxPGOwnerDrawnComboBox);
 
2116
        return cb->GetTextCtrl();
 
2117
    }
 
2118
 
 
2119
    return NULL;
 
2120
}
 
2121
 
 
2122
// -----------------------------------------------------------------------
 
2123
// wxPGEditorDialogAdapter
 
2124
// -----------------------------------------------------------------------
 
2125
 
 
2126
IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter, wxObject)
 
2127
 
 
2128
bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
 
2129
{
 
2130
    if ( !propGrid->EditorValidate() )
 
2131
        return false;
 
2132
 
 
2133
    bool res = DoShowDialog( propGrid, property );
 
2134
 
 
2135
    if ( res )
 
2136
    {
 
2137
        propGrid->ValueChangeInEvent( m_value );
 
2138
        return true;
 
2139
    }
 
2140
 
 
2141
    return false;
 
2142
}
 
2143
 
 
2144
// -----------------------------------------------------------------------
 
2145
// wxPGMultiButton
 
2146
// -----------------------------------------------------------------------
 
2147
 
 
2148
wxPGMultiButton::wxPGMultiButton( wxPropertyGrid* pg, const wxSize& sz )
 
2149
    : wxWindow( pg->GetPanel(), wxPG_SUBID2, wxPoint(-100,-100), wxSize(0, sz.y) ),
 
2150
      m_fullEditorSize(sz), m_buttonsWidth(0)
 
2151
{
 
2152
    SetBackgroundColour(pg->GetCellBackgroundColour());
 
2153
}
 
2154
 
 
2155
int wxPGMultiButton::GenId( int id ) const
 
2156
{
 
2157
    if ( id < -1 )
 
2158
    {
 
2159
        if ( m_buttons.size() )
 
2160
            id = GetButton(m_buttons.size()-1)->GetId() + 1;
 
2161
        else
 
2162
            id = wxPG_SUBID2;
 
2163
    }
 
2164
    return id;
 
2165
}
 
2166
 
 
2167
#if wxUSE_BMPBUTTON
 
2168
void wxPGMultiButton::Add( const wxBitmap& bitmap, int id )
 
2169
{
 
2170
    id = GenId(id);
 
2171
    wxSize sz = GetSize();
 
2172
    wxButton* button = new wxBitmapButton( this, id, bitmap, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
 
2173
    m_buttons.push_back(button);
 
2174
    int bw = button->GetSize().x;
 
2175
    SetSize(wxSize(sz.x+bw,sz.y));
 
2176
    m_buttonsWidth += bw;
 
2177
}
 
2178
#endif
 
2179
 
 
2180
void wxPGMultiButton::Add( const wxString& label, int id )
 
2181
{
 
2182
    id = GenId(id);
 
2183
    wxSize sz = GetSize();
 
2184
    wxButton* button = new wxButton( this, id, label, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
 
2185
    m_buttons.push_back(button);
 
2186
    int bw = button->GetSize().x;
 
2187
    SetSize(wxSize(sz.x+bw,sz.y));
 
2188
    m_buttonsWidth += bw;
 
2189
}
 
2190
 
 
2191
// -----------------------------------------------------------------------