diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 1c07d800..af6f2817 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -23,15 +23,17 @@ changes since wmaker 0.62.1: - added WMSetListAllowEmptySelection(), WMListAllowsEmptySelection(). - WMListSelectionDidChangeNotification passes NULL as the notification client data (previously passed the selected item row). -- WMRemoveListItem() returns an int : 1 success, 0 fail (previously was void). - added WMUnselectListItem(), WMSelectAllListItems(), WMUnselectAllListItems() - better behavior of wheel mices in WMList. Simple mouse wheel events - will scroll by 1/3 of the WMList height. Using Control as a modifier will - scroll line by line, while using Shift as a modifier will scroll page + will scroll by 1/3 of the WMList height. Using Shift as a modifier will + scroll line by line, while using Control as a modifier will scroll page by page. -- better behavior of WMScroller regarding mouse wheel events. Control modifier - will scroll line by line, while Shift modifier will scroll page by page. +- better behavior of WMScroller regarding mouse wheel events. 'Shift' modifier + will scroll line by line, while 'Control' modifier will scroll page by page. - fixed some buffer overflow allowing bugs. +- added WSDecrementWheel and WSIncrementWheel for handling mouse wheel in + scrollers and scrolled widgets. This should be treated like the WSxxxPage + counterparts, except it should scroll by page_size/3 instead of one full page changes since wmaker 0.62.0: diff --git a/WINGs/TODO b/WINGs/TODO index b79d3315..fc04d50a 100644 --- a/WINGs/TODO +++ b/WINGs/TODO @@ -1,4 +1,8 @@ - move paint to idle handlers +- finish the multiple selection code for lists (check for + allowEmptySelection and add handlers for scrolling while drag-selecting). +- check whether WMDestroyWidget() should first call WMUnmapWidget(). + - optimize color allocation for repeated colors - make it work in 8bpp diff --git a/WINGs/Tests/wtest.c b/WINGs/Tests/wtest.c index fa0c1aa2..c30c061e 100644 --- a/WINGs/Tests/wtest.c +++ b/WINGs/Tests/wtest.c @@ -115,6 +115,41 @@ testFrame(WMScreen *scr) } + +static void +singleClick(WMWidget *self, void *data) +{ +} + + +static void +doubleClick(WMWidget *self, void *data) +{ + WMLabel *label = (WMLabel*)data; + WMList *lPtr = (WMList*)self; + char buf[255]; + + WMSelectAllListItems(lPtr); + + //sprintf(buf, "Selected items: %d", + // WMGetArrayItemCount(WMGetListSelectedItems(lPtr)));; + //WMSetLabelText(label, buf); +} + + +static void +listSelectionObserver(void *observer, WMNotification *notification) +{ + WMLabel *label = (WMLabel*)observer; + WMList *lPtr = (WMList*)WMGetNotificationObject(notification); + char buf[255]; + + sprintf(buf, "Selected items: %d", + WMGetArrayItemCount(WMGetListSelectedItems(lPtr)));; + WMSetLabelText(label, buf); +} + + void testList(WMScreen *scr) { @@ -123,27 +158,67 @@ testList(WMScreen *scr) WMList *mlist; WMLabel *label; WMLabel *mlabel; + WMLabel *title; + WMLabel *mtitle; char text[100]; int i; windowCount++; win = WMCreateWindow(scr, "testList"); + WMResizeWidget(win, 370, 250); WMSetWindowTitle(win, "List"); WMSetWindowCloseAction(win, closeAction, NULL); + title = WMCreateLabel(win); + WMResizeWidget(title, 150, 20); + WMMoveWidget(title, 10, 10); + WMSetLabelRelief(title, WRRidge); + WMSetLabelText(title, "Single selection list"); + + mtitle = WMCreateLabel(win); + WMResizeWidget(mtitle, 150, 20); + WMMoveWidget(mtitle, 210, 10); + WMSetLabelRelief(mtitle, WRRidge); + WMSetLabelText(mtitle, "Multiple selection list"); + list = WMCreateList(win); + WMMoveWidget(list, 10, 40); for (i=0; i<50; i++) { sprintf(text, "Item %i", i); WMAddListItem(list, text); } mlist = WMCreateList(win); WMSetListAllowMultipleSelection(mlist, True); - WMMoveWidget(mlist, 220, 0); - for (i=0; i<50; i++) { + WMMoveWidget(mlist, 210, 40); + for (i=0; i<135; i++) { sprintf(text, "Item %i", i); WMAddListItem(mlist, text); } + + label = WMCreateLabel(win); + WMResizeWidget(label, 150, 40); + WMMoveWidget(label, 10, 200); + WMSetLabelRelief(label, WRRidge); + WMSetLabelText(label, "Selected items: 0"); + + mlabel = WMCreateLabel(win); + WMResizeWidget(mlabel, 150, 40); + WMMoveWidget(mlabel, 210, 200); + WMSetLabelRelief(mlabel, WRRidge); + WMSetLabelText(mlabel, "Selected items: 0"); + + WMSetListAction(list, singleClick, label); + WMSetListDoubleAction(list, doubleClick, label); + WMSetListAction(mlist, singleClick, mlabel); + WMSetListDoubleAction(mlist, doubleClick, mlabel); + + WMAddNotificationObserver(listSelectionObserver, label, + WMListSelectionDidChangeNotification, list); + WMAddNotificationObserver(listSelectionObserver, mlabel, + WMListSelectionDidChangeNotification, mlist); + + WMRealizeWidget(win); WMMapSubwidgets(win); WMMapWidget(win); diff --git a/WINGs/WINGs.h b/WINGs/WINGs.h index f836e3f7..1ed9a154 100644 --- a/WINGs/WINGs.h +++ b/WINGs/WINGs.h @@ -145,6 +145,8 @@ typedef enum { WSIncrementPage, WSDecrementLine, WSIncrementLine, + WSDecrementWheel, + WSIncrementWheel, WSKnob, WSKnobSlot } WMScrollerPart; @@ -1088,12 +1090,18 @@ WMListItem *WMGetListItem(WMList *lPtr, int row); WMArray *WMGetListItems(WMList *lPtr); -int WMRemoveListItem(WMList *lPtr, int row); +void WMRemoveListItem(WMList *lPtr, int row); void WMSelectListItem(WMList *lPtr, int row); void WMUnselectListItem(WMList *lPtr, int row); +/* This will select all items in range, and deselect all the others */ +void WMSetListSelectionToRange(WMList *lPtr, WMRange range); + +/* This will select all items in range, leaving the others as they are */ +void WMSelectListItemsInRange(WMList *lPtr, WMRange range); + void WMSelectAllListItems(WMList *lPtr); void WMUnselectAllListItems(WMList *lPtr); diff --git a/WINGs/WUtil.h b/WINGs/WUtil.h index 62fc5142..9a536ee3 100644 --- a/WINGs/WUtil.h +++ b/WINGs/WUtil.h @@ -332,6 +332,8 @@ WMArray* WMCreateArray(int initialSize); WMArray* WMCreateArrayWithDestructor(int initialSize, WMFreeDataProc *destructor); +WMArray* WMCreateArrayWithArray(WMArray *array); + void WMEmptyArray(WMArray *array); void WMFreeArray(WMArray *array); @@ -339,15 +341,15 @@ void WMFreeArray(WMArray *array); int WMGetArrayItemCount(WMArray *array); /* appends other to array. other remains unchanged */ -int WMAppendArray(WMArray *array, WMArray *other); +void WMAppendArray(WMArray *array, WMArray *other); /* add will place the element at the end of the array */ -int WMAddToArray(WMArray *array, void *item); +void WMAddToArray(WMArray *array, void *item); #define WMPushInArray(array, item) WMAddToArray(array, item) /* insert will increment the index of elements after it by 1 */ -int WMInsertInArray(WMArray *array, int index, void *item); +void WMInsertInArray(WMArray *array, int index, void *item); /* replace and set will return the old item WITHOUT calling the * destructor on it even if its available. Free the returned item yourself. @@ -387,6 +389,7 @@ void WMSortArray(WMArray *array, WMCompareDataProc *comparer); void WMMapArray(WMArray *array, void (*function)(void*, void*), void *data); +WMArray* WMGetSubarrayWithRange(WMArray* array, WMRange aRange); /*..........................................................................*/ @@ -414,12 +417,12 @@ WMBag* WMCreateTreeBagWithDestructor(WMFreeDataProc *destructor); int WMGetBagItemCount(WMBag *bag); -int WMAppendBag(WMBag *bag, WMBag *other); +void WMAppendBag(WMBag *bag, WMBag *other); -int WMPutInBag(WMBag *bag, void *item); +void WMPutInBag(WMBag *bag, void *item); /* insert will increment the index of elements after it by 1 */ -int WMInsertInBag(WMBag *bag, int index, void *item); +void WMInsertInBag(WMBag *bag, int index, void *item); /* this is slow */ /* erase will remove the element from the bag, diff --git a/WINGs/array.c b/WINGs/array.c index 30fa70a7..a8ecb357 100644 --- a/WINGs/array.c +++ b/WINGs/array.c @@ -41,7 +41,7 @@ WMCreateArrayWithDestructor(int initialSize, WMFreeDataProc *destructor) array = wmalloc(sizeof(WMArray)); - if (initialSize == 0) { + if (initialSize <= 0) { initialSize = INITIAL_SIZE; } @@ -55,6 +55,24 @@ WMCreateArrayWithDestructor(int initialSize, WMFreeDataProc *destructor) } +WMArray* +WMCreateArrayWithArray(WMArray *array) +{ + WMArray *newArray; + + newArray = wmalloc(sizeof(WMArray)); + + newArray->items = wmalloc(sizeof(void*) * array->allocSize); + memcpy(newArray->items, array->items, sizeof(void*)*array->itemCount); + + newArray->itemCount = array->itemCount; + newArray->allocSize = array->allocSize; + newArray->destructor = NULL; + + return newArray; +} + + void WMEmptyArray(WMArray *array) { @@ -85,11 +103,11 @@ WMGetArrayItemCount(WMArray *array) } -int +void WMAppendArray(WMArray *array, WMArray *other) { if (other->itemCount == 0) - return 1; + return; if (array->itemCount + other->itemCount > array->allocSize) { array->allocSize += other->allocSize; @@ -99,12 +117,10 @@ WMAppendArray(WMArray *array, WMArray *other) memcpy(array->items+array->itemCount, other->items, sizeof(void*)*other->itemCount); array->itemCount += other->itemCount; - - return 1; } -int +void WMAddToArray(WMArray *array, void *item) { if (array->itemCount >= array->allocSize) { @@ -114,15 +130,13 @@ WMAddToArray(WMArray *array, void *item) array->items[array->itemCount] = item; array->itemCount++; - - return 1; } -int +void WMInsertInArray(WMArray *array, int index, void *item) { - wassertrv(index >= 0 && index <= array->itemCount, 0); + wassertr(index >= 0 && index <= array->itemCount); if (array->itemCount >= array->allocSize) { array->allocSize += RESIZE_INCREMENT; @@ -135,8 +149,6 @@ WMInsertInArray(WMArray *array, int index, void *item) array->items[index] = item; array->itemCount++; - - return 1; } @@ -147,6 +159,7 @@ WMReplaceInArray(WMArray *array, int index, void *item) wassertrv(index >= 0 && index <= array->itemCount, NULL); + /* is it really useful to perform append if index == array->itemCount ? -Dan */ if (index == array->itemCount) { WMAddToArray(array, item); return NULL; @@ -186,7 +199,8 @@ WMRemoveFromArray(WMArray *array, void *item) for (i = 0; i < array->itemCount; i++) { if (array->items[i] == item) { - return WMDeleteFromArray(array, i); + WMDeleteFromArray(array, i); + return 1; } } @@ -266,3 +280,27 @@ WMMapArray(WMArray *array, void (*function)(void*, void*), void *data) } +WMArray* +WMGetSubarrayWithRange(WMArray* array, WMRange aRange) +{ + WMArray *newArray; + + if (aRange.count <= 0) + return WMCreateArray(0); + + if (aRange.position < 0) + aRange.position = 0; + if (aRange.position >= array->itemCount) + aRange.position = array->itemCount - 1; + if (aRange.position + aRange.count > array->itemCount) + aRange.count = array->itemCount - aRange.position; + + newArray = WMCreateArray(aRange.count); + memcpy(newArray->items, array->items+aRange.position, + sizeof(void*)*aRange.count); + newArray->itemCount = aRange.count; + + return newArray; +} + + diff --git a/WINGs/bagtree.c b/WINGs/bagtree.c index c324eca3..42ae74ea 100644 --- a/WINGs/bagtree.c +++ b/WINGs/bagtree.c @@ -423,22 +423,19 @@ WMGetBagItemCount(WMBag *self) } -int +void WMAppendBag(WMBag *self, WMBag *bag) { WMBagIterator ptr; void *data; for (data = WMBagFirst(bag, &ptr); data != NULL; data = WMBagNext(bag, &ptr)) { - if (!WMPutInBag(self, data)) - return 0; + WMPutInBag(self, data); } - - return 1; } -int +void WMPutInBag(WMBag *self, void *item) { W_Node *ptr; @@ -454,12 +451,10 @@ WMPutInBag(WMBag *self, void *item) rbTreeInsert(self, ptr); self->count++; - - return 1; } -int +void WMInsertInBag(WMBag *self, int index, void *item) { W_Node *ptr; @@ -480,8 +475,6 @@ WMInsertInBag(WMBag *self, int index, void *item) self->count++; - - return 1; } @@ -720,9 +713,7 @@ void WMFreeBag(WMBag *self) { WMEmptyBag(self); - free(self->nil); - free(self); } @@ -785,11 +776,9 @@ WMBagFirst(WMBag *self, WMBagIterator *ptr) if (node == self->nil) { *ptr = NULL; - return NULL; } else { *ptr = node; - return node->data; } } @@ -805,11 +794,9 @@ WMBagLast(WMBag *self, WMBagIterator *ptr) if (node == self->nil) { *ptr = NULL; - return NULL; } else { *ptr = node; - return node->data; } } @@ -827,11 +814,9 @@ WMBagNext(WMBag *self, WMBagIterator *ptr) if (node == self->nil) { *ptr = NULL; - return NULL; } else { *ptr = node; - return node->data; } } @@ -849,11 +834,9 @@ WMBagPrevious(WMBag *self, WMBagIterator *ptr) if (node == self->nil) { *ptr = NULL; - return NULL; } else { *ptr = node; - return node->data; } } diff --git a/WINGs/data.c b/WINGs/data.c index 3efc67d8..3c2b6d76 100644 --- a/WINGs/data.c +++ b/WINGs/data.c @@ -243,14 +243,14 @@ WMGetSubdataWithRange(WMData *aData, WMRange aRange) /*FOLD00*/ void *buffer; WMData *newData; - /* return an empty subdata instead if aRange.count is 0 ? */ - wassertrv(aRange.count > 0, NULL); + if (aRange.count <= 0) + return WMCreateDataWithCapacity(0); buffer = wmalloc(aRange.count); WMGetDataBytesWithRange(aData, buffer, aRange); newData = WMCreateDataWithBytesNoCopy(buffer, aRange.count, wfree); newData->format = aData->format; - + return newData; } diff --git a/WINGs/wbrowser.c b/WINGs/wbrowser.c index e615128b..3c0c2d08 100644 --- a/WINGs/wbrowser.c +++ b/WINGs/wbrowser.c @@ -571,14 +571,15 @@ scrollCallback(WMWidget *scroller, void *self) #define LAST_VISIBLE_COLUMN bPtr->firstVisibleColumn+bPtr->maxVisibleColumns switch (WMGetScrollerHitPart(sPtr)) { - case WSDecrementLine: + case WSDecrementLine: if (bPtr->firstVisibleColumn > 0) { scrollToColumn(bPtr, bPtr->firstVisibleColumn-1, True); } break; - case WSDecrementPage: - if (bPtr->firstVisibleColumn > 0) { + case WSDecrementPage: + case WSDecrementWheel: + if (bPtr->firstVisibleColumn > 0) { newFirst = bPtr->firstVisibleColumn - bPtr->maxVisibleColumns; scrollToColumn(bPtr, newFirst, True); @@ -586,13 +587,14 @@ scrollCallback(WMWidget *scroller, void *self) break; - case WSIncrementLine: + case WSIncrementLine: if (LAST_VISIBLE_COLUMN < bPtr->usedColumnCount) { scrollToColumn(bPtr, bPtr->firstVisibleColumn+1, True); } break; - case WSIncrementPage: + case WSIncrementPage: + case WSIncrementWheel: if (LAST_VISIBLE_COLUMN < bPtr->usedColumnCount) { newFirst = bPtr->firstVisibleColumn + bPtr->maxVisibleColumns; @@ -603,7 +605,7 @@ scrollCallback(WMWidget *scroller, void *self) } break; - case WSKnob: + case WSKnob: { double floatValue; double value = bPtr->columnCount - bPtr->maxVisibleColumns; @@ -624,8 +626,8 @@ scrollCallback(WMWidget *scroller, void *self) } break; - case WSKnobSlot: - case WSNoPart: + case WSKnobSlot: + case WSNoPart: /* do nothing */ break; } diff --git a/WINGs/wlist.c b/WINGs/wlist.c index bad5c16c..9fed3aea 100644 --- a/WINGs/wlist.c +++ b/WINGs/wlist.c @@ -201,7 +201,7 @@ WMInsertListItem(WMList *lPtr, int row, char *text) } -int +void WMRemoveListItem(WMList *lPtr, int row) { WMListItem *item; @@ -210,13 +210,13 @@ WMRemoveListItem(WMList *lPtr, int row) CHECK_CLASS(lPtr, WC_List); - if (row < 0 || row >= WMGetArrayItemCount(lPtr->items)) - return 0; + /*wassertr(row>=0 && rowitems));*/ + if (row<0 || row>=WMGetArrayItemCount(lPtr->items)) + return; item = WMGetFromArray(lPtr->items, row); if (item->selected) { WMRemoveFromArray(lPtr->selectedItems, item); - //WMUnselectListItem(lPtr, row); selNotify = 1; } @@ -236,8 +236,6 @@ WMRemoveListItem(WMList *lPtr, int row) if (selNotify) { WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); } - - return 1; } @@ -446,6 +444,14 @@ vScrollCallBack(WMWidget *scroller, void *self) scrollByAmount(lPtr, lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1); break; + case WSDecrementWheel: + scrollByAmount(lPtr, -lPtr->fullFitLines / 3); + break; + + case WSIncrementWheel: + scrollByAmount(lPtr, lPtr->fullFitLines / 3); + break; + case WSKnob: lPtr->topItem = WMGetScrollerValue(lPtr->vScroller) * (float)(itemCount - lPtr->fullFitLines); @@ -513,6 +519,13 @@ paintItem(List *lPtr, int index) WALeft, WMColorGC(scr->black), False, itemPtr->text, strlen(itemPtr->text)); } + + if ((index-lPtr->topItem+lPtr->fullFitLines)*lPtr->itemHeight > + lPtr->view->size.height-2) { + W_DrawRelief(lPtr->view->screen, lPtr->view->window, 0, 0, + lPtr->view->size.width, lPtr->view->size.height, + WRSunken); + } } @@ -620,62 +633,40 @@ WMFindRowOfListItemWithTitle(WMList *lPtr, char *title) void WMSelectListItem(WMList *lPtr, int row) { - WMListItem *item, *oldSelected; + WMListItem *item; if (row >= WMGetArrayItemCount(lPtr->items)) return; + if (row < 0) { - /* Should row = -1 deselect all or just do nothing ?. Check it. -Dan */ - if (!lPtr->flags.allowMultipleSelection) { - WMUnselectAllListItems(lPtr); - } + /* row = -1 will deselects all for backward compatibility. + * will be removed later. -Dan */ + WMUnselectAllListItems(lPtr); return; } item = WMGetFromArray(lPtr->items, row); if (item->selected) - return; /* Return if already selected */ + return; /* Return if already selected */ - oldSelected = WMGetFromArray(lPtr->selectedItems, 0); - - /* unselect previous selected item if case */ - if (!lPtr->flags.allowMultipleSelection && oldSelected) { - int oldSelectedRow = WMGetListSelectedItemRow(lPtr); - - // better call WMUnselectAllListItems() here? -Dan - oldSelected->selected = 0; - WMDeleteFromArray(lPtr->selectedItems, 0); - // This is faster and have the same effect in the single selected case - // but may leave xxx->selected flags set after a multi->single selected - // switch - //WMEmptyArray(lPtr->selectedItems); - - if (lPtr->view->flags.mapped && oldSelectedRow>=lPtr->topItem - && oldSelectedRow<=lPtr->topItem+lPtr->fullFitLines) { - paintItem(lPtr, oldSelectedRow); - } + if (!lPtr->flags.allowMultipleSelection) { + /* unselect previous selected items */ + WMUnselectAllListItems(lPtr); } /* select item */ item->selected = 1; WMAddToArray(lPtr->selectedItems, item); - if (lPtr->view->flags.mapped) { + if (lPtr->view->flags.mapped && row>=lPtr->topItem + && row<=lPtr->topItem+lPtr->fullFitLines) { paintItem(lPtr, row); - - if ((row-lPtr->topItem+lPtr->fullFitLines)*lPtr->itemHeight - > lPtr->view->size.height-2) - W_DrawRelief(lPtr->view->screen, lPtr->view->window, 0, 0, - lPtr->view->size.width, lPtr->view->size.height, - WRSunken); } WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); } -// make them return an int - void WMUnselectListItem(WMList *lPtr, int row) { @@ -684,7 +675,10 @@ WMUnselectListItem(WMList *lPtr, int row) if (!item || !item->selected) return; - // also add check for allowEmptySelection + if (!lPtr->flags.allowEmptySelection && + WMGetArrayItemCount(lPtr->selectedItems) <= 1) { + return; + } item->selected = 0; WMRemoveFromArray(lPtr->selectedItems, item); @@ -693,6 +687,120 @@ WMUnselectListItem(WMList *lPtr, int row) && row<=lPtr->topItem+lPtr->fullFitLines) { paintItem(lPtr, row); } + + WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); +} + + +void +WMSelectListItemsInRange(WMList *lPtr, WMRange range) +{ + WMListItem *item; + int position = range.position, k = 1, notify = 0; + int total = WMGetArrayItemCount(lPtr->items); + + if (!lPtr->flags.allowMultipleSelection) + return; + if (range.count==0) + return; /* Nothing to select */ + + if (range.count < 0) { + range.count = -range.count; + k = -1; + } + + for (; range.count>0 && position>=0 && positionitems, position); + if (!item->selected) { + item->selected = 1; + WMAddToArray(lPtr->selectedItems, item); + if (lPtr->view->flags.mapped && position>=lPtr->topItem + && position<=lPtr->topItem+lPtr->fullFitLines) { + paintItem(lPtr, position); + } + notify = 1; + } + position += k; + } + + if (notify) { + WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); + } +} + + +void +WMSetListSelectionToRange(WMList *lPtr, WMRange range) +{ + WMListItem *item; + int mark1, mark2, i, k; + int position = range.position, notify = 0; + int total = WMGetArrayItemCount(lPtr->items); + + if (!lPtr->flags.allowMultipleSelection) + return; + + if (range.count==0) { + WMUnselectAllListItems(lPtr); + return; + } + + if (range.count < 0) { + mark1 = range.position + range.count + 1; + mark2 = range.position + 1; + range.count = -range.count; + k = -1; + } else { + mark1 = range.position; + mark2 = range.position + range.count; + k = 1; + } + if (mark1 > total) + mark1 = total; + if (mark2 < 0) + mark2 = 0; + + WMEmptyArray(lPtr->selectedItems); + + for (i=0; iitems, i); + if (item->selected) { + item->selected = 0; + if (lPtr->view->flags.mapped && i>=lPtr->topItem + && i<=lPtr->topItem+lPtr->fullFitLines) { + paintItem(lPtr, i); + } + notify = 1; + } + } + for (; range.count>0 && position>=0 && positionitems, position); + if (!item->selected) { + item->selected = 1; + if (lPtr->view->flags.mapped && position>=lPtr->topItem + && position<=lPtr->topItem+lPtr->fullFitLines) { + paintItem(lPtr, position); + } + notify = 1; + } + WMAddToArray(lPtr->selectedItems, item); + position += k; + } + for (i=mark2; iitems, i); + if (item->selected) { + item->selected = 0; + if (lPtr->view->flags.mapped && i>=lPtr->topItem + && i<=lPtr->topItem+lPtr->fullFitLines) { + paintItem(lPtr, i); + } + notify = 1; + } + } + + if (notify) { + WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); + } } @@ -705,28 +813,43 @@ WMSelectAllListItems(WMList *lPtr) if (!lPtr->flags.allowMultipleSelection) return; - // implement some WMDuplicateArray() ? + if (WMGetArrayItemCount(lPtr->items) == + WMGetArrayItemCount(lPtr->selectedItems)) { + return; /* All items are selected already */ + } + + WMFreeArray(lPtr->selectedItems); + lPtr->selectedItems = WMCreateArrayWithArray(lPtr->items); + for (i=0; iitems); i++) { item = WMGetFromArray(lPtr->items, i); if (!item->selected) { item->selected = 1; - WMAddToArray(lPtr->selectedItems, item); if (lPtr->view->flags.mapped && i>=lPtr->topItem && i<=lPtr->topItem+lPtr->fullFitLines) { paintItem(lPtr, i); } } } + + WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); } void WMUnselectAllListItems(WMList *lPtr) { - int i; - WMListItem *item; + int i;//, keep; + WMListItem *item;//, *keepItem; - // check for allowEmptySelection + // FIXME: check for allowEmptySelection + + //keep = lPtr->flags.allowEmptySelection ? 0 : 1; + + //if (WMGetArrayItemCount(lPtr->selectedItems) == keep) + // return 1; /* Nothing selected so return */ + + //keepItem = (keep==1 ? WMGetFromArray(lPtr->selectedItems, 0) : NULL); for (i=0; iitems); i++) { item = WMGetFromArray(lPtr->items, i); @@ -740,6 +863,7 @@ WMUnselectAllListItems(WMList *lPtr) } WMEmptyArray(lPtr->selectedItems); + WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL); } @@ -763,30 +887,29 @@ handleActionEvents(XEvent *event, void *data) List *lPtr = (List*)data; int tmp; int topItem = lPtr->topItem; - static int oldClicked = -1; + static int lastClicked = -1, prevItem = -1; CHECK_CLASS(data, WC_List); switch (event->type) { case ButtonRelease: -#define CHECK_WHEEL_PATCH -#ifdef CHECK_WHEEL_PATCH /* Ignore mouse wheel events, they're not "real" button events */ if (event->xbutton.button == WINGsConfiguration.mouseWheelUp || event->xbutton.button == WINGsConfiguration.mouseWheelDown) { break; } -#endif lPtr->flags.buttonPressed = 0; tmp = getItemIndexAt(lPtr, event->xbutton.y); - if (/*tmp == lPtr->selectedItem && */tmp >= 0) { + if (tmp >= 0) { if (lPtr->action) (*lPtr->action)(lPtr, lPtr->clientData); } - oldClicked = tmp; + if (!(event->xbutton.state & ShiftMask)) + lastClicked = prevItem = tmp; + break; case EnterNotify: @@ -800,52 +923,96 @@ handleActionEvents(XEvent *event, void *data) break; case ButtonPress: - if (event->xbutton.x > WMWidgetWidth(lPtr->vScroller)) { -#ifdef CHECK_WHEEL_PATCH - if (event->xbutton.button == WINGsConfiguration.mouseWheelDown || - event->xbutton.button == WINGsConfiguration.mouseWheelUp) { - int amount = 0; + if (event->xbutton.x <= WMWidgetWidth(lPtr->vScroller)) + break; + if (event->xbutton.button == WINGsConfiguration.mouseWheelDown || + event->xbutton.button == WINGsConfiguration.mouseWheelUp) { + int amount = 0; - if (event->xbutton.state & ShiftMask) { - amount = lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1; - } else if (event->xbutton.state & ControlMask) { - amount = 1; - } else { - amount = lPtr->fullFitLines / 3; - if (amount == 0) - amount++; - } - if (event->xbutton.button == WINGsConfiguration.mouseWheelUp) - amount = -amount; - - scrollByAmount(lPtr, amount); - break; + if (event->xbutton.state & ControlMask) { + amount = lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1; + } else if (event->xbutton.state & ShiftMask) { + amount = 1; + } else { + amount = lPtr->fullFitLines / 3; + if (amount == 0) + amount++; } -#endif + if (event->xbutton.button == WINGsConfiguration.mouseWheelUp) + amount = -amount; - tmp = getItemIndexAt(lPtr, event->xbutton.y); - lPtr->flags.buttonPressed = 1; - - if (tmp >= 0) { - if (tmp == oldClicked && WMIsDoubleClick(event)) { - WMSelectListItem(lPtr, tmp); - if (lPtr->doubleAction) - (*lPtr->doubleAction)(lPtr, lPtr->doubleClientData); - } else { - WMSelectListItem(lPtr, tmp); - } - } - - oldClicked = tmp; + scrollByAmount(lPtr, amount); + break; } + + tmp = getItemIndexAt(lPtr, event->xbutton.y); + lPtr->flags.buttonPressed = 1; + + if (tmp >= 0) { + if (tmp == lastClicked && WMIsDoubleClick(event)) { + WMSelectListItem(lPtr, tmp); + if (lPtr->doubleAction) + (*lPtr->doubleAction)(lPtr, lPtr->doubleClientData); + } else { + if (!lPtr->flags.allowMultipleSelection) { + WMSelectListItem(lPtr, tmp); + } else { + WMRange range; + WMListItem *item, *lastSel; + + if (event->xbutton.state & ControlMask) { + item = WMGetFromArray(lPtr->items, tmp); + if (item && item->selected) { + WMUnselectListItem(lPtr, tmp); + } else { + WMSelectListItem(lPtr, tmp); + } + } else if (event->xbutton.state & ShiftMask) { + if (WMGetArrayItemCount(lPtr->selectedItems) == 0) { + WMSelectListItem(lPtr, tmp); + } else { + lastSel = WMGetFromArray(lPtr->items, lastClicked); + range.position = WMGetFirstInArray(lPtr->items, + lastSel); + if (tmp >= range.position) + range.count = tmp - range.position + 1; + else + range.count = tmp - range.position - 1; + + WMSetListSelectionToRange(lPtr, range); + } + } else { + range.position = tmp; + range.count = 1; + WMSetListSelectionToRange(lPtr, range); + } + } + } + } + + if (!(event->xbutton.state & ShiftMask)) + lastClicked = prevItem = tmp; + break; case MotionNotify: if (lPtr->flags.buttonPressed) { tmp = getItemIndexAt(lPtr, event->xmotion.y); - if (tmp>=0 /*&& tmp != lPtr->selectedItem*/) { - WMSelectListItem(lPtr, tmp); + if (tmp>=0 && tmp!=prevItem) { + if (lPtr->flags.allowMultipleSelection) { + WMRange range; + + range.position = lastClicked; + if (tmp >= lastClicked) + range.count = tmp - lastClicked + 1; + else + range.count = tmp - lastClicked - 1; + WMSetListSelectionToRange(lPtr, range); + } else { + WMSelectListItem(lPtr, tmp); + } } + prevItem = tmp; } break; } diff --git a/WINGs/wscroller.c b/WINGs/wscroller.c index 72945857..10a89676 100644 --- a/WINGs/wscroller.c +++ b/WINGs/wscroller.c @@ -817,9 +817,11 @@ handleActionEvents(XEvent *event, void *data) /* FIXME: change Mod1Mask with something else */ if (event->xbutton.button==WINGsConfiguration.mouseWheelUp) { if (event->xbutton.state & ControlMask) { + sPtr->flags.hitPart = WSDecrementPage; + } else if (event->xbutton.state & ShiftMask) { sPtr->flags.hitPart = WSDecrementLine; } else { - sPtr->flags.hitPart = WSDecrementPage; + sPtr->flags.hitPart = WSDecrementWheel; } if (sPtr->action) { (*sPtr->action)(sPtr, sPtr->clientData); @@ -827,9 +829,11 @@ handleActionEvents(XEvent *event, void *data) } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown) { if (event->xbutton.state & ControlMask) { + sPtr->flags.hitPart = WSIncrementPage; + } else if (event->xbutton.state & ShiftMask) { sPtr->flags.hitPart = WSIncrementLine; } else { - sPtr->flags.hitPart = WSIncrementPage; + sPtr->flags.hitPart = WSIncrementWheel; } if (sPtr->action) { (*sPtr->action)(sPtr, sPtr->clientData); diff --git a/WINGs/wscrollview.c b/WINGs/wscrollview.c index 2c1483b0..09496007 100644 --- a/WINGs/wscrollview.c +++ b/WINGs/wscrollview.c @@ -258,7 +258,7 @@ doScrolling(WMWidget *self, void *data) vpsize = 1; switch (WMGetScrollerHitPart(self)) { - case WSDecrementLine: + case WSDecrementLine: if (pos > 0) { pos-=sPtr->lineScroll; if (pos < 0) @@ -268,7 +268,7 @@ doScrolling(WMWidget *self, void *data) WMGetScrollerKnobProportion(self)); } break; - case WSIncrementLine: + case WSIncrementLine: if (pos < size) { pos+=sPtr->lineScroll; if (pos > size) @@ -278,12 +278,13 @@ doScrolling(WMWidget *self, void *data) WMGetScrollerKnobProportion(self)); } break; - case WSKnob: + + case WSKnob: value = WMGetScrollerValue(self); pos = value*size; break; - - case WSDecrementPage: + + case WSDecrementPage: if (pos > 0) { pos -= vpsize; if (pos < 0) @@ -292,9 +293,20 @@ doScrolling(WMWidget *self, void *data) WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self)); } + break; + + case WSDecrementWheel: + if (pos > 0) { + pos -= vpsize/3; + if (pos < 0) + pos = 0; + value = (float)pos / size; + WMSetScrollerParameters(self, value, + WMGetScrollerKnobProportion(self)); + } break; - - case WSIncrementPage: + + case WSIncrementPage: if (pos < size) { pos += vpsize; if (pos > size) @@ -304,7 +316,18 @@ doScrolling(WMWidget *self, void *data) WMGetScrollerKnobProportion(self)); } break; - + + case WSIncrementWheel: + if (pos < size) { + pos += vpsize/3; + if (pos > size) + pos = size; + value = (float)pos / size; + WMSetScrollerParameters(self, value, + WMGetScrollerKnobProportion(self)); + } + break; + case WSNoPart: case WSKnobSlot: break; diff --git a/WINGs/wtext.c b/WINGs/wtext.c index eced6df7..00aa52b8 100644 --- a/WINGs/wtext.c +++ b/WINGs/wtext.c @@ -2557,9 +2557,10 @@ prepareForDragOperation(WMView *self, WMDraggingInfo *info) char *badbadbad; +static void receivedData(WMView *view, Atom selection, Atom target, Time timestamp, void *cdata, WMData *data) -{ +{ badbadbad = wstrdup((char *)WMDataBytes(data)); }