-
Notifications
You must be signed in to change notification settings - Fork 0
/
button.cc
232 lines (185 loc) · 5.24 KB
/
button.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/* button.cc -- Implementation of the Button Figure
Copyright (C) 1997-2013, Brian Bray
*/
#define NOTRACE
#include "bw/trace.h"
#include "bw/bwassert.h"
#include "bw/string.h"
#include "bw/figure.h"
#include "bw/button.h"
#include "bw/tools.h"
#include "bw/styletools.h"
namespace bw {
// Compile time options
//
// onQuerySize returns the size needed to "comfortably" fit the button text.
// These parameters determine the level of "comfort"
//
static const int nVerticalPad = 2;
static const int nHorizontalPad = 20;
static const int nHorizontalMin = 50;
///////////////////////////////////////////////////////////////////////////
/*: class Button
This is a basic button Figure. It is written as a true BW figure without
using a native control.
Button is a subclass of <A HREF=Figure.html>Figure</A>,
<A HREF=Focus.html>Focus</A>, and <A HREF=Mouse.html>Mouse</A> and defines
event handling functions declared in these base classes.
*/
///////////////////////////////////////////////////////////////////////////
/*: Button::Button()
Constructor. The arguments give a constant label for the button and
indicate the action that will be signalled if the button is pushed.
*/
Button::Button( const char* pszLabel, const char* pszAction )
: m_strLabel( pszLabel ),
m_strAction( pszAction ),
m_state( Inactive ),
m_isDefault( false ),
m_hasFocus( false )
{
// Intentionally empty
}
///////////////////////////////////////////////////////////////////////////
/*: Button::~Button()
Destructor.
*/
Button::~Button()
{}
///////////////////////////////////////////////////////////////////////////
/*: Button::makeDefault()
Makes this button the default button in a group.
Prototype: void Button::makeDefault( bool isDefault=true )
*/
void Button::makeDefault( bool isDefault )
{
if (m_isDefault != isDefault)
invalidate();
m_isDefault = isDefault;
}
///////////////////////////////////////////////////////////////////////////
/*: Button::onQuerySize()
Returns the minimum size button that will confortably fit the text.
*/
void Button::onQuerySize( LogPos& lposWidth, LogPos& lposHeight )
{
FontMetric fm(*this,FaceFont);
TextExtent tex = fm.getTextExtent(m_strLabel);
lposHeight = fm.height() + Bevel::borderWidth()*2 + 2 + nVerticalPad;
lposWidth = tex.width + Bevel::borderWidth()*2 + nHorizontalPad;
if (lposWidth<nHorizontalMin)
lposWidth = nHorizontalMin;
}
///////////////////////////////////////////////////////////////////////////
/*: Button::draw()
Draws button. This buttons style has quite generic 3D look. Focus is
indicated by a dashed line just inside the button face. The standard
style colours (Face, ButtonFace, etc) are used. The default button is
indicated with a black border.
*/
void Button::draw( Canvas& cvs )
{
Bevel bvl(cvs);
int w = cvs.width();
int h = cvs.height();
// wBorder is the full border width including:
// 1 pixel for the default indicator
// Several pixels for the Bevel
// 2 pixels for the Focus indicator
int wBorder = Bevel::borderWidth() + 3;
// Max text size
int maxW = w - 2*wBorder;
int maxH = h - 2*wBorder - 1;
//bwassert( maxW>0 ); // TODO: Handle this case cleanly
//bwassert( maxH>0 );
Pen penBlack(cvs, Black);
if (m_isDefault) {
penBlack.rectangle( 0, 0, w, h );
} else {
Brush brBack(cvs, ControlSurface);
brBack.rectangle( 0, 0, w, h );
}
String strLabel = m_strLabel;
Press prsLabel(cvs, FaceFont);
TextExtent tex=prsLabel.getTextExtent(strLabel);
// Pick font size
if (tex.height>maxH) {
// Font too big, try a smaller one
prsLabel.changeFont( SmallFaceFont );
tex = prsLabel.getTextExtent(strLabel);
if (tex.height>maxH)
strLabel = ""; // I assume that "..." is not too high
}
// cut label to fit
if (tex.width>maxW || tex.height>maxH) {
int lDots = prsLabel.getTextLength("...");
int nChar = prsLabel.fitString( strLabel, maxW-lDots );
strLabel = strLabel.substring(0,nChar) + "...";
// I need to do it again in case the "..." is itself too long
nChar = prsLabel.fitString( strLabel, maxW );
strLabel = strLabel.substring(0,nChar);
tex = prsLabel.getTextExtent( strLabel );
}
int xt = (w-tex.width)/2;
int yt = (h-tex.height)/2 + tex.ascent;
switch (m_state) {
case Released:
case Inactive:
bvl.drawRaised( 1, 1, w-2, h-2);
prsLabel.drawText( xt, yt, strLabel );
break;
case Pushed:
bvl.drawLowered( 1, 1, w-2, h-2 );
prsLabel.drawText( xt, yt+1, strLabel );
break;
}
if (m_hasFocus) {
penBlack.setDashes(2,2);
penBlack.rectangle( wBorder-2, wBorder-2, maxW+4, maxH+5 );
}
}
void Button::onMouseButton(int nButton, bool isPush)
{
using std::endl;
if (nButton==1) {
if (isPush) {
m_state = Pushed;
trace << "Pushed" << endl;
invalidate();
} else {
if (m_state==Pushed) {
doAction( m_strAction );
invalidate();
}
m_state = Inactive;
trace << "Inactive" << endl;
}
}
}
void Button::onMouseEnter()
{
if (m_state==Released) {
m_state = Pushed;
trace << "Pushed" << std::endl;
invalidate();
}
}
void Button::onMouseExit()
{
if (m_state==Pushed) {
m_state = Released;
trace << "Released" << std::endl;
invalidate();
}
}
void Button::onGotFocus()
{
m_hasFocus = true;
invalidate();
}
void Button::onLostFocus()
{
m_hasFocus = false;
invalidate();
}
} // namespace