47 namespace spin_details {
48 template <
class T> T mod(T, T);
49 template <
class T> T div(T, T);
83 Spin(
X x,
Y y,
X w, T value, T step, T min, T max,
bool edits,
const boost::shared_ptr<Font>& font,
Clr color,
113 virtual void Disable(
bool b =
true);
140 enum {BORDER_THICK = 2, PIXEL_MARGIN = 5};
160 void ConnectSignals();
162 void ValueUpdated(
const std::string& val_text);
163 void IncrImpl(
bool signal);
164 void DecrImpl(
bool signal);
165 void SetValueImpl(T value,
bool signal);
180 static void ValueChangedEcho(
const T& value);
200 Spin<T>::Spin(
X x,
Y y,
X w, T value, T step, T min, T max,
bool edits,
const boost::shared_ptr<Font>& font,
Clr color,
202 Control(x, y, w, font->Height() + 2 * PIXEL_MARGIN, flags),
213 Init(font, color, text_color, interior, flags);
215 if (INSTRUMENT_ALL_SIGNALS)
226 Pt edit_min = m_edit->MinUsableSize();
227 Pt up_min = m_up_button->MinUsableSize();
228 Pt down_min = m_down_button->MinUsableSize();
229 return Pt(edit_min.
x + std::max(up_min.
x, down_min.
x) + 2 * BORDER_THICK,
230 std::max(up_min.
y + down_min.
y, edit_min.
y) + 2 * BORDER_THICK);
239 {
return m_step_size; }
243 {
return m_min_value; }
247 {
return m_max_value; }
251 {
return m_editable; }
255 {
return m_button_width; }
259 {
return m_edit->TextColor(); }
263 {
return m_edit->InteriorColor(); }
267 {
return m_edit->HiliteColor(); }
271 {
return m_edit->SelectedTextColor(); }
277 Clr int_color_to_use = Disabled() ?
DisabledColor(InteriorColor()) : InteriorColor();
278 Pt ul = UpperLeft(), lr = LowerRight();
279 BeveledRectangle(ul, lr, int_color_to_use, color_to_use,
false, BORDER_THICK);
286 const X BUTTON_X_POS = Width() - m_button_width - BORDER_THICK;
287 const Y BUTTONS_HEIGHT = Height() - 2 * BORDER_THICK;
288 m_edit->SizeMove(
Pt(),
Pt(Width() - m_button_width, Height()));
289 m_up_button->SizeMove(
Pt(BUTTON_X_POS,
Y(BORDER_THICK)),
290 Pt(BUTTON_X_POS + m_button_width, BORDER_THICK + BUTTONS_HEIGHT / 2));
291 m_down_button->SizeMove(
Pt(BUTTON_X_POS, BORDER_THICK + BUTTONS_HEIGHT / 2),
292 Pt(BUTTON_X_POS + m_button_width, BORDER_THICK + BUTTONS_HEIGHT));
300 m_up_button->Disable(b);
301 m_down_button->Disable(b);
308 m_up_button->SetColor(c);
309 m_down_button->SetColor(c);
314 { SetValueImpl(m_value + m_step_size,
false); }
318 { SetValueImpl(m_value - m_step_size,
false); }
322 { SetValueImpl(value,
false); }
335 if (m_value < m_min_value)
336 SetValue(m_min_value);
343 if (m_max_value < m_value)
344 SetValue(m_max_value);
349 { m_edit->SetTextColor(c); }
355 if (Width() - 2 * BORDER_THICK - 1 < width)
356 width = Width() - 2 * BORDER_THICK - 1;
357 m_button_width = width;
358 SizeMove(RelativeUpperLeft(), RelativeLowerRight());
364 { m_edit->SetInteriorColor(c); }
368 { m_edit->SetHiliteColor(c); }
372 { m_edit->SetSelectedTextColor(c); }
376 {
return m_up_button; }
380 {
return m_down_button; }
391 SetValueImpl(m_min_value,
true);
394 SetValueImpl(m_max_value,
true);
416 for (
int i = 0; i < move; ++i) {
419 for (
int i = 0; i < -move; ++i) {
428 if (!m_editable && event.
Type() == WndEvent::GainingFocus) {
441 Connect(m_edit->FocusUpdateSignal, &Spin::ValueUpdated,
this);
442 Connect(m_up_button->ClickedSignal, boost::bind(&Spin::IncrImpl,
this,
true));
443 Connect(m_down_button->ClickedSignal, boost::bind(&Spin::DecrImpl,
this,
true));
447 void Spin<T>::Init(
const boost::shared_ptr<Font>& font, Clr color, Clr text_color, Clr interior, Flags<WndFlag> flags)
449 boost::shared_ptr<StyleFactory> style = GetStyleFactory();
451 m_edit = style->NewSpinEdit(X0, Y0, X1, boost::lexical_cast<std::string>(m_value), font, CLR_ZERO, text_color, interior);
452 boost::shared_ptr<Font> small_font =
GUI::GetGUI()->
GetFont(font, static_cast<int>(font->PointSize() * 0.75));
453 m_up_button = style->NewSpinIncrButton(X0, Y0, X1, Y1,
"+", small_font, color);
454 m_down_button = style->NewSpinDecrButton(X0, Y0, X1, Y1,
"-", small_font, color);
455 m_edit->InstallEventFilter(
this);
456 m_up_button->InstallEventFilter(
this);
457 m_down_button->InstallEventFilter(
this);
459 AttachChild(m_up_button);
460 AttachChild(m_down_button);
462 SizeMove(UpperLeft(), LowerRight());
466 void Spin<T>::ValueUpdated(
const std::string& val_text)
470 value = boost::lexical_cast<T>(val_text);
471 }
catch (boost::bad_lexical_cast) {
472 SetValueImpl(m_min_value,
true);
475 SetValueImpl(value,
true);
479 void Spin<T>::IncrImpl(
bool signal)
480 { SetValueImpl(static_cast<T>(m_value + m_step_size), signal); }
483 void Spin<T>::DecrImpl(
bool signal)
484 { SetValueImpl(static_cast<T>(m_value - m_step_size), signal); }
487 void Spin<T>::SetValueImpl(T value,
bool signal)
489 T old_value = m_value;
490 if (value < m_min_value) {
491 m_value = m_min_value;
492 }
else if (m_max_value < value) {
493 m_value = m_max_value;
496 if (std::abs(spin_details::mod(static_cast<T>(value - m_min_value), m_step_size)) >
497 std::numeric_limits<T>::epsilon()) {
501 spin_details::div(static_cast<T>(value - m_min_value), m_step_size) *
502 static_cast<T
>(m_step_size + m_min_value));
504 static_cast<T
>(closest_below + m_step_size);
506 ((value - closest_below) < (closest_above - value) ?
507 closest_below : closest_above);
513 if (signal && m_value != old_value)
514 ValueChangedSignal(m_value);
518 void Spin<T>::ValueChangedEcho(
const T& value)
519 { std::cerr <<
"GG SIGNAL : Spin<>::ValueChangedSignal(value=" << value <<
")\n"; }
522 namespace spin_details {
524 template <
class T>
inline
525 T mod (T dividend, T divisor) {
return static_cast<T
>(dividend % divisor);}
529 float mod<float> (
float dividend,
float divisor) {
return std::fmod(dividend, divisor);}
531 double mod<double> (
double dividend,
double divisor) {
return std::fmod(dividend, divisor);}
533 long double mod<long double> (
long double dividend,
long double divisor) {
return std::fmod(dividend, divisor);}
536 template <
class T>
inline
537 T div (T dividend, T divisor) {
return static_cast<T
>(dividend / divisor);}
541 float div<float> (
float dividend,
float divisor) {
return std::floor(dividend / divisor);}
543 double div<double> (
double dividend,
double divisor) {
return std::floor(dividend / divisor);}
545 long double div<long double> (
long double dividend,
long double divisor) {
return std::floor(dividend / divisor);}