1 /*
2  * Copyright(c) 2016, OpenAV
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in
12  *       the documentation and/or other materials provided with the
13  *       distribution.
14  *     * Neither the name of the <organization> nor the
15  *       names of its contributors may be used to endorse or promote
16  *       products derived from this software without specific prior
17  *       written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENAV BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 
32 #include "dialog.hxx"
33 
34 #include "button.hxx"
35 #include "ui.hxx"
36 #include "theme.hxx"
37 
38 #include <stdio.h>
39 
40 using namespace Avtk;
41 
Dialog(Avtk::UI * ui,int x_,int y_,int w_,int h_,std::string label_)42 Dialog::Dialog( Avtk::UI* ui, int x_, int y_, int w_, int h_, std::string label_) :
43 	Group( ui, x_, y_, w_, h_, label_ )
44 {
45 	mx = my = -1;
46 
47 	ok     = new Button( ui, 0, 0, 60, 20, "OK" );
48 	cancel = new Button( ui, 0, 0, 60, 20, "Cancel" );
49 
50 	add( ok     );
51 	add( cancel );
52 
53 	visible_ = false;
54 
55 	end();
56 }
57 
draw(cairo_t * cr)58 void Dialog::draw( cairo_t* cr )
59 {
60 	cairo_save( cr );
61 
62 	// buttons_
63 	if( buttons_ == OK ) {
64 		ok->x( x_ + w_ * 0.8  );
65 		ok->y( y_ + h_ * 0.75 );
66 		ok->visible( true );
67 	} else if( buttons_ == OK_CANCEL ) {
68 		ok->x( x_ + w_ * 0.8 - 70  );
69 		ok->y( y_ + h_ * 0.75 );
70 		cancel->x( x_ + w_ * 0.8  );
71 		cancel->y( y_ + h_ * 0.75 );
72 		ok->visible( true );
73 		cancel->visible( true );
74 	}
75 
76 	if( mx != -1 || my != -1 ) {
77 		// get co-ords of the OK button, and find delta to mx/my
78 		int xd = mx - (ok->x()+ok->w()/2.f);
79 		int yd = my - (ok->y()+10);
80 
81 		// clip to *always* show entire dialog (aka, no "off-window" drawing)
82 		int diagX = x_ + xd;
83 		int diagY = y_ + yd;
84 
85 		// clip top left
86 		if( diagX < 0 ) diagX = 0;
87 		if( diagY < 0 ) diagY = 0;
88 
89 		// clip lower right
90 		if( diagX + w_ > ui->w() ) diagX = ui->w() - w_;
91 		if( diagY + h_ > ui->h() ) diagY = ui->h() - h_;
92 
93 		// set
94 		x( diagX );
95 		y( diagY );
96 	}
97 
98 	// transparent-out the *entire* UI
99 	cairo_rectangle( cr, 0, 0, ui->w(), ui->h() );
100 	//theme_->color( cr, BG_DARK, 0.8 );
101 	cairo_set_source_rgba( cr, 1, 1, 1, 0.2 );
102 	cairo_fill_preserve( cr );
103 	cairo_stroke( cr );
104 
105 	// draw diagonal lines
106 	int end = ui->w() + ui->h();
107 	for(int i = 0; i < end; i += 40 ) {
108 		cairo_move_to( cr,    -10,  i + 10 );
109 		cairo_line_to( cr, i + 10,     -10 );
110 	}
111 	theme_->color( cr, BG_DARK, 0.2 );
112 	//cairo_set_source_rgba( cr, 1, 1, 1, 0.2 );
113 	cairo_set_line_width( cr, 13 );
114 	cairo_stroke( cr );
115 
116 	// draw dark BG
117 	cairo_rectangle( cr, x_+1, y_+1, w_-2, h_-1 );
118 	theme_->color( cr, BG_DARK, 1 );
119 	cairo_fill_preserve( cr );
120 	cairo_set_line_width( cr, 1.0 );
121 	cairo_stroke( cr );
122 	theme_->color( cr, BG_DARK, 1 );
123 	cairo_select_font_face(cr, "impact", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
124 
125 	// draw header
126 	cairo_rectangle( cr, x_, y_, w_, 14 );
127 	theme_->color( cr, HIGHLIGHT, 1.0 );
128 	cairo_fill( cr );
129 
130 	/// TODO: get the dialog text amount, wrap based on text extents
131 	/// and draw buttons in Y position to not interfere with text
132 
133 	// show the header
134 	cairo_text_extents_t extents;
135 	cairo_set_font_size(cr, 10.0);
136 	cairo_text_extents(cr, label(), &extents);
137 	cairo_move_to(cr, x_ + 4, y_ + 7 + (extents.height / 2) );
138 	theme_->color( cr, BG_DARK, 1 );
139 	cairo_show_text( cr, label() );
140 
141 	// show the content
142 	cairo_set_font_size(cr, 12.0);
143 	cairo_text_extents(cr, contents.c_str(), &extents);
144 	cairo_move_to(cr, x_ + 4, y_  + 25 + 7 + (extents.height / 2) );
145 	//theme_->color( cr, BG_DARK, 1 );
146 	cairo_set_source_rgb( cr, 1,1,1 );
147 	cairo_show_text( cr, contents.c_str() );
148 
149 
150 	Group::draw( cr );
151 
152 	cairo_restore( cr );
153 }
154 
155 // to highjack the OK / Cancel buttons events
valueCB(Avtk::Widget * widget)156 void Dialog::valueCB( Avtk::Widget* widget)
157 {
158 	if( widget == ok ) {
159 		ui->handleOnly( 0x0 );
160 		visible( false );
161 		value( 1.f );
162 
163 		callback( this, ui );
164 	} else if( widget == cancel ) {
165 		ui->handleOnly( 0x0 );
166 		visible( false );
167 		value( 0.f );
168 
169 		callback( this, ui );
170 	} else {
171 		//printf("Dialog::widgetValueCB() widget %s\n", widget->label() );
172 	}
173 }
174 
run(const char * header,const char * text,BUTTONS b,int mx_,int my_)175 void Dialog::run( const char* header, const char* text, BUTTONS b, int mx_, int my_ )
176 {
177 	// show the dialog
178 	label( header );
179 	contents = text;
180 	buttons_ = b;
181 
182 	ok->value( false );
183 	cancel->value( false );
184 
185 	visible( true );
186 	// position to have OK/YES under mouse cursor. When -1, ignore
187 	mx = mx_;
188 	my = my_;
189 
190 	// make UI route all events to here, and wait for the valueCB to be called to
191 	// release the handleOnly
192 	ui->handleOnly( this );
193 }
194