/* Starshatter OpenSource Distribution Copyright (c) 1997-2004, Destroyer Studios LLC. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name "Destroyer Studios" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SUBSYSTEM: nGenEx.lib FILE: ListBox.cpp AUTHOR: John DiCamillo OVERVIEW ======== ListBox ActiveWindow class */ #include "MemDebug.h" #include "ListBox.h" #include "Button.h" #include "Bitmap.h" #include "FormWindow.h" #include "Video.h" #include "Font.h" #include "Keyboard.h" #include "Mouse.h" // +--------------------------------------------------------------------+ class ListBoxCell { public: static const char* TYPENAME() { return "ListBoxCell"; } ListBoxCell() : data(0), image(0) { } Text text; DWORD data; Bitmap* image; }; // +--------------------------------------------------------------------+ class ListBoxItem { public: static const char* TYPENAME() { return "ListBoxItem"; } ListBoxItem() : data(0), image(0), selected(false), listbox(0), color(Color::White) { } ~ListBoxItem() { subitems.destroy(); } int operator < (const ListBoxItem& item) const; int operator <=(const ListBoxItem& item) const; int operator ==(const ListBoxItem& item) const; Text text; DWORD data; Bitmap* image; bool selected; Color color; List subitems; ListBox* listbox; }; // +--------------------------------------------------------------------+ class ListBoxColumn { public: static const char* TYPENAME() { return "ListBoxColumn"; } ListBoxColumn() : width(0), align(0), sort(0), color(Color::White), use_color(0), percent(0) { } Text title; int width; int align; int sort; Color color; int use_color; double percent; }; // +--------------------------------------------------------------------+ int ListBoxItem::operator < (const ListBoxItem& item) const { if (listbox && listbox == item.listbox) { int sort_column = listbox->GetSortColumn() - 1; int sort_criteria = listbox->GetSortCriteria(); if (sort_column == -1) { switch (sort_criteria) { case ListBox::LIST_SORT_NUMERIC_DESCENDING: return data > item.data; case ListBox::LIST_SORT_ALPHA_DESCENDING: return text > item.text; case ListBox::LIST_SORT_ALPHA_ASCENDING: return text < item.text; case ListBox::LIST_SORT_NUMERIC_ASCENDING: return data < item.data; } } else if (sort_column >= 0 && sort_column <= subitems.size() && sort_column <= item.subitems.size()) { switch (sort_criteria) { case ListBox::LIST_SORT_NUMERIC_DESCENDING: return subitems[sort_column]->data > item.subitems[sort_column]->data; case ListBox::LIST_SORT_ALPHA_DESCENDING: return subitems[sort_column]->text > item.subitems[sort_column]->text; case ListBox::LIST_SORT_ALPHA_ASCENDING: return subitems[sort_column]->text < item.subitems[sort_column]->text; case ListBox::LIST_SORT_NUMERIC_ASCENDING: return subitems[sort_column]->data < item.subitems[sort_column]->data; } } } return 0; } // +--------------------------------------------------------------------+ int ListBoxItem::operator <=(const ListBoxItem& item) const { if (listbox && listbox == item.listbox) { int sort_column = listbox->GetSortColumn() - 1; int sort_criteria = listbox->GetSortCriteria(); if (sort_column == -1) { switch (sort_criteria) { case ListBox::LIST_SORT_NUMERIC_DESCENDING: return data >= item.data; case ListBox::LIST_SORT_ALPHA_DESCENDING: return text >= item.text; case ListBox::LIST_SORT_ALPHA_ASCENDING: return text <= item.text; case ListBox::LIST_SORT_NUMERIC_ASCENDING: return data <= item.data; } } else if (sort_column >= 0 && sort_column <= subitems.size() && sort_column <= item.subitems.size()) { switch (sort_criteria) { case ListBox::LIST_SORT_NUMERIC_DESCENDING: return subitems[sort_column]->data >= item.subitems[sort_column]->data; case ListBox::LIST_SORT_ALPHA_DESCENDING: return subitems[sort_column]->text >= item.subitems[sort_column]->text; case ListBox::LIST_SORT_ALPHA_ASCENDING: return subitems[sort_column]->text <= item.subitems[sort_column]->text; case ListBox::LIST_SORT_NUMERIC_ASCENDING: return subitems[sort_column]->data <= item.subitems[sort_column]->data; } } } return 0; } // +--------------------------------------------------------------------+ int ListBoxItem::operator == (const ListBoxItem& item) const { if (listbox && listbox == item.listbox) { int sort_column = listbox->GetSortColumn() - 1; int sort_criteria = listbox->GetSortCriteria(); if (sort_column == -1) { switch (sort_criteria) { case ListBox::LIST_SORT_NUMERIC_DESCENDING: return data == item.data; case ListBox::LIST_SORT_ALPHA_DESCENDING: return text == item.text; case ListBox::LIST_SORT_ALPHA_ASCENDING: return text == item.text; case ListBox::LIST_SORT_NUMERIC_ASCENDING: return data == item.data; } } else if (sort_column >= 0 && sort_column <= subitems.size() && sort_column <= item.subitems.size()) { switch (sort_criteria) { case ListBox::LIST_SORT_NUMERIC_DESCENDING: return subitems[sort_column]->data == item.subitems[sort_column]->data; case ListBox::LIST_SORT_ALPHA_DESCENDING: return subitems[sort_column]->text == item.subitems[sort_column]->text; case ListBox::LIST_SORT_ALPHA_ASCENDING: return subitems[sort_column]->text == item.subitems[sort_column]->text; case ListBox::LIST_SORT_NUMERIC_ASCENDING: return subitems[sort_column]->data == item.subitems[sort_column]->data; } } } return 0; } // +--------------------------------------------------------------------+ static int old_cursor; // +--------------------------------------------------------------------+ ListBox::ListBox(ActiveWindow* p, int ax, int ay, int aw, int ah, DWORD aid) : ScrollWindow(p->GetScreen(), ax, ay, aw, ah, aid, 0, p) { show_headings = false; multiselect = false; list_index = 0; selcount = 0; selected_color = Color(255, 255, 128); sort_column = 0; item_style = LIST_ITEM_STYLE_PLAIN; seln_style = LIST_ITEM_STYLE_PLAIN; char buf[32]; sprintf_s(buf, "ListBox %d", id); desc = buf; } ListBox::ListBox(Screen* s, int ax, int ay, int aw, int ah, DWORD aid) : ScrollWindow(s, ax, ay, aw, ah, aid) { show_headings = false; multiselect = false; list_index = 0; selcount = 0; selected_color = Color(255, 255, 128); sort_column = 0; item_style = LIST_ITEM_STYLE_PLAIN; seln_style = LIST_ITEM_STYLE_PLAIN; char buf[32]; sprintf_s(buf, "ListBox %d", id); desc = buf; } ListBox::~ListBox() { items.destroy(); columns.destroy(); } // +--------------------------------------------------------------------+ void ListBox::DrawContent(const Rect& ctrl_rect) { SizeColumns(); Rect item_rect = ctrl_rect; item_rect.h = line_height; int h = rect.h; // draw headings at top, if needed: if (show_headings) { Color save_color = back_color; back_color = ShadeColor(back_color, 1.3); font->SetColor(fore_color); int max_column = columns.size()-1; item_rect.h += HEADING_EXTRA; page_size = (h-item_rect.h) / (line_height + leading); for (int column = 0; column <= max_column; column++) { item_rect.w = GetColumnWidth(column); // draw heading button FillRect(item_rect, back_color); DrawStyleRect(item_rect, WIN_RAISED_FRAME); Rect title_rect = item_rect; title_rect.Deflate(3,3); DrawText(GetColumnTitle(column), 0, title_rect, DT_CENTER|DT_SINGLELINE); item_rect.x += item_rect.w; } item_rect.y += item_rect.h; back_color = save_color; item_rect.h = line_height; } int index = 0; ListIter iter = items; while (++iter && item_rect.y < h) { ListBoxItem* item = iter.value(); if (index++ >= top_index) { // draw main item: int column = 0; item_rect.x = ctrl_rect.x; item_rect.w = GetColumnWidth(column) - 2; if (item_rect.y + item_rect.h > h) { item_rect.h = h - item_rect.y - 1; } Color item_color = GetItemColor(index-1, 0); if (item->selected) { font->SetColor(selected_color); if (seln_style == LIST_ITEM_STYLE_FILLED_BOX) FillRect(item_rect, selected_color * 0.25); if (seln_style >= LIST_ITEM_STYLE_BOX) DrawRect(item_rect, selected_color); } else { font->SetColor(item_color); if (item_style == LIST_ITEM_STYLE_FILLED_BOX) FillRect(item_rect, item_color * 0.25); if (item_style >= LIST_ITEM_STYLE_BOX) DrawRect(item_rect, item_color); } Rect text_rect = item_rect; if (item->image && item->image->Width() > 0 && item->image->Height() > 0) { DrawBitmap(text_rect.x, text_rect.y, text_rect.x + text_rect.w, text_rect.y + line_height, item->image); } else { text_rect.Deflate(2,0); DrawText(item->text.data(), item->text.length(), text_rect, GetColumnAlign(column)|DT_SINGLELINE); } // draw subitems: ListIter sub_iter = item->subitems; while (++sub_iter) { ListBoxCell* sub = sub_iter.value(); column++; item_rect.x += item_rect.w + 2; item_rect.w = GetColumnWidth(column) - 2; if (item->selected) { if (seln_style == LIST_ITEM_STYLE_FILLED_BOX) FillRect(item_rect, selected_color * 0.25); if (seln_style >= LIST_ITEM_STYLE_BOX) DrawRect(item_rect, selected_color); } else { if (item_style == LIST_ITEM_STYLE_FILLED_BOX) FillRect(item_rect, item_color * 0.25); if (item_style >= LIST_ITEM_STYLE_BOX) DrawRect(item_rect, item_color); } if (item->selected) font->SetColor(selected_color); else font->SetColor(GetItemColor(index-1, column)); Rect text_rect = item_rect; if (sub->image && sub->image->Width() > 0 && sub->image->Height() > 0) { DrawBitmap(text_rect.x, text_rect.y, text_rect.x + text_rect.w, text_rect.y + line_height, sub->image); } else { text_rect.Deflate(2,0); DrawText(sub->text.data(), sub->text.length(), text_rect, GetColumnAlign(column)|DT_SINGLELINE); } } item_rect.y += line_height + leading; } } } // +--------------------------------------------------------------------+ void ListBox::SizeColumns() { ListBoxColumn* c = columns.first(); if (c->percent < 0.001) { double total = 0; ListIter iter = columns; while (++iter) { c = iter.value(); total += c->width; } iter.reset(); while (++iter) { c = iter.value(); c->percent = c->width / total; } } int usable_width = rect.w; int used = 0; if (IsScrollVisible()) { usable_width -= SCROLL_WIDTH + 2; } else { usable_width -= 3; } for (int i = 0; i < columns.size(); i++) { c = columns[i]; if (i < columns.size() - 1) c->width = (int) (c->percent * usable_width); else c->width = usable_width - used; used += c->width; } } // +--------------------------------------------------------------------+ int ListBox::NumItems() { return items.size(); } int ListBox::NumColumns() { return columns.size(); } Text ListBox::GetItemText(int index) { if (index >= 0 && index < items.size()) return items[index]->text; return Text(); } void ListBox::SetItemText(int index, const char* text) { if (index >= 0 && index < items.size()) { items[index]->text = text; } } DWORD ListBox::GetItemData(int index) { if (index >= 0 && index < items.size()) return items[index]->data; return 0; } void ListBox::SetItemData(int index, DWORD data) { if (index >= 0 && index < items.size()) { items[index]->data = data; } } Bitmap* ListBox::GetItemImage(int index) { if (index >= 0 && index < items.size()) return items[index]->image; return 0; } void ListBox::SetItemImage(int index, Bitmap* img) { if (index >= 0 && index < items.size()) { items[index]->image = img; } } Color ListBox::GetItemColor(int index) { if (index >= 0 && index < items.size()) return items[index]->color; return Color::White; } void ListBox::SetItemColor(int index, Color c) { if (index >= 0 && index < items.size()) { items[index]->color = c; } } Text ListBox::GetItemText(int index, int column) { if (column == 0) { return GetItemText(index); } if (index >= 0 && index < items.size()) { ListBoxItem* item = items[index]; column--; if (column >= 0 && column < item->subitems.size()) return item->subitems[column]->text; } return Text(); } void ListBox::SetItemText(int index, int column, const char* text) { if (column == 0) { SetItemText(index, text); return; } if (index >= 0 && index < items.size()) { ListBoxItem* item = items[index]; column--; if (column >= 0 && column < columns.size()-1) { while (column >= item->subitems.size()) { ListBoxCell* cell = new(__FILE__,__LINE__) ListBoxCell; if (cell) item->subitems.append(cell); } item->subitems[column]->text = text; } } } DWORD ListBox::GetItemData(int index, int column) { if (column == 0) { return GetItemData(index); } if (index >= 0 && index < items.size()) { ListBoxItem* item = items[index]; column--; if (column >= 0 && column < item->subitems.size()) return item->subitems[column]->data; } return 0; } void ListBox::SetItemData(int index, int column, DWORD data) { if (column == 0) { SetItemData(index, data); return; } if (index >= 0 && index < items.size()) { ListBoxItem* item = items[index]; column--; if (column >= 0 && column < columns.size()-1) { while (column >= item->subitems.size()) { ListBoxCell* cell = new(__FILE__,__LINE__) ListBoxCell; if (cell) item->subitems.append(cell); } item->subitems[column]->data = data; } } } Bitmap* ListBox::GetItemImage(int index, int column) { if (column == 0) { return GetItemImage(index); } if (index >= 0 && index < items.size()) { ListBoxItem* item = items[index]; column--; if (column >= 0 && column < item->subitems.size()) return item->subitems[column]->image; } return 0; } void ListBox::SetItemImage(int index, int column, Bitmap* img) { if (column == 0) { SetItemImage(index, img); return; } if (index >= 0 && index < items.size()) { ListBoxItem* item = items[index]; column--; if (column >= 0 && column < columns.size()-1) { while (column >= item->subitems.size()) { ListBoxCell* cell = new(__FILE__,__LINE__) ListBoxCell; if (cell) item->subitems.append(cell); } item->subitems[column]->image = img; } } } int ListBox::AddItem(const char* text) { ListBoxItem* item = new(__FILE__,__LINE__) ListBoxItem; if (item) { item->text = text; item->color = fore_color; item->listbox = this; items.append(item); line_count = items.size(); list_index = items.size()-1; } return list_index+1; } int ListBox::AddItemWithData(const char* text, int data) { ListBoxItem* item = new(__FILE__,__LINE__) ListBoxItem; if (item) { item->text = text; item->data = data; item->color = fore_color; item->listbox = this; items.append(item); line_count = items.size(); list_index = items.size()-1; } return list_index+1; } int ListBox::AddImage(Bitmap* img) { ListBoxItem* item = new(__FILE__,__LINE__) ListBoxItem; if (item) { item->image = img; item->color = fore_color; item->listbox = this; items.append(item); line_count = items.size(); list_index = items.size()-1; } return list_index+1; } void ListBox::InsertItem(int index, const char* text) { if (index >=0 && index < items.size()) { ListBoxItem* item = new(__FILE__,__LINE__) ListBoxItem; if (item) { item->text = text; item->color = fore_color; item->listbox = this; list_index = index; items.insert(item, list_index); line_count = items.size(); } } } void ListBox::InsertItemWithData(int index, const char* text, int data) { if (index >=0 && index < items.size()) { ListBoxItem* item = new(__FILE__,__LINE__) ListBoxItem; if (item) { item->text = text; item->data = data; item->color = fore_color; item->listbox = this; list_index = index; items.insert(item, list_index); line_count = items.size(); } } } void ListBox::ClearItems() { items.destroy(); selcount = 0; top_index = 0; list_index = 0; line_count = 0; } void ListBox::RemoveItem(int index) { if (index >= 0 && index < items.size()) { if (items[index]->selected) selcount--; items.removeIndex(index); line_count = items.size(); } } void ListBox::RemoveSelectedItems() { if (selcount) { ListIter item = items; while (++item) { if (item->selected) { delete item.removeItem(); } } line_count = items.size(); selcount = 0; } } void ListBox::AddColumn(const char* title, int width, int align, int sort) { ListBoxColumn* column = new(__FILE__,__LINE__) ListBoxColumn; if (column) { column->title = title; column->width = width; column->align = align; column->sort = sort; columns.append(column); } } Text ListBox::GetColumnTitle(int index) { if (index >= 0 && index < columns.size()) return columns[index]->title; return Text(); } void ListBox::SetColumnTitle(int index, const char* title) { if (index >= 0 && index < columns.size()) { columns[index]->title = title; } } int ListBox::GetColumnWidth(int index) { if (index >= 0 && index < columns.size()) return columns[index]->width; return 0; } void ListBox::SetColumnWidth(int index, int width) { if (index >= 0 && index < columns.size()) { columns[index]->width = width; } } int ListBox::GetColumnAlign(int index) { if (index >= 0 && index < columns.size()) return columns[index]->align; return 0; } void ListBox::SetColumnAlign(int index, int align) { if (index >= 0 && index < columns.size()) { columns[index]->align = align; } } int ListBox::GetColumnSort(int index) { if (index >= 0 && index < columns.size()) return columns[index]->sort; return 0; } void ListBox::SetColumnSort(int index, int sort) { if (index >= 0 && index < columns.size()) { columns[index]->sort = sort; } } Color ListBox::GetColumnColor(int index) { if (index >= 0 && index < columns.size()) return columns[index]->color; return Color::White; } void ListBox::SetColumnColor(int index, Color c) { if (index >= 0 && index < columns.size()) { columns[index]->color = c; columns[index]->use_color = true; } } Color ListBox::GetItemColor(int index, int column) { Color c = Color::White; if (index >= 0 && index < items.size()) c = items[index]->color; if (column >= 0 && column < columns.size()) { if (columns[column]->use_color) c = columns[column]->color; } return c; } int ListBox::GetMultiSelect() { return multiselect; } void ListBox::SetMultiSelect(int nNewValue) { if (multiselect != nNewValue && (nNewValue == 0 || nNewValue == 1)) { multiselect = nNewValue; ClearSelection(); } } bool ListBox::GetShowHeadings() { return show_headings; } void ListBox::SetShowHeadings(bool nNewValue) { if (show_headings != nNewValue) { show_headings = nNewValue; } } Color ListBox::GetSelectedColor() { return selected_color; } void ListBox::SetSelectedColor(Color c) { if (selected_color != c) { selected_color = c; } } int ListBox::GetItemStyle() const { return item_style; } void ListBox::SetItemStyle(int style) { if (style >= LIST_ITEM_STYLE_PLAIN && style <= LIST_ITEM_STYLE_FILLED_BOX) { item_style = style; } } int ListBox::GetSelectedStyle() const { return seln_style; } void ListBox::SetSelectedStyle(int style) { if (style >= LIST_ITEM_STYLE_PLAIN && style <= LIST_ITEM_STYLE_FILLED_BOX) { seln_style = style; } } bool ListBox::IsSelected(int index) { if (index >= 0 && index < items.size()) return items[index]->selected; return false; } void ListBox::SetSelected(int index, bool bNewValue) { if (index >= 0 && index < items.size()) { if (!multiselect) ClearSelection(); if (items[index]->selected != bNewValue) { items[index]->selected = bNewValue; if (bNewValue) { list_index = index; selcount++; } else { selcount--; } } } } void ListBox::ClearSelection() { ListIter item = items; while (++item) item->selected = false; selcount = 0; } int ListBox::GetListIndex() { return list_index; } int ListBox::GetLineCount() { line_count = items.size(); return line_count; } int ListBox::GetSelCount() { return selcount; } int ListBox::GetSelection() { for (int i = 0; i < items.size(); i++) if (items[i]->selected) return i; return -1; } Text ListBox::GetSelectedItem() { int n = GetSelection(); return GetItemText(n); } // +--------------------------------------------------------------------+ int ListBox::GetSortColumn() { return sort_column; } void ListBox::SetSortColumn(int col_index) { if (col_index >= 0 && col_index <= columns.size()) sort_column = col_index; } int ListBox::GetSortCriteria() { return GetColumnSort(sort_column); } void ListBox::SetSortCriteria(SORT sort) { SetColumnSort(sort_column, sort); } // +--------------------------------------------------------------------+ void ListBox::SortItems() { if (sort_column >=0 && sort_column <= columns.size()) items.sort(); } // +--------------------------------------------------------------------+ int ListBox::IndexFromPoint(int x, int y) const { int sel_index = -1; if (show_headings) sel_index = top_index + (y - (line_height+HEADING_EXTRA)) / (line_height + leading); else sel_index = top_index + y / (line_height + leading); return sel_index; } // +--------------------------------------------------------------------+ int ListBox::OnMouseMove(int x, int y) { bool dirty = false; if (captured) { ActiveWindow* test = GetCapture(); if (test != this) { captured = false; dirty = true; } else { if (selecting && !dragging) { if (dragdrop && (x < rect.x || x > rect.x+rect.w || y < rect.y || y > rect.y+rect.h)) { dragging = true; OnDragStart(x,y); } } if (scrolling == SCROLL_THUMB) { mouse_y = y - rect.y - TRACK_START; int dest = (int) ((double) mouse_y/track_length * (items.size()-1)); ScrollTo(dest); dirty = true; } } } return ActiveWindow::OnMouseMove(x,y); } // +--------------------------------------------------------------------+ static bool preselected = false; int ListBox::OnLButtonDown(int x, int y) { if (!captured) captured = SetCapture(); mouse_x = x - rect.x; mouse_y = y - rect.y; int x_scroll_bar = rect.w; if (IsScrollVisible()) x_scroll_bar -= SCROLL_WIDTH; if (mouse_x < x_scroll_bar) { scrolling = SCROLL_NONE; if (show_headings && mouse_y < line_height+BORDER_WIDTH+EXTRA_WIDTH) { int next_col_start = 0; int max_column = columns.size()-1; int column; for (column = 0; column < max_column; column++) { next_col_start += GetColumnWidth(column); if (mouse_x < next_col_start) break; } sort_column = column; int& sort_criteria = columns[sort_column]->sort; if (sort_criteria != LIST_SORT_NEVER) { if (!sort_criteria) sort_criteria = LIST_SORT_ALPHA_DESCENDING; else sort_criteria = -sort_criteria; SortItems(); } } else { selecting = true; } } else { selecting = false; if (mouse_y < TRACK_START) { scrolling = SCROLL_UP; Scroll(scrolling, 1); Button::PlaySound(Button::SND_LIST_SCROLL); } else if (mouse_y > rect.h-TRACK_START) { scrolling = SCROLL_DOWN; if (top_index < items.size()-1) top_index++; Button::PlaySound(Button::SND_LIST_SCROLL); } else if (mouse_y < thumb_pos) { scrolling = SCROLL_PAGE_UP; Scroll(scrolling, page_size); Button::PlaySound(Button::SND_LIST_SCROLL); } else if (mouse_y > thumb_pos+THUMB_HEIGHT) { scrolling = SCROLL_PAGE_DOWN; Scroll(scrolling, page_size); Button::PlaySound(Button::SND_LIST_SCROLL); } else { scrolling = SCROLL_THUMB; } } if (selecting) { list_index = IndexFromPoint(mouse_x, mouse_y); preselected = IsSelected(list_index); if (!multiselect || !Keyboard::KeyDown(VK_SHIFT)) ClearSelection(); SetSelected(list_index); EnsureVisible(list_index); Button::PlaySound(Button::SND_LIST_SELECT); } return ActiveWindow::OnLButtonDown(x,y); } // +--------------------------------------------------------------------+ int ListBox::OnLButtonUp(int x, int y) { if (captured) { mouse_x = x-rect.x; mouse_y = y-rect.y; if (dragging) { if (mouse_x < 0 || mouse_x > rect.w || mouse_y < 0 || mouse_y > rect.h) { FormWindow* parent_form = (FormWindow*) form; if (parent_form) { ActiveWindow* drop_target = parent_form->FindControl(x,y); if (drop_target && drop_target->IsEnabled() && drop_target->IsShown()) drop_target->OnDragDrop(x,y,this); } } } else if (preselected) { if (multiselect && Keyboard::KeyDown(VK_SHIFT)) { SetSelected(list_index, false); Button::PlaySound(Button::SND_LIST_SELECT); } } ReleaseCapture(); captured = false; Mouse::SetCursor((Mouse::CURSOR) old_cursor); } dragging = false; selecting = false; return ActiveWindow::OnLButtonUp(x,y); } // +--------------------------------------------------------------------+ int ListBox::OnMouseWheel(int wheel) { return ScrollWindow::OnMouseWheel(wheel); } // +--------------------------------------------------------------------+ int ListBox::OnClick() { int fire_select = !scrolling; if (scrolling == SCROLL_THUMB) scrolling = SCROLL_NONE; if (fire_select) return ActiveWindow::OnSelect(); else return ActiveWindow::OnClick(); return 0; } // +--------------------------------------------------------------------+ int ListBox::OnKeyDown(int vk, int flags) { if (selcount == 1 && list_index >= 0 && list_index < items.size()) { ListBoxItem* item = items[list_index]; if (vk == VK_DOWN) { if (list_index < items.size() - 1) { item->selected = false; list_index++; item = items[list_index]; item->selected = true; OnClick(); return ActiveWindow::OnKeyDown(vk, flags); } } else if (vk == VK_UP) { if (list_index > 0) { item->selected = false; list_index--; item = items[list_index]; item->selected = true; OnClick(); return ActiveWindow::OnKeyDown(vk, flags); } } } return ScrollWindow::OnKeyDown(vk, flags); } // +--------------------------------------------------------------------+ int ListBox::OnDragStart(int x, int y) { old_cursor = Mouse::SetCursor(Mouse::DRAG); return ActiveWindow::OnDragStart(x,y); } // +--------------------------------------------------------------------+ int ListBox::OnDragDrop(int x, int y, ActiveWindow* source) { if (!dragdrop) return 0; ListBox* drag_source = (ListBox*) source; if (drag_source) { int max_col = NumColumns(); if (max_col != drag_source->NumColumns()) max_col = 0; for (int i = 0; i < drag_source->NumItems(); i++) { if (drag_source->IsSelected(i)) { AddItemWithData(drag_source->GetItemText(i), drag_source->GetItemData(i)); for (int c = 1; c < max_col; c++) { SetItemText(list_index, c, drag_source->GetItemText(i,c)); SetItemData(list_index, c, drag_source->GetItemData(i,c)); } if (!multiselect) ClearSelection(); items[list_index]->selected = true; selcount++; } } drag_source->RemoveSelectedItems(); Button::PlaySound(Button::SND_LIST_DROP); } return ActiveWindow::OnDragDrop(x,y,source); }