2 Copyright 2013 Karel Matas
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <FL/Fl_Menu_Item.H>
20 #include "gui_dicview.hxx"
25 using utils::split_string
;
30 DicView::DicView ( int x
, int y
, int w
, int h
, const char *l
): Fl_Table_Row(x
,y
,w
,h
,l
)
32 when( FL_WHEN_RELEASE
|FL_WHEN_CHANGED
);
33 table_box( FL_NO_BOX
);
35 cb_leftclick( scb_general
, nullptr );
36 cb_rightclick( scb_general
, nullptr );
37 cb_doubleclick( scb_general
, nullptr );
38 cb_select( scb_general
, nullptr );
39 register_tag("default", TextStyle());;
40 register_tag("sep", TextStyle(TextStyle::SEPARATOR_SQUARE
) );
41 register_tag("br", TextStyle(TextStyle::NEWLINE_AFTER
));
43 headers_
= {"", "", ""};
50 void DicView::set_data ( const vector
<string
> &d
, const vector
<int> &cell_ids
)
52 // prevents division by zero
60 int c
= d
.size()/cols();
62 cell_heights_
.clear();
63 cell_heights_
.resize(d
.size());
66 if ( cell_ids
.empty() )
67 ids_
= vector
<int>(data_
.size(),-1);
68 // recalc cols and rows and redraw
69 draw_cell( CONTEXT_RC_RESIZE
, 0, 0, 0, 0 );
74 int DicView::draw_single_cell ( int R
, int C
, int X
, int Y
, int W
, int H
)
76 int cell
= R
*cols()+C
;
78 if ( cell
>= int(data_
.size()) ){
79 fl_push_clip(X
, Y
, W
, H
);
82 fl_color( Fl::get_color( FL_BACKGROUND2_COLOR
) );
94 fl_push_clip(X
, Y
, W
, H
);
97 fl_color( row_selected(R
) ? FL_LIGHT2
:FL_BACKGROUND2_COLOR
);
102 auto p
= utils::parse_markup(data_
.at(cell
).c_str());
103 string raw_string
= p
.first
;
104 auto tags
= p
.second
;
105 std::sort( tags
.begin(), tags
.end() );
106 std::multimap
<int,TextTag
> tmap
;
108 // fill gaps in tag ranges with default tag
109 for ( size_t i
=0; i
<tags
.size(); i
++ ) {
110 int prev_end
= (i
>0) ? tags
[i
-1].pos
+ tags
[i
-1].len
:0;
111 if ( prev_end
< tags
[i
].pos
)
112 tmap
.insert( { prev_end
, {"default", prev_end
, tags
[i
].pos
-prev_end
,
113 static_cast<int>(tmap
.size()+1)} } );
114 tmap
.insert( {tags
[i
].pos
, tags
[i
]} );
118 // apply default tag on whole string (if no other tags were defined)
119 int raw_len
= strlen(raw_string
.c_str());
121 tmap
.insert( { 0,{ "default", 0, raw_len
, -1 } } );
122 // create last default tag if neccessary
124 int pos
= tags
.back().pos
+ tags
.back().len
;
126 tmap
.insert( { pos
,{ "default", pos
, raw_len
-pos
,
127 static_cast<int>(tmap
.size()+1) }} );
130 for ( auto mi
= tmap
.begin(); mi
!= tmap
.end(); ++mi
){
132 // remove unneded default
133 if ( t
.tag
== "default" ){
134 auto bounds
= tmap
.equal_range( mi
->second
.pos
);
135 for( auto j
=bounds
.first
; j
!=bounds
.second
; j
++ ){
136 // XXX: ? nemuze se stat, ze bude 2x stejny default
137 if ( j
->second
.pos
== t
.pos
&& j
->second
.len
== t
.len
138 && j
->second
.tag
!= "default" )
146 tags
.push_back( t
.second
);
147 // XXX: ? sort tags by pos and id ? (torikaeru)
148 // std::sort( tags.begin(), tags.end(),
149 // []( const TextTag &a, const TextTag &b )
151 // char ba[8], bb[8];
152 // sprintf(ba,"%d.%d",a.pos,a.id);
153 // sprintf(bb,"%d.%d",b.pos,b.id);
154 // return atof(ba)<atof(bb); }
159 printf("\n\n************************************\n\n");
160 printf("%s\n",data_.at(cell).c_str());
161 printf("%s\n", raw_string.c_str() );
162 for ( auto t: tags ){
163 printf("[%3d] %10s pos: %2d len: %2d id: %2d '%s'\n",
164 t.pos, t.tag.c_str(), t.pos, t.len, t.id,
165 raw_string.substr(t.pos,t.len).c_str() );
169 // detect biggest font on the first line
170 // for the first line is better use font size instead of fl_height
171 // because the bigger font is, the bigger fl_height which leads to too
173 // (e.g. size=14 : fl_height=16, size=50 : fl_height=61)
175 auto mi
= tmap
.begin();
177 while ( total_w
< W
){
178 if ( mi
== tmap
.end() )
180 TextStyle
*style
= get_style(mi
->second
.tag
);
181 fl_font( style
->font
, int(font_size_
*style
->relsize
) );
182 int ffh
= style
->relsize
*font_size_
;
185 total_w
+= fl_width("m")*mi
->second
.len
;
189 // set values needed for calculations
190 int fx
= X
+ cell_padding_x();
191 fy
= Y
+ cell_padding_y() + fh
;
193 for ( auto t
: tags
){
194 // printf("%10s pos: %2zd len: %2zd '%s'\n",
195 // t.tag.c_str(), t.pos, t.len,raw_string.substr(t.pos,t.len).c_str() );
196 TextStyle
*style
= get_style(t
.tag
);
197 fl_font( style
->font
, int(font_size_
*style
->relsize
) );
198 fl_color( style
->color
);
200 int space_width
= fl_width(" ");
201 int fy_correction
= 0; // interline spacing when using subscript
204 // inserts: [SPACE]SQUARE[SPACE]
205 if ( style
->separator
!= TextStyle::SEPARATOR_NONE
){
206 Fl_Color prev_color
= fl_color();
207 fl_color( style
->color
);
208 int size
= ceil(fh
*0.4);
209 fl_rectf( fx
+ space_width
, fy
-size
, size
, size
);
210 fx
+= size
+ 2*space_width
;
211 fl_color( prev_color
);
215 // interline space when <sub>
216 if ( style
->offset_y
> fy_correction
)
217 fy_correction
= style
->offset_y
;
221 for ( auto &ss
: split_string( raw_string
.substr(t
.pos
,t
.len
), " " ) ) {
222 int swidth
= fl_width(ss
.c_str());
224 if ( fx
+swidth
-X
> W
-2*cell_padding_x() ){
225 fx
= X
+ cell_padding_x();
226 fy
+= fh
+ fy_correction
;
229 fl_draw( ss
.c_str(), fx
, fy
+ style
->offset_y
);
230 fx
+= swidth
+ space_width
;
233 if ( style
->newline
== TextStyle::NEWLINE_AFTER
){
234 fx
= X
+ cell_padding_x();
235 fy
+= fh
+ 2*fl_descent() + fy_correction
;
238 } // END: for tag in tags
241 fy
+= cell_padding_y_
; // empty space
243 // draw a line between rows (draw line above current cell)
245 fl_color( Fl::get_color( FL_FOREGROUND_COLOR
) );
246 fl_line(X
,Y
,X
+col_width(C
),Y
);
252 int this_height
= fy
-Y
+cell_padding_y();
253 cell_heights_
[R
*C
+C
] = this_height
;
255 if ( C
== cols()-1 ){
257 for ( int c
=0; c
<=C
; c
++ ){
258 int ch
= cell_heights_
[R
*c
+c
];
259 if ( ch
> max_height
)
262 if ( max_height
!= H
){
263 redraw_row(R
,max_height
);
271 void DicView::redraw_row ( int R
, int H
)
274 for ( int c
=0; c
<cols(); c
++ ){
279 find_cell( CONTEXT_CELL
, R
, c
, X
, Y
, W
, H
);
280 draw_single_cell(R
,c
,X
,Y
,W
,H
);
286 void DicView::draw_cell ( TableContext context
, int R
, int C
, int X
, int Y
, int W
, int H
)
290 case CONTEXT_STARTPAGE
:
291 fl_font( FL_HELVETICA
, font_size());
294 case CONTEXT_COL_HEADER
:
295 fl_push_clip(X
, Y
, W
, H
);
297 fl_draw_box(FL_THIN_UP_BOX
, X
, Y
, W
, H
, col_header_color());
298 fl_font( FL_HELVETICA
, 0.7*col_header_height() );
299 fl_color( FL_BLACK
);
300 if ( !headers_
.at(C
).empty() )
301 fl_draw( headers_
.at(C
).c_str(), X
+5, Y
+fl_height() );
309 draw_single_cell(R
,C
,X
,Y
,W
,H
);
314 case CONTEXT_RC_RESIZE
:
316 // adjust last column (sense) width
318 for ( int c
=0; c
<cols()-1; c
++ )
320 int scroll
= 1.2*vscrollbar
->w();
321 if ( !vscrollbar
->visible() )
323 col_width(cols()-1, w() - sum
- scroll
);
327 case CONTEXT_ROW_HEADER
:
328 case CONTEXT_ENDPAGE
:
336 int DicView::handle ( int event
)
341 int row
= row_at_y(Fl::event_y()-y());
342 if ( selected_row() == -1 )
348 int row
= row_at_y(Fl::event_y()-y());
351 // Fl::belowmouse() ensures that scrollbar will be still usable
352 if ( Fl::event_button() == FL_LEFT_MOUSE
&& Fl::belowmouse()==this ){
353 if ( Fl::event_clicks() > 1 )
354 cb_doubleclick(this);
359 else if ( Fl::event_button() == FL_RIGHT_MOUSE
){
366 if ( Fl::event_button() == FL_RIGHT_MOUSE
)
371 int row
= selected_row();
376 visible_cells(r1
,r2
,c1
,c2
);
379 else if ( row
<= r1
&& r1
> 0 )
382 switch ( Fl::event_key() ){
395 // Page Up/Down are handled by the vertical scrollbar
403 return Fl_Table_Row::handle(event
);