/* * Portions of this file are copyright Rebirth contributors and licensed as * described in COPYING.txt. * Portions of this file are copyright Parallax Software and licensed * according to the Parallax license below. * See COPYING.txt for license details. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include "maths.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #include "timer.h" namespace dcx { namespace { static void gr_draw_sunken_border( short x1, short y1, short x2, short y2 ); void ui_draw_listbox(UI_DIALOG &dlg, UI_GADGET_LISTBOX &listbox) { int x, y, stop; int w, h; //if (listbox.current_item<0) // listbox.current_item=0; //if (listbox.current_item>=listbox.num_items) // listbox.current_item = listbox.num_items - 1; //if (listbox.first_item<0) // listbox.first_item=0; //if (listbox.first_item>(listbox.num_items-listbox.num_items_displayed)) // listbox.first_item=(listbox.num_items-listbox.num_items_displayed); #if 0 //ndef OGL if ((listbox.status!=1) && !listbox.moved) return; #endif gr_set_current_canvas(listbox.canvas); auto &canvas = *grd_curcanv; w = listbox.width; h = listbox.height; gr_rect(canvas, 0, 0, w-1, h-1, CBLACK); gr_draw_sunken_border(-2, -2, w+listbox.scrollbar->width+4, h+1); stop = listbox.first_item+listbox.num_items_displayed; if (stop>listbox.num_items) stop = listbox.num_items; listbox.status = 0; x = y = 0; for (int i = listbox.first_item; i < stop; ++i) { const auto color = (i == listbox.current_item) ? CGREY : CBLACK; gr_rect(canvas, x, y, listbox.width - 1, y + h - 1, color); if (i != listbox.current_item) { if (listbox.current_item == -1 && dlg.keyboard_focus_gadget == &listbox && i == listbox.first_item) gr_set_fontcolor(canvas, CRED, -1); else gr_set_fontcolor(canvas, CWHITE, -1); } else { if (dlg.keyboard_focus_gadget == &listbox) gr_set_fontcolor(canvas, CRED, -1); else gr_set_fontcolor(canvas, CBLACK, -1); } gr_get_string_size(*canvas.cv_font, listbox.list[i], &w, &h, nullptr); gr_string(canvas, *canvas.cv_font, x + 2, y, listbox.list[i], w, h); y += h; } if (stop < listbox.num_items_displayed - 1) { gr_rect(canvas, x, y, listbox.width - 1, listbox.height-1, CBLACK); } } static void gr_draw_sunken_border( short x1, short y1, short x2, short y2 ) { const uint8_t cgrey = CGREY; const uint8_t cbright = CBRIGHT; Hline(*grd_curcanv, x1 - 1, x2 + 1, y1 - 1, cgrey); Vline(*grd_curcanv, y1 - 1, y2 + 1, x1 - 1, cgrey); Hline(*grd_curcanv, x1 - 1, x2 + 1, y2 + 1, cbright); Vline(*grd_curcanv, y1, y2 + 1, x2 + 1, cbright); } } std::unique_ptr ui_add_gadget_listbox(UI_DIALOG &dlg, short x, short y, short w, short h, short numitems, char **list) { int th, i; gr_get_string_size(*grd_curcanv->cv_font, "*", nullptr, &th, nullptr); i = h / th; h = i * th; auto listbox = ui_gadget_add(dlg, x, y, x + w - 1, y + h - 1); listbox->list = list; listbox->width = w; listbox->height = h; listbox->num_items = numitems; listbox->num_items_displayed = i; listbox->first_item = 0; listbox->current_item = -1; listbox->last_scrolled = 0; listbox->textheight = th; listbox->dragging = 0; listbox->selected_item = -1; listbox->moved = 1; listbox->scrollbar = ui_add_gadget_scrollbar(dlg, x + w + 3, y, 0, h, 0, numitems - i, 0, i); listbox->scrollbar->parent = listbox.get(); return listbox; } window_event_result UI_GADGET_LISTBOX::event_handler(UI_DIALOG &dlg, const d_event &event) { int kf; if (event.type == EVENT_WINDOW_DRAW) { ui_draw_listbox(dlg, *this); return window_event_result::ignored; } const auto keypress = (event.type == EVENT_KEY_COMMAND) ? event_key_get(event) : 0u; selected_item = -1; moved = 0; if (num_items < 1 ) { current_item = -1; first_item = 0; old_current_item = current_item; old_first_item = first_item; if (dlg.keyboard_focus_gadget == this) { dlg.keyboard_focus_gadget = &ui_gadget_get_next(*this); } return window_event_result::ignored; } old_current_item = current_item; old_first_item = first_item; if (GADGET_PRESSED(scrollbar.get())) { moved = 1; first_item = scrollbar->position; if (current_item(first_item+num_items_displayed-1)) current_item = first_item + num_items_displayed-1; } if (B1_JUST_RELEASED) dragging = 0; window_event_result rval = window_event_result::ignored; if (B1_JUST_PRESSED && ui_mouse_on_gadget(*this)) { dragging = 1; rval = window_event_result::handled; } if (dlg.keyboard_focus_gadget == this) { if (keypress==KEY_ENTER) { selected_item = current_item; rval = window_event_result::handled; } kf = 0; switch(keypress) { case (KEY_UP): current_item--; kf = 1; break; case (KEY_DOWN): current_item++; kf = 1; break; case (KEY_HOME): current_item=0; kf = 1; break; case (KEY_END): current_item=num_items-1; kf = 1; break; case (KEY_PAGEUP): current_item -= num_items_displayed; kf = 1; break; case (KEY_PAGEDOWN): current_item += num_items_displayed; kf = 1; break; } if (kf==1) { moved = 1; rval = window_event_result::handled; if (current_item<0) current_item=0; if (current_item>=num_items) current_item = num_items-1; if (current_item=(first_item+num_items_displayed)) first_item = current_item-num_items_displayed+1; if (num_items <= num_items_displayed ) first_item = 0; else { const auto oldfakepos = scrollbar->position; scrollbar->position = first_item; scrollbar->fake_position = scrollbar->position-scrollbar->start; scrollbar->fake_position *= scrollbar->height-scrollbar->fake_size; scrollbar->fake_position /= (scrollbar->stop-scrollbar->start); if (scrollbar->fake_position<0) { scrollbar->fake_position = 0; } if (scrollbar->fake_position > (scrollbar->height-scrollbar->fake_size)) { scrollbar->fake_position = (scrollbar->height-scrollbar->fake_size); } if (oldfakepos != scrollbar->position ) scrollbar->status = 1; } } } if (selected_gadget == this) { if (dragging) { int x, y, z; mouse_get_pos(&x, &y, &z); const auto mitem = (y < y1) ? -1 : (y - y1) / textheight; if ((mitem < 0) && (timer_query() > last_scrolled + 1)) { current_item--; last_scrolled = timer_query(); moved = 1; } if ((mitem >= num_items_displayed) && (timer_query() > last_scrolled + 1)) { current_item++; last_scrolled = timer_query(); moved = 1; } if ((mitem>=0) && (mitem= num_items ) current_item = num_items-1; if (current_item=(first_item+num_items_displayed)) first_item = current_item-num_items_displayed+1; if (num_items <= num_items_displayed ) first_item = 0; else { const auto oldfakepos = scrollbar->position; scrollbar->position = first_item; scrollbar->fake_position = scrollbar->position-scrollbar->start; scrollbar->fake_position *= scrollbar->height-scrollbar->fake_size; scrollbar->fake_position /= (scrollbar->stop-scrollbar->start); if (scrollbar->fake_position<0) { scrollbar->fake_position = 0; } if (scrollbar->fake_position > (scrollbar->height-scrollbar->fake_size)) { scrollbar->fake_position = (scrollbar->height-scrollbar->fake_size); } if (oldfakepos != scrollbar->position ) scrollbar->status = 1; } } if (B1_DOUBLE_CLICKED ) { selected_item = current_item; rval = window_event_result::handled; } } if (moved || (selected_item > 0)) { rval = ui_gadget_send_event(dlg, (selected_item > 0) ? EVENT_UI_LISTBOX_SELECTED : EVENT_UI_LISTBOX_MOVED, *this); if (rval == window_event_result::ignored) rval = window_event_result::handled; } return rval; } void ui_listbox_change(UI_DIALOG *, UI_GADGET_LISTBOX *listbox, uint_fast32_t numitems, const char *const *list) { int stop, start; UI_GADGET_SCROLLBAR * scrollbar; listbox->list = list; listbox->num_items = numitems; listbox->first_item = 0; listbox->current_item = -1; listbox->last_scrolled = timer_query(); listbox->dragging = 0; listbox->selected_item = -1; listbox->status = 1; listbox->first_item = 0; listbox->current_item = listbox->old_current_item = 0; listbox->moved = 0; scrollbar = listbox->scrollbar.get(); start=0; stop= numitems - listbox->num_items_displayed; if (stop < start) stop = start; scrollbar->horz = 0; scrollbar->start = start; scrollbar->stop = stop; scrollbar->fake_length = scrollbar->height; scrollbar->fake_position = 0; if (stop!=start) scrollbar->fake_size = (listbox->num_items_displayed * scrollbar->height)/(stop-start+1+listbox->num_items_displayed); else scrollbar->fake_size = scrollbar->height; if (scrollbar->fake_size < 7) scrollbar->fake_size = 7; scrollbar->dragging = 0; scrollbar->moved=0; scrollbar->status=1; } }