| 214 | | m_default_font = new ASCIIBitmapFont(); |
|---|
| 215 | | |
|---|
| 216 | | bkg_color.set(212,208,200); |
|---|
| 217 | | text_color.set(0,0,0); |
|---|
| 218 | | |
|---|
| 219 | | sel_text_color.set(255,255,255); |
|---|
| 220 | | sel_text_bkg_color.set(10,36,106); |
|---|
| 221 | | sel_text_unfocus_bkg_color.set(176,176,176); |
|---|
| 222 | | |
|---|
| 223 | | hilite_color[0].set(64,64,64); |
|---|
| 224 | | hilite_color[1].set(128,128,128); |
|---|
| 225 | | hilite_color[2].set(255,255,255); |
|---|
| 226 | | |
|---|
| 227 | | m_bitmaps = new StdBitmapSet; |
|---|
| 228 | | |
|---|
| 229 | | // Some default colors |
|---|
| 230 | | set_background_color(Overlay.classinfo, Color(0,0,0,0)); |
|---|
| 231 | | } |
|---|
| 232 | | |
|---|
| 233 | | class ThemeData { |
|---|
| 234 | | Color[char[]] colors; |
|---|
| 235 | | } |
|---|
| 236 | | |
|---|
| 237 | | // Public interface functions for users |
|---|
| 238 | | Color get_theme_color(Widget w, char[] key, inout Color default_) { |
|---|
| 239 | | ThemeData td = get_theme_data(w); |
|---|
| 240 | | if (td && key in td.colors) { return td.colors[key]; } |
|---|
| 241 | | return get_theme_color(w.classinfo, key, default_); |
|---|
| 242 | | } |
|---|
| 243 | | Color get_theme_color(ClassInfo klass, char[] key, inout Color default_) { |
|---|
| 244 | | // Search parents too? |
|---|
| 245 | | ThemeData td = get_theme_data(klass); |
|---|
| 246 | | if (td && key in td.colors) { return td.colors[key]; } |
|---|
| 247 | | return default_; |
|---|
| 248 | | } |
|---|
| 249 | | |
|---|
| 250 | | Color get_background_color(Widget w) { |
|---|
| 251 | | return get_theme_color(w, "background", bkg_color); |
|---|
| 252 | | } |
|---|
| 253 | | Color get_background_color(ClassInfo klass) { |
|---|
| 254 | | return get_theme_color(klass, "background", bkg_color); |
|---|
| 255 | | } |
|---|
| 256 | | void set_background_color(Widget w, Color c) { |
|---|
| 257 | | getadd_theme_data(w).colors["background"] = c; |
|---|
| 258 | | } |
|---|
| 259 | | void set_background_color(ClassInfo klass, Color c) { |
|---|
| 260 | | getadd_theme_data(klass).colors["background"] = c; |
|---|
| 261 | | } |
|---|
| 262 | | |
|---|
| 263 | | //============================================================================ |
|---|
| 264 | | // Built-in Drawing and size routines |
|---|
| 265 | | |
|---|
| 266 | | //----HELPERS----------------------------------------------------------------- |
|---|
| 267 | | Font get_font() { return m_default_font; } |
|---|
| 268 | | bool set_color(float g) |
|---|
| 269 | | { |
|---|
| 270 | | glColor3f(g,g,g); |
|---|
| 271 | | return true; |
|---|
| 272 | | } |
|---|
| 273 | | bool set_color(Color c) |
|---|
| 274 | | { |
|---|
| 275 | | glColor4ubv(c.ptr); |
|---|
| 276 | | return c.a!=0; |
|---|
| 277 | | } |
|---|
| 278 | | |
|---|
| 279 | | //---------------------------------------------------------------------- |
|---|
| 280 | | ThemeData get_theme_data(Widget w) { |
|---|
| 281 | | Object td=null; |
|---|
| 282 | | if (w && (td=w.theme_instance_data)!is null) { |
|---|
| 283 | | return cast(ThemeData)td; |
|---|
| 284 | | } |
|---|
| 285 | | return null; |
|---|
| 286 | | } |
|---|
| 287 | | ThemeData getadd_theme_data(Widget w) { |
|---|
| 288 | | Object td; |
|---|
| 289 | | if (w && (td=w.theme_instance_data)!is null) { |
|---|
| 290 | | return cast(ThemeData)td; |
|---|
| 291 | | } |
|---|
| 292 | | else { |
|---|
| 293 | | ThemeData td2 = new ThemeData; |
|---|
| 294 | | w.theme_instance_data = td2; |
|---|
| 295 | | return td2; |
|---|
| 296 | | } |
|---|
| 297 | | } |
|---|
| 298 | | ThemeData add_theme_data(Widget w) { |
|---|
| 299 | | ThemeData td = new ThemeData; |
|---|
| 300 | | w.theme_instance_data = td; |
|---|
| 301 | | return td; |
|---|
| 302 | | } |
|---|
| 303 | | |
|---|
| 304 | | ThemeData get_theme_data(ClassInfo klass) { |
|---|
| 305 | | if (klass in m_classThemeData) { |
|---|
| 306 | | return m_classThemeData[klass]; |
|---|
| 307 | | } |
|---|
| 308 | | return null; |
|---|
| 309 | | } |
|---|
| 310 | | ThemeData getadd_theme_data(ClassInfo klass) { |
|---|
| 311 | | if (klass in m_classThemeData) { |
|---|
| 312 | | return m_classThemeData[klass]; |
|---|
| 313 | | } |
|---|
| 314 | | else { |
|---|
| 315 | | ThemeData td = new ThemeData; |
|---|
| 316 | | m_classThemeData[klass] = td; |
|---|
| 317 | | return td; |
|---|
| 318 | | } |
|---|
| 319 | | } |
|---|
| 320 | | ThemeData add_theme_data(ClassInfo klass) { |
|---|
| 321 | | ThemeData td = new ThemeData; |
|---|
| 322 | | m_classThemeData[klass] = td; |
|---|
| 323 | | return td; |
|---|
| 324 | | } |
|---|
| 325 | | //---------------------------------------------------------------------- |
|---|
| 326 | | |
|---|
| 327 | | |
|---|
| 328 | | void draw_text_plain(char[] label, float x, float y) |
|---|
| 329 | | { |
|---|
| 330 | | alias m_default_font font; |
|---|
| 331 | | Point trans = font.origin; trans.x+=x; trans.y+=y; |
|---|
| 332 | | translate(trans); |
|---|
| 333 | | font.draw_string(label); |
|---|
| 334 | | untranslate(trans); |
|---|
| 335 | | } |
|---|
| 336 | | |
|---|
| 337 | | /** Draw text so the upper left corner is at (x,y) */ |
|---|
| 338 | | void draw_text(char[] label, float x, float y, bool enabled=true) |
|---|
| 339 | | { |
|---|
| 340 | | alias m_default_font font; |
|---|
| 341 | | Point trans = font.origin; trans.x+=x; trans.y+=y; |
|---|
| 342 | | translate(trans); |
|---|
| 343 | | if (!enabled) { |
|---|
| 344 | | set_color( hilite_color[2] ); |
|---|
| 345 | | translate(1,1); |
|---|
| 346 | | font.draw_string(label); |
|---|
| 347 | | translate(-1,-1); |
|---|
| 348 | | } |
|---|
| 349 | | set_color( enabled ? text_color : hilite_color[0] ); |
|---|
| 350 | | font.draw_string(label); |
|---|
| 351 | | untranslate(trans); |
|---|
| 352 | | } |
|---|
| 353 | | |
|---|
| 354 | | /** Draw text so the first character's origin is at x,y. Not so useful. */ |
|---|
| 355 | | void draw_label_text(char[] label, float x, float y, bool enabled=true) |
|---|
| 356 | | { |
|---|
| 357 | | alias m_default_font font; |
|---|
| 358 | | translate(x,y); |
|---|
| 359 | | if (!enabled) { |
|---|
| 360 | | set_color( hilite_color[2] ); |
|---|
| 361 | | translate(1,1); |
|---|
| 362 | | font.draw_string(label); |
|---|
| 363 | | translate(-1,-1); |
|---|
| 364 | | } |
|---|
| 365 | | set_color( enabled ? text_color : hilite_color[0] ); |
|---|
| 366 | | font.draw_string(label); |
|---|
| 367 | | translate(-x,-y); |
|---|
| 368 | | } |
|---|
| 369 | | |
|---|
| 370 | | |
|---|
| 371 | | //----OVERLAY----------------------------------------------------------------- |
|---|
| 372 | | void begin_drawing(Rect r) { |
|---|
| 373 | | gldraw.push_graphics_state(r); |
|---|
| 374 | | } |
|---|
| 375 | | void end_drawing() { |
|---|
| 376 | | gldraw.pop_graphics_state(); |
|---|
| 377 | | } |
|---|
| 378 | | //----PANEL------------------------------------------------------------------- |
|---|
| 379 | | void panel_register() { |
|---|
| 380 | | m_drawFuncs.add(Panel.classinfo, &panel_draw); |
|---|
| 381 | | } |
|---|
| 382 | | |
|---|
| 383 | | void panel_draw(Widget widget) { |
|---|
| 384 | | auto w = cast(Panel)widget; assert(w); |
|---|
| 385 | | if (set_color(get_background_color(widget))) |
|---|
| 386 | | fill_rect(w.rect); |
|---|
| 387 | | } |
|---|
| 388 | | |
|---|
| 389 | | //----LABEL------------------------------------------------------------------- |
|---|
| 390 | | void label_register() { |
|---|
| 391 | | addHandlers!(Label)(&label_draw, &label_best_size); |
|---|
| 392 | | } |
|---|
| 393 | | Size label_best_size(Widget widget, Size bounds) { |
|---|
| 394 | | auto w = cast(Label)widget; assert(w); |
|---|
| 395 | | Rect r = m_default_font.string_rect(w.label); |
|---|
| 396 | | return Size(r.width+2,r.height+2); |
|---|
| 397 | | } |
|---|
| 398 | | void label_draw(Widget widget) { |
|---|
| 399 | | auto w = cast(Label)widget; assert(w); |
|---|
| 400 | | set_color(get_background_color(widget)); |
|---|
| 401 | | fill_rect(w.rect); |
|---|
| 402 | | with (w) { |
|---|
| 403 | | alias m_default_font f; |
|---|
| 404 | | |
|---|
| 405 | | Rect sr = f.string_rect(label); |
|---|
| 406 | | |
|---|
| 407 | | float x = w.rect.x + min(0.0,(w.rect.w-sr.w)/2); |
|---|
| 408 | | float y = w.rect.y + min(0.0,(w.rect.h-sr.h)/2); |
|---|
| 409 | | draw_text(label,x,y,enabled); |
|---|
| 410 | | } |
|---|
| 411 | | } |
|---|
| 412 | | |
|---|
| 413 | | //----BUTTON------------------------------------------------------------------ |
|---|
| 414 | | void button_register() { |
|---|
| 415 | | addHandlers!(Button)(&button_draw, &button_best_size, &button_min_size); |
|---|
| 416 | | } |
|---|
| 417 | | Size button_min_size(Widget widget, Size bounds) { |
|---|
| 418 | | auto w = cast(Button)widget; assert(w); |
|---|
| 419 | | Rect r = m_default_font.string_rect(w.label); |
|---|
| 420 | | return Size(r.width+5,r.height+5); |
|---|
| 421 | | } |
|---|
| 422 | | Size button_best_size(Widget widget, Size bounds) { |
|---|
| 423 | | auto w = cast(Button)widget; assert(w); |
|---|
| 424 | | Size minsz = button_min_size(w,bounds); |
|---|
| 425 | | return Size(max(50.,minsz.w), max(22.,minsz.h)); |
|---|
| 426 | | } |
|---|
| 427 | | void button_draw(Widget widget) { |
|---|
| 428 | | auto w = cast(Button)widget; assert(w); |
|---|
| 429 | | with (w) { |
|---|
| 430 | | alias m_default_font f; |
|---|
| 431 | | |
|---|
| 432 | | set_color(get_background_color(widget)); |
|---|
| 433 | | fill_rect(rect); |
|---|
| 434 | | if (w.depressed) { |
|---|
| 435 | | stroke_sunken_rect( |
|---|
| 436 | | rect,bkg_color,hilite_color[0],hilite_color[1],hilite_color[2] |
|---|
| 437 | | ); |
|---|
| 438 | | } else { |
|---|
| 439 | | stroke_raised_rect( |
|---|
| 440 | | rect,bkg_color,hilite_color[0],hilite_color[1],hilite_color[2] |
|---|
| 441 | | ); |
|---|
| 442 | | } |
|---|
| 443 | | |
|---|
| 444 | | Rect sr = f.string_rect(label); |
|---|
| 445 | | |
|---|
| 446 | | float shift = w.depressed?1:0; |
|---|
| 447 | | float x = w.rect.x+(w.rect.w-sr.w)/2 + shift; |
|---|
| 448 | | float y = w.rect.y+(w.rect.h-sr.h)/2 + shift; |
|---|
| 449 | | draw_text(label, x, y, enabled); |
|---|
| 450 | | |
|---|
| 451 | | if (w.focused()) { |
|---|
| 452 | | set_color(hilite_color[0]); |
|---|
| 453 | | Rect r = w.rect(); |
|---|
| 454 | | r.inset(3); |
|---|
| 455 | | glEnable(GL_LINE_STIPPLE); |
|---|
| 456 | | glLineStipple( 1, 0x5555 ); |
|---|
| 457 | | stroke_rect(r); |
|---|
| 458 | | glDisable(GL_LINE_STIPPLE); |
|---|
| 459 | | } |
|---|
| 460 | | } |
|---|
| 461 | | } |
|---|
| 462 | | |
|---|
| 463 | | //----CHECKBOX---------------------------------------------------------------- |
|---|
| 464 | | void checkbox_register() { |
|---|
| 465 | | addHandlers!(Checkbox)(&checkbox_draw, &checkbox_best_size); |
|---|
| 466 | | } |
|---|
| 467 | | //Size checkbox_min_size(Widget widget, Size bounds) { |
|---|
| 468 | | // auto w = cast(Checkbox)widget; assert(w); |
|---|
| 469 | | // return Size(0,0); |
|---|
| 470 | | //} |
|---|
| 471 | | Size checkbox_best_size(Widget widget, Size bounds) { |
|---|
| 472 | | // Drawing basics |
|---|
| 473 | | // [x] the label string |
|---|
| 474 | | // we want 2 pixel clearance around string, 1 pixel around box |
|---|
| 475 | | |
|---|
| 476 | | auto w = cast(Checkbox)widget; assert(w); |
|---|
| 477 | | Size cbsize = m_bitmaps[StdBitmaps.Checkbox_On].size; |
|---|
| 478 | | Size text_size = m_default_font.string_rect( w.label ).size; |
|---|
| 479 | | Size sz; |
|---|
| 480 | | sz.width = (cbsize.width+2) + (text_size.width+4); |
|---|
| 481 | | sz.height = max(cbsize.height+2, text_size.height+4); |
|---|
| 482 | | return sz; |
|---|
| 483 | | } |
|---|
| 484 | | void checkbox_draw(Widget widget) { |
|---|
| 485 | | alias m_default_font font; |
|---|
| 486 | | auto w = cast(Checkbox)widget; assert(w); |
|---|
| 487 | | set_color(get_background_color(widget)); |
|---|
| 488 | | fill_rect(w.rect); |
|---|
| 489 | | with (w) |
|---|
| 490 | | { |
|---|
| 491 | | Size cbsize = m_bitmaps[StdBitmaps.Checkbox_On].size; |
|---|
| 492 | | Point cbpos = rect.pos; |
|---|
| 493 | | cbpos.x += 1; |
|---|
| 494 | | cbpos.y = rect.y+(rect.h-cbsize.h)/2; |
|---|
| 495 | | if (value != 0 ^ depressed) { |
|---|
| 496 | | if ( enabled ) |
|---|
| 497 | | m_bitmaps.draw( StdBitmaps.Checkbox_On, cbpos ); |
|---|
| 498 | | else |
|---|
| 499 | | m_bitmaps.draw( StdBitmaps.Checkbox_On_Dis, cbpos ); |
|---|
| 500 | | } |
|---|
| 501 | | else { |
|---|
| 502 | | if ( enabled ) |
|---|
| 503 | | m_bitmaps.draw( StdBitmaps.Checkbox_Off, cbpos ); |
|---|
| 504 | | else |
|---|
| 505 | | m_bitmaps.draw( StdBitmaps.Checkbox_Off_Dis, cbpos ); |
|---|
| 506 | | } |
|---|
| 507 | | |
|---|
| 508 | | Rect text_rect = font.string_rect( label ); |
|---|
| 509 | | text_rect.x = rect.x + (cbsize.w+2)+2; |
|---|
| 510 | | text_rect.y = rect.y + 2; |
|---|
| 511 | | { |
|---|
| 512 | | if ( focused ) { |
|---|
| 513 | | glEnable( GL_LINE_STIPPLE ); |
|---|
| 514 | | glLineStipple( 1, 0x5555 ); |
|---|
| 515 | | set_color( hilite_color[0] ); |
|---|
| 516 | | |
|---|
| 517 | | Rect focus_rect = text_rect; |
|---|
| 518 | | focus_rect.inset(-1); |
|---|
| 519 | | stroke_rect(focus_rect); |
|---|
| 520 | | |
|---|
| 521 | | glDisable( GL_LINE_STIPPLE ); |
|---|
| 522 | | } |
|---|
| 523 | | } |
|---|
| 524 | | |
|---|
| 525 | | draw_text( label, text_rect.x, text_rect.y, enabled); |
|---|
| 526 | | } |
|---|
| 527 | | } |
|---|
| 528 | | |
|---|
| 529 | | //----TEXTFIELD------------------------------------------------------------- |
|---|
| 530 | | void textfield_register() { |
|---|
| 531 | | addHandlers!(TextField)(&textfield_draw, &textfield_best_size, &textfield_min_size); |
|---|
| 532 | | addEventHandlers!(TextField)(&textfield_mouse_button, &textfield_mouse_move); |
|---|
| 533 | | } |
|---|
| 534 | | const int textfield_base_scroll = 3; |
|---|
| 535 | | |
|---|
| 536 | | /** Returns a double indicating the position of the x value. |
|---|
| 537 | | If exactly on a char boundary then the return value will be |
|---|
| 538 | | integral, if right in the middle of a character it will be |
|---|
| 539 | | 0.5 offset from an integer. |
|---|
| 540 | | */ |
|---|
| 541 | | void textfield_get_rects(TextField w, inout Rect entry, inout Rect txt) |
|---|
| 542 | | { |
|---|
| 543 | | entry = w.rect; |
|---|
| 544 | | entry.y+=1; |
|---|
| 545 | | entry.h-=2; |
|---|
| 546 | | txt = entry; |
|---|
| 547 | | txt.inset(1); txt.w-=1; txt.h-=1; |
|---|
| 548 | | } |
|---|
| 549 | | float textfield_get_char_pos(TextField txtf, float clickx) |
|---|
| 550 | | { |
|---|
| 551 | | Rect entry_rect,inside_rect; |
|---|
| 552 | | textfield_get_rects(txtf, entry_rect, inside_rect); |
|---|
| 553 | | alias m_default_font font; |
|---|
| 554 | | float offset = inside_rect.x + textfield_base_scroll + txtf.xscroll_offset; |
|---|
| 555 | | float x = offset; |
|---|
| 556 | | float lastx = x-10; |
|---|
| 557 | | int imax = txtf.text.length; |
|---|
| 558 | | // binary search would of course be better here |
|---|
| 559 | | int i; |
|---|
| 560 | | for(i=0; x<clickx && i<imax; x=offset+font.string_rect(txtf.text[0..++i]).w) |
|---|
| 561 | | { |
|---|
| 562 | | lastx = x; |
|---|
| 563 | | } |
|---|
| 564 | | if (i==0) return 0; |
|---|
| 565 | | else if (i>=imax) return imax; |
|---|
| 566 | | |
|---|
| 567 | | float frac = (clickx-lastx)/(x-lastx); |
|---|
| 568 | | return i-1.0+frac; |
|---|
| 569 | | |
|---|
| 570 | | } |
|---|
| 571 | | Size textfield_min_size(Widget widget, Size bounds) { |
|---|
| 572 | | auto w = cast(TextField)widget; assert(w); |
|---|
| 573 | | Size sz = Size(20,2); |
|---|
| 574 | | return sz; |
|---|
| 575 | | } |
|---|
| 576 | | Size textfield_best_size(Widget widget, Size bounds) { |
|---|
| 577 | | auto w = cast(TextField)widget; assert(w); |
|---|
| 578 | | Size sz = textfield_min_size(w,bounds); |
|---|
| 579 | | return Size(max(130.,sz.x),max(20.,sz.h)); |
|---|
| 580 | | } |
|---|
| 581 | | void textfield_draw(Widget widget) |
|---|
| 582 | | { |
|---|
| 583 | | auto txtf = cast(TextField)widget; assert(txtf); |
|---|
| 584 | | set_color(get_background_color(widget)); |
|---|
| 585 | | fill_rect(txtf.rect); |
|---|
| 586 | | translate(txtf.rect.x, txtf.rect.y); |
|---|
| 587 | | |
|---|
| 588 | | alias m_default_font font; |
|---|
| 589 | | with (txtf) { |
|---|
| 590 | | Rect entry_rect,inside_rect; |
|---|
| 591 | | textfield_get_rects(txtf, entry_rect, inside_rect); |
|---|
| 592 | | entry_rect.pos -= rect.pos; |
|---|
| 593 | | inside_rect.pos -= rect.pos; |
|---|
| 594 | | |
|---|
| 595 | | set_color(hilite_color[2]); |
|---|
| 596 | | fill_rect( entry_rect ); |
|---|
| 597 | | |
|---|
| 598 | | // Find where to draw the text |
|---|
| 599 | | |
|---|
| 600 | | // Clip to insides of entry rect |
|---|
| 601 | | push_clip_rect( inside_rect ); |
|---|
| 602 | | |
|---|
| 603 | | float offset = inside_rect.x + textfield_base_scroll + xscroll_offset; |
|---|
| 604 | | float sel_offset = font.string_rect(text[0..sel_begin]).width; |
|---|
| 605 | | Size sel_size = font.string_rect(text[sel_begin..sel_end]).size; |
|---|
| 606 | | |
|---|
| 607 | | // make sure active end of selection is visible |
|---|
| 608 | | { |
|---|
| 609 | | float sel_x = offset + sel_offset; |
|---|
| 610 | | if (sel_active==1) sel_x += sel_size.width; |
|---|
| 611 | | float dx; |
|---|
| 612 | | if ((dx=sel_x-inside_rect.x)<0) { |
|---|
| 613 | | offset-=dx-2; xscroll_offset-=dx-2; |
|---|
| 614 | | } |
|---|
| 615 | | else if ((dx=sel_x-inside_rect.x2)>0) { |
|---|
| 616 | | offset-=dx+1; xscroll_offset-=dx+1; |
|---|
| 617 | | } |
|---|
| 618 | | } |
|---|
| 619 | | |
|---|
| 620 | | if (selection_length) |
|---|
| 621 | | { |
|---|
| 622 | | Rect rsel; |
|---|
| 623 | | rsel.x = offset + sel_offset; |
|---|
| 624 | | rsel.y = 4; |
|---|
| 625 | | rsel.size = sel_size; |
|---|
| 626 | | |
|---|
| 627 | | // draw unselected first part of text |
|---|
| 628 | | if (sel_begin!=0) { |
|---|
| 629 | | draw_text(text[0..sel_begin], offset, inside_rect.y); |
|---|
| 630 | | offset += sel_offset; |
|---|
| 631 | | } |
|---|
| 632 | | |
|---|
| 633 | | // Draw selection bkg |
|---|
| 634 | | if (focused) { |
|---|
| 635 | | set_color(sel_text_bkg_color); |
|---|
| 636 | | } else { |
|---|
| 637 | | set_color(sel_text_unfocus_bkg_color); |
|---|
| 638 | | } |
|---|
| 639 | | fill_rect( rsel ); |
|---|
| 640 | | |
|---|
| 641 | | // draw selected text |
|---|
| 642 | | set_color(sel_text_color); |
|---|
| 643 | | draw_text_plain(text[sel_begin..sel_end], |
|---|
| 644 | | offset, |
|---|
| 645 | | inside_rect.y); |
|---|
| 646 | | offset += rsel.width; |
|---|
| 647 | | |
|---|
| 648 | | // draw rest of unselected text |
|---|
| 649 | | if (sel_end!=text.length) { |
|---|
| 650 | | draw_text(text[sel_end..$], offset, inside_rect.y); |
|---|
| 651 | | } |
|---|
| 652 | | } |
|---|
| 653 | | else { |
|---|
| 654 | | // Draw all the text in one go |
|---|
| 655 | | draw_text(text, offset, inside_rect.y); |
|---|
| 656 | | } |
|---|
| 657 | | |
|---|
| 658 | | // Draw some outline rects; |
|---|
| 659 | | float w = rect.width-1; |
|---|
| 660 | | float h = rect.height-1; |
|---|
| 661 | | |
|---|
| 662 | | // Caret |
|---|
| 663 | | if ( enabled && selection_length == 0 ) { |
|---|
| 664 | | if (focused && selection_length==0) |
|---|
| 665 | | { |
|---|
| 666 | | float x = offset + sel_offset; |
|---|
| 667 | | set_color(hilite_color[0]); |
|---|
| 668 | | glBegin( GL_LINE_LOOP ); |
|---|
| 669 | | glVertex2f( x, 0 + 4 ); |
|---|
| 670 | | glVertex2f( x, 0 + 4 ); |
|---|
| 671 | | glVertex2f( x, 0 + h - 3 ); |
|---|
| 672 | | glVertex2f( x, 0 + h - 3 ); |
|---|
| 673 | | glEnd(); |
|---|
| 674 | | } |
|---|
| 675 | | } |
|---|
| 676 | | pop_clip_rect(); |
|---|
| 677 | | |
|---|
| 678 | | translate(0.5,0.5); |
|---|
| 679 | | glBegin( GL_LINES ); |
|---|
| 680 | | set_color(hilite_color[1]); |
|---|
| 681 | | glVertex2f( entry_rect.x, 0 ); glVertex2f( w, 0 ); |
|---|
| 682 | | glVertex2f( entry_rect.x, 0 ); glVertex2f( entry_rect.x, h ); |
|---|
| 683 | | |
|---|
| 684 | | set_color(hilite_color[2]); |
|---|
| 685 | | glVertex2f( entry_rect.x, h ); glVertex2f( w, h ); |
|---|
| 686 | | glVertex2f( w, h ); glVertex2f( w, 0 ); |
|---|
| 687 | | |
|---|
| 688 | | if ( enabled ) |
|---|
| 689 | | set_color( hilite_color[0] ); |
|---|
| 690 | | else |
|---|
| 691 | | set_color( .25 ); |
|---|
| 692 | | |
|---|
| 693 | | glVertex2f( entry_rect.x+1, 1 ); glVertex2f( w-1, 1 ); |
|---|
| 694 | | glVertex2f( entry_rect.x+1, 1 ); glVertex2f( entry_rect.x+1, h-2 ); |
|---|
| 695 | | |
|---|
| 696 | | set_color( .75 ); |
|---|
| 697 | | glVertex2f( entry_rect.x+1, h-1 ); glVertex2f( w-1, h-1 ); |
|---|
| 698 | | glVertex2f( w-1, h-1 ); glVertex2f( w-1, 1 ); |
|---|
| 699 | | glEnd(); |
|---|
| 700 | | translate(-0.5,-0.5); |
|---|
| 701 | | } |
|---|
| 702 | | translate(-widget.rect.x, -widget.rect.y); |
|---|
| 703 | | } |
|---|
| 704 | | void textfield_mouse_button(Widget widget, MouseButtonEvent ev) |
|---|
| 705 | | { |
|---|
| 706 | | if (ev.is_left) |
|---|
| 707 | | { |
|---|
| 708 | | auto txtf = cast(TextField)widget; assert(txtf); |
|---|
| 709 | | if (ev.is_press) { |
|---|
| 710 | | float fselpos = textfield_get_char_pos(txtf, ev.x); |
|---|
| 711 | | int pos = lrint(fselpos); |
|---|
| 712 | | if (ev.shift_down) { |
|---|
| 713 | | int[2] sel=txtf.sel_range[]; |
|---|
| 714 | | sel[txtf.sel_active] = pos; |
|---|
| 715 | | txtf.select_range(sel[0],sel[1]); |
|---|
| 716 | | } |
|---|
| 717 | | else { |
|---|
| 718 | | txtf.select_range(pos,pos); |
|---|
| 719 | | } |
|---|
| 720 | | txtf.grab_mouse(); |
|---|
| 721 | | } |
|---|
| 722 | | else if (ev.is_release) { |
|---|
| 723 | | if (txtf.is_grabbing_mouse) txtf.release_mouse(); |
|---|
| 724 | | } |
|---|
| 725 | | } |
|---|
| 726 | | } |
|---|
| 727 | | void textfield_mouse_move(Widget widget, MouseMoveEvent ev) |
|---|
| 728 | | { |
|---|
| 729 | | if (ev.left_down) { |
|---|
| 730 | | auto txtf = cast(TextField)widget; assert(txtf); |
|---|
| 731 | | float fselpos = textfield_get_char_pos(txtf, ev.x); |
|---|
| 732 | | int pos = lrint(fselpos); |
|---|
| 733 | | int[2] sel=txtf.sel_range[]; |
|---|
| 734 | | sel[txtf.sel_active] = pos; |
|---|
| 735 | | txtf.select_range(sel[0],sel[1]); |
|---|
| 736 | | } |
|---|
| 737 | | } |
|---|
| 738 | | |
|---|
| 739 | | |
|---|
| 740 | | //----SLIDER---------------------------------------------------------------- |
|---|
| 741 | | void slider_register() { |
|---|
| 742 | | addHandlers!(Slider)(&slider_draw, &slider_best_size, &slider_min_size); |
|---|
| 743 | | addEventHandlers!(Slider)(&slider_mouse_button, &slider_mouse_move); |
|---|
| 744 | | } |
|---|
| 745 | | |
|---|
| 746 | | static const int scroll_thumb_w = 8; |
|---|
| 747 | | static const int scroll_thumb_h = 18; |
|---|
| 748 | | static const int slider_track_inset = 2; |
|---|
| 749 | | Size slider_min_size(Widget widget, Size bounds) { |
|---|
| 750 | | auto w = cast(Slider)widget; assert(w); |
|---|
| 751 | | Size sz = Size(scroll_thumb_w+20, scroll_thumb_h+5); |
|---|
| 752 | | if (w.vertical) { |
|---|
| 753 | | return Size(sz.h,sz.w); |
|---|
| 754 | | } |
|---|
| 755 | | return sz; |
|---|
| 756 | | } |
|---|
| 757 | | Size slider_best_size(Widget widget, Size bounds) { |
|---|
| 758 | | auto w = cast(Slider)widget; assert(w); |
|---|
| 759 | | Size sz = Size(100,scroll_thumb_h+5); |
|---|
| 760 | | if (w.vertical) { |
|---|
| 761 | | return Size(sz.h,sz.w); |
|---|
| 762 | | } |
|---|
| 763 | | return sz; |
|---|
| 764 | | } |
|---|
| 765 | | void slider_draw(Widget widget) { |
|---|
| 766 | | auto w = cast(Slider)widget; assert(w); |
|---|
| 767 | | set_color(get_background_color(widget)); |
|---|
| 768 | | fill_rect(w.rect); |
|---|
| 769 | | translate(widget.rect.pos); scope(exit) untranslate(widget.rect.pos); |
|---|
| 770 | | { |
|---|
| 771 | | Rect rect = w.rect; |
|---|
| 772 | | |
|---|
| 773 | | const int tw = slider_track_inset; |
|---|
| 774 | | Rect rtrack; |
|---|
| 775 | | if (w.horizontal) { |
|---|
| 776 | | float ctr = 0.5*(rect.h); |
|---|
| 777 | | rtrack.set(tw, ctr-tw, rect.w-tw-tw, tw+tw); |
|---|
| 778 | | } else { |
|---|
| 779 | | float ctr = 0.5*(rect.w); |
|---|
| 780 | | rtrack.set(ctr-tw, tw, tw+tw, rect.h-tw-tw); |
|---|
| 781 | | } |
|---|
| 782 | | stroke_sunken_rect( |
|---|
| 783 | | rtrack, bkg_color,hilite_color[0],hilite_color[1],hilite_color[2]); |
|---|
| 784 | | |
|---|
| 785 | | Rect rthumb; float vpos; |
|---|
| 786 | | float t = w.value/(w.value_max-w.value_min); |
|---|
| 787 | | if (w.horizontal) { |
|---|
| 788 | | rthumb.size = Size(scroll_thumb_w,scroll_thumb_h); |
|---|
| 789 | | vpos = tw + t*(rtrack.w-rthumb.w); |
|---|
| 790 | | rthumb.x = lrint(vpos); |
|---|
| 791 | | rthumb.y = lrint(rect.h-rthumb.h)/2; |
|---|
| 792 | | } |
|---|
| 793 | | else { |
|---|
| 794 | | rthumb.size = Size(scroll_thumb_h,scroll_thumb_w); |
|---|
| 795 | | vpos = tw+(1-t)*(rtrack.h-rthumb.h); |
|---|
| 796 | | rthumb.x = lrint(rect.w-rthumb.w)/2; |
|---|
| 797 | | rthumb.y = lrint(vpos); |
|---|
| 798 | | } |
|---|
| 799 | | set_color(bkg_color); |
|---|
| 800 | | fill_rect(rthumb); |
|---|
| 801 | | stroke_raised_rect( |
|---|
| 802 | | rthumb, bkg_color,hilite_color[0],hilite_color[1],hilite_color[2]); |
|---|
| 803 | | |
|---|
| 804 | | if (w.focused()) { |
|---|
| 805 | | set_color(hilite_color[0]); |
|---|
| 806 | | Rect r = rtrack; |
|---|
| 807 | | r.enclose(rthumb); |
|---|
| 808 | | r.inset(-2); |
|---|
| 809 | | glEnable(GL_LINE_STIPPLE); |
|---|
| 810 | | glLineStipple( 1, 0x5555 ); |
|---|
| 811 | | stroke_rect(r); |
|---|
| 812 | | glDisable(GL_LINE_STIPPLE); |
|---|
| 813 | | } |
|---|
| 814 | | } |
|---|
| 815 | | } |
|---|
| 816 | | |
|---|
| 817 | | double slider_map_mouse_to_value(Slider w, Point p) |
|---|
| 818 | | { |
|---|
| 819 | | double t; |
|---|
| 820 | | const int tw = slider_track_inset; |
|---|
| 821 | | if (w.horizontal) { |
|---|
| 822 | | double trackmin = w.rect.x + tw; |
|---|
| 823 | | double trackmax = w.rect.x2 - tw*2; |
|---|
| 824 | | t = (p.x-trackmin)/(trackmax-trackmin); |
|---|
| 825 | | } else { |
|---|
| 826 | | double trackmin = w.rect.y + tw*2; |
|---|
| 827 | | double trackmax = w.rect.y2 - tw*2; |
|---|
| 828 | | t = 1 - (p.y-trackmin)/(trackmax-trackmin); |
|---|
| 829 | | } |
|---|
| 830 | | double v = w.value_min + t*(w.value_max - w.value_min); |
|---|
| 831 | | return v; |
|---|
| 832 | | } |
|---|
| 833 | | |
|---|
| 834 | | void slider_mouse_button(Widget widget, MouseButtonEvent ev) |
|---|
| 835 | | { |
|---|
| 836 | | auto w = cast(Slider)widget; assert(w); |
|---|
| 837 | | if (ev.is_left && ev.is_press) { w.grab_mouse(); } |
|---|
| 838 | | else if (ev.is_left && ev.is_release) { w.release_mouse(); } |
|---|
| 839 | | double v = slider_map_mouse_to_value(w, ev.p); |
|---|
| 840 | | w.m_saveValue = w.value; |
|---|
| 841 | | w.value = v; |
|---|
| 842 | | } |
|---|
| 843 | | void slider_mouse_move(Widget widget, MouseMoveEvent ev) |
|---|
| 844 | | { |
|---|
| 845 | | if (!widget.is_grabbing_mouse) { |
|---|
| 846 | | return; |
|---|
| 847 | | } |
|---|
| 848 | | auto w = cast(Slider)widget; assert(w); |
|---|
| 849 | | if (ev.left_down) { |
|---|
| 850 | | double v = slider_map_mouse_to_value(w, ev.p); |
|---|
| 851 | | w.value = v; |
|---|
| 852 | | } |
|---|
| 853 | | } |
|---|
| 854 | | //----SPINNER---------------------------------------------------------------- |
|---|
| 855 | | void spinner_register() { |
|---|
| 856 | | //addHandlers!(Spinner)(&spinner_draw, &spinner_best_size); |
|---|
| 857 | | } |
|---|
| 858 | | /* |
|---|
| 859 | | Size spinner_min_size(Widget widget, Size bounds) { |
|---|
| 860 | | auto w = cast(Spinner)widget; assert(w); |
|---|
| 861 | | return Size(0,0); |
|---|
| 862 | | } |
|---|
| 863 | | Size spinner_best_size(Widget widget, Size bounds) { |
|---|
| 864 | | auto w = cast(Spinner)widget; assert(w); |
|---|
| 865 | | return Size(0,0); |
|---|
| 866 | | } |
|---|
| 867 | | void spinner_draw(Widget widget) { |
|---|
| 868 | | auto w = cast(Spinner)widget; assert(w); |
|---|
| 869 | | set_color(get_background_color(widget)); |
|---|
| 870 | | fill_rect(w.rect); |
|---|
| 871 | | } |
|---|
| 872 | | */ |
|---|
| 873 | | //----RADIOGROUP---------------------------------------------------------------- |
|---|
| 874 | | void radiogroup_register() { |
|---|
| 875 | | //addHandlers!(RadioGroup)(&radiogroup_draw, &radiogroup_best_size); |
|---|
| 876 | | } |
|---|
| 877 | | Size radiogroup_min_size(Widget widget, Size bounds) { |
|---|
| 878 | | auto w = cast(RadioGroup)widget; assert(w); |
|---|
| 879 | | return Size(0,0); |
|---|
| 880 | | } |
|---|
| 881 | | Size radiogroup_best_size(Widget widget, Size bounds) { |
|---|
| 882 | | auto w = cast(RadioGroup)widget; assert(w); |
|---|
| 883 | | return Size(0,0); |
|---|
| 884 | | } |
|---|
| 885 | | void radiogroup_draw(Widget widget) { |
|---|
| 886 | | auto w = cast(RadioGroup)widget; assert(w); |
|---|
| 887 | | set_color(get_background_color(widget)); |
|---|
| 888 | | fill_rect(w.rect); |
|---|
| 889 | | } |
|---|
| 890 | | //----RADIOBUTTON---------------------------------------------------------------- |
|---|
| 891 | | void radiobutton_register() { |
|---|
| 892 | | //addHandlers!(RadioButton)(&radiobutton_draw, &radiobutton_best_size); |
|---|
| 893 | | } |
|---|
| 894 | | Size radiobutton_min_size(Widget widget, Size bounds) { |
|---|
| 895 | | auto w = cast(RadioButton)widget; assert(w); |
|---|
| 896 | | return Size(0,0); |
|---|
| 897 | | } |
|---|
| 898 | | Size radiobutton_best_size(Widget widget, Size bounds) { |
|---|
| 899 | | auto w = cast(RadioButton)widget; assert(w); |
|---|
| 900 | | return Size(0,0); |
|---|
| 901 | | } |
|---|
| 902 | | void radiobutton_draw(Widget widget) { |
|---|
| 903 | | auto w = cast(RadioButton)widget; assert(w); |
|---|
| 904 | | set_color(get_background_color(widget)); |
|---|
| 905 | | fill_rect(w.rect); |
|---|
| 906 | | } |
|---|
| 907 | | //---------------------------------------------------------------------------- |
|---|
| 908 | | |
|---|
| 909 | | Color bkg_color; |
|---|
| 910 | | Color text_color; |
|---|
| 911 | | Color sel_text_color; |
|---|
| 912 | | Color sel_text_bkg_color; |
|---|
| 913 | | Color sel_text_unfocus_bkg_color; |
|---|
| 914 | | Color hilite_color[3]; // dark medium light |
|---|
| 915 | | |
|---|
| 916 | | private: |
|---|
| 917 | | |
|---|
| 918 | | Font m_default_font; |
|---|
| 919 | | StdBitmapSet m_bitmaps; |
|---|
| 920 | | |
|---|
| 921 | | ThemeData[ClassInfo] m_classThemeData; |
|---|
| 922 | | } |
|---|
| 923 | | |
|---|