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