1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module w4d.widget.input.checkbox; 8 import w4d.layout.placer.lineup, 9 w4d.layout.fill, 10 w4d.parser.colorset, 11 w4d.style.color, 12 w4d.style.rect, 13 w4d.style.scalar, 14 w4d.style.widget, 15 w4d.task.window, 16 w4d.widget.base, 17 w4d.widget.text, 18 w4d.event, 19 w4d.exception; 20 import g4d.element.shape.border, 21 g4d.element.shape.regular, 22 g4d.ft.font, 23 g4d.glfw.cursor, 24 g4d.shader.base; 25 import gl3n.linalg; 26 import std.math; 27 28 /// A handler that handles changing checked. 29 alias CheckHandler = EventHandler!( void, bool ); 30 31 /// A widget of checkbox. 32 class CheckBoxWidget : Widget 33 { 34 protected class CheckMarkWidget : Widget 35 { 36 protected RegularNgonBorderElement!4 _border; 37 protected RegularNgonElement!4 _mark; 38 39 override @property vec2 wantedSize () 40 { 41 auto lineheight = _text.font.size.y; 42 return vec2( lineheight, lineheight ); 43 } 44 override @property const(Cursor) cursor () 45 { 46 return Cursor.Hand; 47 } 48 this () 49 { 50 super(); 51 52 _border = new RegularNgonBorderElement!4; 53 _mark = new RegularNgonElement!4; 54 55 style.box.size.width = Scalar.Auto; 56 style.box.size.height = Scalar.Auto; 57 } 58 override vec2 layout ( vec2 pos, vec2 size ) 59 { 60 scope(success) { 61 auto sz = style.box.clientSize.x; 62 _border.resize( sz/2, 1.5f ); 63 _mark .resize( sz/3 ); 64 } 65 return super.layout( pos, size ); 66 } 67 override void draw ( Window w, in ColorSet parent ) 68 { 69 super.draw( w, parent ); 70 71 auto shader = w.shaders.fill3; 72 const saver = ShaderStateSaver( shader ); 73 auto late = style.box.clientSize/2; 74 late += style.clientLeftTop; 75 76 shader.use(); 77 shader.matrix.late = vec3( late, 0 ); 78 shader.matrix.rota = vec3( 0, 0, PI/4 ); 79 shader.color = colorset.foreground; 80 _border.draw( shader ); 81 82 if ( checked ) { 83 _mark.draw( shader ); 84 } 85 } 86 override @property bool trackable () { return false; } 87 override @property bool focusable () { return false; } 88 } 89 90 protected CheckMarkWidget _mark; 91 protected TextWidget _text; 92 93 /// 94 override @property Widget[] children () 95 { 96 return [ _mark, _text ]; 97 } 98 99 protected bool _checked; 100 /// Checks if the checkbox is checked. 101 @property checked () { return _checked; } 102 103 /// 104 CheckHandler onCheck; 105 106 /// 107 override bool handleMouseButton ( MouseButton btn, bool status, vec2 pos ) 108 { 109 if ( super.handleMouseButton( btn, status, pos ) ) return true; 110 111 if ( !style.isPointInside(pos) ) return false; 112 113 if ( btn == MouseButton.Left && !status ) { 114 setChecked( !_checked ); 115 return true; 116 } 117 return false; 118 } 119 120 /// 121 this () 122 { 123 super(); 124 setLayout!( FillLayout, HorizontalLineupPlacer ); 125 126 _mark = new CheckMarkWidget; 127 _text = new TextWidget; 128 129 _checked = false; 130 131 parseColorSetsFromFile!"colorset/checkbox.yaml"( style ); 132 style.box.margins = Rect(1.mm); 133 style.box.borderWidth = Rect(1.pixel); 134 } 135 136 /// Changes checked. 137 void setChecked ( bool b ) 138 { 139 const temp = _checked; 140 _checked = b; 141 142 if ( _checked != temp ) { 143 onCheck.call( _checked ); 144 145 (_checked? &enableState: &disableState) 146 ( WidgetState.Selected ); 147 requestRedraw(); 148 } 149 } 150 151 /// Changes text. 152 void loadText ( dstring text, FontFace face = null ) 153 { 154 _text.loadText( text, face ); 155 } 156 157 /// 158 override const @property bool trackable () { return true; } 159 /// 160 override const @property bool focusable () { return true; } 161 }