summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormichi_cc <michi_cc@openttd.org>2012-04-17 19:43:13 +0000
committermichi_cc <michi_cc@openttd.org>2012-04-17 19:43:13 +0000
commitaf6a33bd1c191f1fcb60f85d8c2c38eca6db4cc5 (patch)
tree3e9aa0f5cdeaf410233844f5d249a1637ca37bde
parent4e5da5760a4e004673cbddcf051083d7660b691d (diff)
downloadopenttd-af6a33bd1c191f1fcb60f85d8c2c38eca6db4cc5.tar.xz
(svn r24126) -Feature [FS#3854]: Drag and drop support for the NewGRF list window. (Based on patch by sbr)
-rw-r--r--src/newgrf_gui.cpp172
1 files changed, 144 insertions, 28 deletions
diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp
index 1b713a24a..95f4565aa 100644
--- a/src/newgrf_gui.cpp
+++ b/src/newgrf_gui.cpp
@@ -26,6 +26,7 @@
#include "core/geometry_func.hpp"
#include "newgrf_text.h"
#include "textfile_gui.h"
+#include "tilehighlight_func.h"
#include "widgets/newgrf_widget.h"
#include "widgets/misc_widget.h"
@@ -537,6 +538,7 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
bool show_params; ///< Are the grf-parameters shown in the info-panel?
bool execute; ///< On pressing 'apply changes' are grf changes applied immediately, or only list is updated.
int preset; ///< Selected preset.
+ int active_over; ///< Active GRF item over which another one is dragged, \c -1 if none.
Scrollbar *vscroll;
Scrollbar *vscroll2;
@@ -552,6 +554,7 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
this->execute = execute;
this->show_params = show_params;
this->preset = -1;
+ this->active_over = -1;
CopyGRFConfigList(&this->actives, *orig_list, false);
GetGRFPresetList(&_grf_preset_list);
@@ -731,7 +734,17 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
bool h = (this->active_sel == c);
PaletteID pal = this->GetPalette(c);
- if (h) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, PC_DARK_BLUE);
+ if (h) {
+ GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, PC_DARK_BLUE);
+ } else if (i == this->active_over) {
+ /* Get index of current selection. */
+ int active_sel_pos = 0;
+ for (GRFConfig *c = this->actives; c != NULL && c != this->active_sel; c = c->next, active_sel_pos++) {}
+ if (active_sel_pos != this->active_over) {
+ uint top = this->active_over < active_sel_pos ? y + 1 : y + step_height - 2;
+ GfxFillRect(r.left + WD_FRAMERECT_LEFT, top - 1, r.right - WD_FRAMERECT_RIGHT, top + 1, PC_GREY);
+ }
+ }
DrawSprite(SPR_SQUARE, pal, square_left, y + square_offset_y);
if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, y + warning_offset_y);
uint txtoffset = c->error == NULL ? 0 : warning.width;
@@ -739,11 +752,14 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
y += step_height;
}
}
+ if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry.
+ GfxFillRect(r.left + WD_FRAMERECT_LEFT, y, r.right - WD_FRAMERECT_RIGHT, y + 2, PC_GREY);
+ }
break;
}
case WID_NS_AVAIL_LIST: {
- GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);
+ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, this->active_over == -2 ? PC_DARK_GREY : PC_BLACK);
uint step_height = this->GetWidget<NWidgetBase>(WID_NS_AVAIL_LIST)->resize_y;
int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2;
@@ -868,6 +884,8 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
}
case WID_NS_FILE_LIST: { // Select an active GRF.
+ ResetObjectToPlace();
+
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST);
GRFConfig *c;
@@ -879,7 +897,10 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
this->avail_pos = -1;
this->InvalidateData();
- if (click_count == 1) break;
+ if (click_count == 1) {
+ if (this->editable && this->active_sel != NULL) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
+ break;
+ }
/* FALL THROUGH, with double click. */
}
@@ -912,6 +933,8 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
}
case WID_NS_AVAIL_LIST: { // Select a non-active GRF.
+ ResetObjectToPlace();
+
uint i = this->vscroll2->GetScrolledRowFromWidget(pt.y, this, WID_NS_AVAIL_LIST);
this->active_sel = NULL;
DeleteWindowByClass(WC_GRF_PARAMETERS);
@@ -920,36 +943,18 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
this->avail_pos = i;
}
this->InvalidateData();
- if (click_count == 1) break;
+ if (click_count == 1) {
+ if (this->editable && this->avail_sel != NULL && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
+ break;
+ }
/* FALL THROUGH, with double click. */
}
- case WID_NS_ADD: {
+ case WID_NS_ADD:
if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break;
- GRFConfig **list;
- /* Find last entry in the list, checking for duplicate grfid on the way */
- for (list = &this->actives; *list != NULL; list = &(*list)->next) {
- if ((*list)->ident.grfid == this->avail_sel->ident.grfid) {
- ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
- return;
- }
- }
-
- GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list.
- c->SetParameterDefaults();
- *list = c; // Append GRF config to configuration list.
-
- /* Select next (or previous, if last one) item in the list. */
- int new_pos = this->avail_pos + 1;
- if (new_pos >= (int)this->avails.Length()) new_pos = this->avail_pos - 1;
- this->avail_pos = new_pos;
- if (new_pos >= 0) this->avail_sel = this->avails[new_pos];
-
- this->avails.ForceRebuild();
- this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
+ this->AddGRFToActive();
break;
- }
case WID_NS_APPLY_CHANGES: // Apply changes made to GRF list
if (!this->editable) break;
@@ -1024,6 +1029,7 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
}
this->avails.ForceRebuild();
+ ResetObjectToPlace();
DeleteWindowByClass(WC_GRF_PARAMETERS);
this->active_sel = NULL;
this->InvalidateData(GOID_NEWGRF_PRESET_LOADED);
@@ -1089,7 +1095,7 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) {}
this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST);
- this->vscroll->SetCount(i);
+ this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling.
this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST);
if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos);
@@ -1226,6 +1232,77 @@ struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
this->InvalidateData(0);
}
+ virtual void OnDragDrop(Point pt, int widget)
+ {
+ if (!this->editable) return;
+
+ if (widget == WID_NS_FILE_LIST) {
+ if (this->active_sel != NULL) {
+ /* Get pointer to the selected file in the active list. */
+ int from_pos = 0;
+ GRFConfig **from_prev;
+ for (from_prev = &this->actives; *from_prev != this->active_sel; from_prev = &(*from_prev)->next, from_pos++) {}
+
+ /* Gets the drag-and-drop destination offset. Ignore the last dummy line. */
+ int to_pos = min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST), this->vscroll->GetCount() - 2);
+ if (to_pos != from_pos) { // Don't move NewGRF file over itself.
+ /* Get pointer to destination position. */
+ GRFConfig **to_prev = &this->actives;
+ for (int i = from_pos < to_pos ? -1 : 0; *to_prev != NULL && i < to_pos; to_prev = &(*to_prev)->next, i++) {}
+
+ /* Detach NewGRF file from its original position. */
+ *from_prev = this->active_sel->next;
+
+ /* Attach NewGRF file to its new position. */
+ this->active_sel->next = *to_prev;
+ *to_prev = this->active_sel;
+
+ this->vscroll->ScrollTowards(to_pos);
+ this->preset = -1;
+ this->InvalidateData();
+ }
+ } else if (this->avail_sel != NULL) {
+ int to_pos = min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST), this->vscroll->GetCount() - 1);
+ this->AddGRFToActive(to_pos);
+ }
+ } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != NULL) {
+ /* Remove active NewGRF file by dragging it over available list. */
+ Point dummy = {-1, -1};
+ this->OnClick(dummy, WID_NS_REMOVE, 1);
+ }
+
+ ResetObjectToPlace();
+
+ if (this->active_over != -1) {
+ /* End of drag-and-drop, hide dragged destination highlight. */
+ this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
+ this->active_over = -1;
+ }
+ }
+
+ virtual void OnMouseDrag(Point pt, int widget)
+ {
+ if (!this->editable) return;
+
+ if (widget == WID_NS_FILE_LIST && (this->active_sel != NULL || this->avail_sel != NULL)) {
+ /* An NewGRF file is dragged over the active list. */
+ int to_pos = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST);
+ /* Skip the last dummy line if the source is from the active list. */
+ to_pos = min(to_pos, this->vscroll->GetCount() - (this->active_sel != NULL ? 2 : 1));
+
+ if (to_pos != this->active_over) {
+ this->active_over = to_pos;
+ this->SetWidgetDirty(WID_NS_FILE_LIST);
+ }
+ } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != NULL) {
+ this->active_over = -2;
+ this->SetWidgetDirty(WID_NS_AVAIL_LIST);
+ } else if (this->active_over != -1) {
+ this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST);
+ this->active_over = -1;
+ }
+ }
+
private:
/** Sort grfs by name. */
static int CDECL NameSorter(const GRFConfig * const *a, const GRFConfig * const *b)
@@ -1288,6 +1365,45 @@ private:
this->vscroll2->SetCount(this->avails.Length()); // Update the scrollbar
}
+
+ /**
+ * Insert a GRF into the active list.
+ * @param ins_pos Insert GRF at this position.
+ * @return True if the GRF was successfully added.
+ */
+ bool AddGRFToActive(int ins_pos = -1)
+ {
+ if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) return false;
+
+ GRFConfig **entry = NULL;
+ GRFConfig **list;
+ /* Find last entry in the list, checking for duplicate grfid on the way */
+ for (list = &this->actives; *list != NULL; list = &(*list)->next, ins_pos--) {
+ if (ins_pos == 0) entry = list; // Insert position? Save.
+ if ((*list)->ident.grfid == this->avail_sel->ident.grfid) {
+ ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
+ return false;
+ }
+ }
+ if (entry == NULL) entry = list;
+
+ GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list.
+ c->SetParameterDefaults();
+
+ /* Insert GRF config to configuration list. */
+ c->next = *entry;
+ *entry = c;
+
+ /* Select next (or previous, if last one) item in the list. */
+ int new_pos = this->avail_pos + 1;
+ if (new_pos >= (int)this->avails.Length()) new_pos = this->avail_pos - 1;
+ this->avail_pos = new_pos;
+ if (new_pos >= 0) this->avail_sel = this->avails[new_pos];
+
+ this->avails.ForceRebuild();
+ this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
+ return true;
+ }
};
#if defined(ENABLE_NETWORK)