From 6a2fc8cfb3a7fae75451a0183fe9575b16a9181e Mon Sep 17 00:00:00 2001
From: David Brown <dbrown@gitlab.riscosopen.org>
Date: Wed, 27 Aug 1997 17:03:38 +0000
Subject: [PATCH] Revised selection model

---
 c/Hotlist | 281 ++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 220 insertions(+), 61 deletions(-)

diff --git a/c/Hotlist b/c/Hotlist
index 205366a..ba8d4e1 100644
--- a/c/Hotlist
+++ b/c/Hotlist
@@ -64,8 +64,7 @@ static hotlist_item * hotlist_newitem;                    /* When ever a new ite
 
 static int            menu_itemno = 0;                    /* Item over which menu was pressed */
 
-static hotlist_item * selected_parent    = NULL;          /* The parent directory of all selected items */
-static int            number_selected    = 0;             /* The number of items selected */
+static int            menu_select        = 0;             /* 1 if an item had to be selected when the menu was opened */
 static unsigned int   last_selected_item = 0xffffffff;    /* The last item which was selected */
 
 static int            hotlist_dragging   = 0;             /* Holds a set of values for different dragging cases (see Hotlist.h) */
@@ -128,6 +127,10 @@ static hotlist_item    * _hotlist_find_selected_item     (hotlist_item * list);
 static hotlist_item    * hotlist_find_selected_item      (void);
 static void              _hotlist_count_displayed_items  (hotlist_item * list);
 static unsigned int      hotlist_count_displayed_items   (hotlist_item * list);
+static void              _hotlist_count_selected_items  (hotlist_item * list);
+static unsigned int      hotlist_count_selected_items   (void);
+static unsigned int      hotlist_contents_selected(hotlist_item *item);
+static unsigned int      hotlist_no_contents_selected(hotlist_item *item);
 static void              _hotlist_draw                   (hotlist_item * list, unsigned int first_item, unsigned int last_item, unsigned int indent);
 static void              hotlist_draw                    (hotlist_item * list, unsigned int first_item, unsigned int last_item);
 static void              _hotlist_get_max_width          (hotlist_item * list, unsigned int indent);
@@ -842,13 +845,36 @@ static void hotlist_delete_item(hotlist_item * item)
 
 static _kernel_oserror * hotlist_move_item(hotlist_item * source, hotlist_item * target, unsigned int position)
 {
-  /* Unlink item from directory structure */
+  hotlist_item *newdir, *tempptr;
+  if (!(source->type == hl_directory && !hotlist_contents_selected(source->data.directory_content)))
+  {
+    /* Unlink item from directory structure */
 
-  hotlist_unlink(source);
+    hotlist_unlink(source);
 
-  /* Link into new position in directory structure */
+    /* Link into new position in directory structure */
 
-  return hotlist_link(source, target, position);
+    return hotlist_link(source, target, position);
+  }
+  else
+  {
+    /* Special case - moving a directory whose contents are only partially selected */
+    /* we can't move a directory whose contents are only partially to be moved,     */
+    /* there would be no where to leave the items which were not moved.             */
+    RetError(hotlist_new_directory(target, source->name, position, &newdir));
+    source = source->data.directory_content;
+    while(source)
+    {
+      tempptr = source->next;
+      if (source->flags & HOTLIST_G_IS_SELECTED)
+      {
+        hotlist_move_item(source, newdir, HOTLIST_POSITION_END); /* move items into new directory */
+        source->flags &= ~HOTLIST_G_IS_SELECTED;
+      }
+      source = tempptr;
+    }
+  }
+  return NULL;
 }
 
 /*************************************************/
@@ -915,7 +941,10 @@ static _kernel_oserror * hotlist_copy_item(hotlist_item * source, hotlist_item *
 
       while (content)
       {
-        RetError(hotlist_copy_item(content, newdir, HOTLIST_POSITION_END, NULL));
+        if (content->flags & HOTLIST_G_IS_SELECTED)
+        {
+          RetError(hotlist_copy_item(content, newdir, HOTLIST_POSITION_END, NULL));
+        }
 
         content = content->next;
       }
@@ -1620,6 +1649,9 @@ static void hotlist_directory_open_close(hotlist_item *item, unsigned int itemno
   hotlist_get_entry_sizes(&item_height, &item_dir_width, &item_url_width);
 
   item->flags ^= HOTLIST_D_IS_OPEN;
+
+  hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+
   hotlist_window_preopen(already_open);
   show_error(window_get_wimp_handle(0, hotlist_windowid, &window_handle));
 
@@ -1683,7 +1715,6 @@ static void hotlist_clear_selection(void)
 {
   hotlist_clear_flags(hotlist_root->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
   hotlist_redraw_now();
-  number_selected = 0;
 }
 
 /*************************************************/
@@ -1733,7 +1764,6 @@ static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno,
         break;
       }
     item->flags &= ~HOTLIST_G_IS_SELECTED;
-    number_selected--;
     hotlist_redraw_items(itemno, itemno);
     }
     break; /* Double click select */
@@ -1753,7 +1783,6 @@ static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno,
         break;
       }
       item->flags &= ~HOTLIST_G_IS_SELECTED;
-      number_selected--;
       hotlist_redraw_items(itemno, itemno);
     }
     break; /* Double click adjust */
@@ -1766,9 +1795,7 @@ static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno,
     if (!(item->flags & HOTLIST_G_IS_SELECTED))
     {
       item->flags |= HOTLIST_G_IS_SELECTED;
-      number_selected++;
 
-      selected_parent = item->parent;
       last_selected_item = itemno;
     }
     hotlist_start_drag();
@@ -1783,30 +1810,33 @@ static _kernel_oserror * hotlist_process_click_on_item(unsigned int itemno,
     else
     {
       hotlist_clear_selection();
-      item->flags |= HOTLIST_G_IS_SELECTED;
-      selected_parent = item->parent;
-      number_selected++;
-      hotlist_redraw_items(itemno, itemno);
+      item->flags |= HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW;
+      if (item->type == hl_directory)
+      {
+        hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+      }
+      hotlist_redraw_now();
     }
     last_selected_item = itemno;
     break;
 
     case 256:                   /* Click adjust */
-    if (selected_parent != item->parent && item->type != hl_url) hotlist_clear_selection();
     item->flags ^= HOTLIST_G_IS_SELECTED;
-    if (item->flags & HOTLIST_G_IS_SELECTED)
-    {
-      number_selected++;
-    }
-    else
+    item->flags |= HOTLIST_G_REDRAW_NOW;
+    last_selected_item = itemno;
+    if (item->type == hl_directory)
     {
-      number_selected--;
+      if (item->flags & HOTLIST_G_IS_SELECTED)
+      {
+        hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+      }
+      else
+      {
+        hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+      }
     }
-    hotlist_redraw_items(itemno, itemno);
-    selected_parent = item->parent;
-    last_selected_item = itemno;
+    hotlist_redraw_now();
     break;
-
   }
 
   return NULL;
@@ -1998,10 +2028,10 @@ static int hotlist_mouse_click_handler(int event_code, WimpPollBlock *event, IdB
 static int hotlist_menuclose_handler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
 {
   ObjectId submenu_id;
-  if (number_selected == -1)
+  if (menu_select)
   {
     hotlist_clear_selection();
-    number_selected = 0;
+    menu_select = 0;
   }
   show_error(menu_get_sub_menu_show(0, id_block->self_id, HOTLIST_URL_MENUITEM, &submenu_id));
   if (submenu_id) show_error(toolbox_delete_object(0, submenu_id));
@@ -2017,7 +2047,7 @@ void hotlist_setmenu_details(ObjectId menuid)
   char entrytext[32];
   ObjectId submenu_id;
 
-  switch(number_selected)
+  switch(hotlist_count_selected_items())
   {
     case 0:
     menu_set_entry_text(0, menuid, HOTLIST_URL_MENUITEM, "URL ''");
@@ -2094,7 +2124,7 @@ static int hotlist_menuopen_handler(int event_code, ToolboxEvent * event, IdBloc
     menu_itemno = -pointerblock.y / item_height;
   }
 
-  if (number_selected == 0)
+  if (hotlist_count_selected_items() == 0)
   {
     item = hotlist_find_item(hotlist_root->data.directory_content, menu_itemno);
 
@@ -2106,8 +2136,7 @@ static int hotlist_menuopen_handler(int event_code, ToolboxEvent * event, IdBloc
     if (item && pointerblock.x >= xmin && pointerblock.x <= xmax)
     {
       item->flags |= HOTLIST_G_IS_SELECTED;
-      selected_parent = item->parent;
-      number_selected = -1;
+      menu_select = 1;
       hotlist_redraw_items(menu_itemno, menu_itemno);
     }
   }
@@ -2759,6 +2788,10 @@ _kernel_oserror * hotlist_initialise(void)
                                           HotlistNewRenameDirectoryCancel,
                                           hotlist_reset_directory_handler,
                                           NULL));
+
+hotlist_load("InetDBase:hotlist\n");
+hotlist_open(Toolbox_ShowObject_Default, 0, 0);
+
   return NULL;
 }
 
@@ -2827,11 +2860,10 @@ static int hotlist_menu_selectall_handler(int event_code, ToolboxEvent *event, I
   if (item && item->parent)
   {
     item = item->parent->data.directory_content;
-    number_selected = 0;
     while(item)
     {
       item->flags |= HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW;
-      number_selected++;
+      if (item->type == hl_directory) hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
       item = item->next;
     }
     hotlist_redraw_now();
@@ -2919,13 +2951,12 @@ static int hotlist_menu_delete_handler(int event_code, ToolboxEvent *event, IdBl
 
   noitems = hotlist_count_displayed_items(hotlist_root->data.directory_content);
 
-  if (!number_selected) return 0;
+  if (!hotlist_count_selected_items()) return 0;
 
   while((item = hotlist_find_selected_item())!=NULL)
   {
     hotlist_delete_item(item);
   }
-  number_selected = 0;
   hotlist_redraw_items(0, noitems);
   hotlist_window_preopen(already_open);
   toolbox_hide_object(0, id_block->ancestor_id);
@@ -3340,7 +3371,7 @@ static _kernel_oserror *_hotlist_start_drag(void)
 
   hotlist_get_shape(&xmin, &xmax, item);
   item = item->next;
-  if (number_selected > 1)
+  if (hotlist_count_selected_items() > 1)
   {
     while(item)
     {
@@ -3371,7 +3402,20 @@ static _kernel_oserror *_hotlist_start_drag(void)
 
   if (_kernel_osbyte(161, 28, 0) & (1<<(8+1))) /* solid drag */
   {
-    if (number_selected == 1)
+    item = hotlist_find_selected_item();
+
+    if (
+         (hotlist_count_selected_items() == 1 && item->type == hl_url) ||
+         (
+           hotlist_count_selected_items() == 1 &&
+           item->type == hl_directory &&
+           (
+             !(item->flags & HOTLIST_D_IS_OPEN) ||
+             hotlist_no_contents_selected(item->data.directory_content)   ||
+             item->data.directory_content == NULL
+           )
+         )
+       )
     {
       box.dragging_box.xmin = xmin-xorigin;                          /* box shape */
       box.dragging_box.ymin = bottom-yorigin;
@@ -3578,6 +3622,8 @@ static int hotlist_drag_completed_handler(int event_code, WimpPollBlock *event,
 
     /* Check to see if moving the selection to this position is acceptable -----------------------*/
 
+    /* This section is not sufficient for the new selection model ///////// */
+
     tempitem = sourceitem;
     while(tempitem)
     {
@@ -3604,8 +3650,12 @@ static int hotlist_drag_completed_handler(int event_code, WimpPollBlock *event,
     if (!shift)
     {
       /* Move selected items */
+
       hotlist_move_item(sourceitem, targetitem, position);                      /* Move first item to specified position */
                                                                                 /* before/after/in target                */
+
+      if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+
       targetitem = sourceitem;
 
       while((sourceitem = hotlist_find_selected_item()) != NULL)
@@ -3613,14 +3663,19 @@ static int hotlist_drag_completed_handler(int event_code, WimpPollBlock *event,
         sourceitem->flags &= ~HOTLIST_G_IS_SELECTED;
         hotlist_move_item(sourceitem, targetitem, HOTLIST_POSITION_AFTER);      /* Move all subsequent items to follow   */
                                                                                 /* first moved item                      */
+        if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
         targetitem = sourceitem;
       }
     }
     else
     {
       /* Copy selected items */
+
+
       hotlist_copy_item(sourceitem, targetitem, position, &targetitem);         /* Copy first item to specified position */
                                                                                 /* before/after/in target                */
+      if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+
       while((sourceitem = hotlist_find_selected_item()) != NULL)
       {
         sourceitem->flags &= ~HOTLIST_G_IS_SELECTED;
@@ -3628,12 +3683,10 @@ static int hotlist_drag_completed_handler(int event_code, WimpPollBlock *event,
                           targetitem,                                           /* first copied item                     */
                           HOTLIST_POSITION_AFTER,
                           &targetitem);
+        if (sourceitem->type == hl_directory) hotlist_clear_flags(sourceitem->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
       }
     }
 
-    number_selected = 0;
-    selected_parent = NULL;
-
     bottom2 = hotlist_count_displayed_items(hotlist_root->data.directory_content);
     if (bottom2 > bottom) bottom = bottom2;
     hotlist_redraw_items(top, bottom);
@@ -3840,6 +3893,16 @@ _kernel_oserror *hotlist_selection_box_start(void)
   return NULL;
 }
 
+/*************************************************/
+/* hotlist_null_drag_select_handler()            */
+/*                                               */
+/* This function is called as a null handler,    */
+/* it is responsible for selecting for selecting */
+/* and deselecting items within and outside of   */
+/* the rubber box drag started by                */
+/* hotlist_selection_box_start                   */
+/*************************************************/
+
 int hotlist_null_drag_select_handler(int event_code, WimpPollBlock *event, IdBlock *id_block, void *handle)
 {
   WimpGetPointerInfoBlock pointerblock;
@@ -3889,34 +3952,28 @@ int hotlist_null_drag_select_handler(int event_code, WimpPollBlock *event, IdBlo
       if (itemno >= item_min && itemno <= item_max)
       {
         hotlist_get_shape(&itemxmin, &itemxmax, item);
-        if (number_selected == 0)
+        if ((!(maxx < itemxmin || minx > itemxmax)))
         {
-          if (!(maxx < itemxmin || minx > itemxmax) && (!(item->flags & HOTLIST_G_IS_SELECTED)))
+          if (!(item->flags & HOTLIST_G_IS_SELECTED))
           {
             item->flags |= HOTLIST_G_IS_SELECTED;
             hotlist_redraw_items(itemno, itemno);
-            selected_parent = item->parent;
-            number_selected++;
+            if (item->type == hl_directory && !(item->flags & HOTLIST_D_IS_OPEN)) /* If directory is closed select everything in it */
+            {
+              hotlist_set_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED);
+              hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_REDRAW_NOW);
+            }
           }
         }
         else
         {
-          if (!(maxx < itemxmin || minx > itemxmax))
-          {
-            if ((selected_parent == item->parent || item->type == hl_url) && (!(item->flags & HOTLIST_G_IS_SELECTED)))
-            {
-              item->flags |= HOTLIST_G_IS_SELECTED;
-              hotlist_redraw_items(itemno, itemno);
-              number_selected++;
-            }
-          }
-          else
+          if (item->flags & HOTLIST_G_IS_SELECTED)
           {
-            if (item->flags & HOTLIST_G_IS_SELECTED)
+            item->flags &= ~HOTLIST_G_IS_SELECTED;
+            hotlist_redraw_items(itemno, itemno);
+            if (item->type == hl_directory && !(item->flags & HOTLIST_D_IS_OPEN)) /* If directory is closed unselect everything in it */
             {
-              item->flags &= ~HOTLIST_G_IS_SELECTED;
-              hotlist_redraw_items(itemno, itemno);
-              number_selected--;
+              hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW);
             }
           }
         }
@@ -3927,7 +3984,10 @@ int hotlist_null_drag_select_handler(int event_code, WimpPollBlock *event, IdBlo
         {
           item->flags &= ~HOTLIST_G_IS_SELECTED;
           hotlist_redraw_items(itemno, itemno);
-          number_selected--;
+          if (item->type == hl_directory && !(item->flags & HOTLIST_D_IS_OPEN)) /* If directory is closed unselect everything in it */
+          {
+            hotlist_clear_flags(item->data.directory_content, hl_ALL, HOTLIST_G_IS_SELECTED | HOTLIST_G_REDRAW_NOW);
+          }
         }
       }
     }
@@ -3935,3 +3995,102 @@ int hotlist_null_drag_select_handler(int event_code, WimpPollBlock *event, IdBlo
 
   return 0;
 }
+
+
+/*************************************************/
+/* _hotlist_count_selected_items()               */
+/*                                               */
+/* This routine does all the work for            */
+/* hotlist_count_selected_items()                */
+/*************************************************/
+
+static void _hotlist_count_selected_items(hotlist_item *list)
+{
+  while(list)
+  {
+    if (list->flags & HOTLIST_G_IS_SELECTED)
+    {
+      item_number++;
+    }
+    else /* Only recurse through directories which are not selected */
+    {
+      if (list->type == hl_directory)
+      {
+        _hotlist_count_selected_items(list->data.directory_content);
+      }
+    }
+    list = list->next;
+  }
+}
+
+/*************************************************/
+/* hotlist_count_selected_items()                */
+/*                                               */
+/* This routine counts the number of selected    */
+/* items                                         */
+/*                                               */
+/* Parameters: Pointer to a hotlist_item         */
+/*                                               */
+/* Returns:    the number of selected items      */
+/*************************************************/
+
+static unsigned int hotlist_count_selected_items(void)
+{
+  item_number = 0;
+  _hotlist_count_selected_items(hotlist_root->data.directory_content);
+  return item_number;
+}
+
+/*************************************************/
+/* hotlist_contents_selected()                   */
+/*                                               */
+/* Checks if all items and subdirectories are    */
+/* selected                                      */
+/*                                               */
+/* Parameters: Pointer to the first hotlist_item */
+/*             to check                          */
+/*                                               */
+/* Returns:    1 if all items are selected       */
+/*             0 if there are unselected items   */
+/*************************************************/
+
+static unsigned int hotlist_contents_selected(hotlist_item *item)
+{
+  while(item)
+  {
+    if (!item->flags & HOTLIST_G_IS_SELECTED) return 0;
+    if (item->type == hl_directory)
+    {
+      if (!hotlist_contents_selected(item->data.directory_content)) return 0;
+    }
+    item = item->next;
+  }
+  return 1;
+}
+
+/*************************************************/
+/* hotlist_no_contents_selected()                */
+/*                                               */
+/* Checks if all items and subdirectories are    */
+/* selected                                      */
+/*                                               */
+/* Parameters: Pointer to the first hotlist_item */
+/*             to check                          */
+/*                                               */
+/* Returns:    1 if all items are selected       */
+/*             0 if there are unselected items   */
+/*************************************************/
+
+static unsigned int hotlist_no_contents_selected(hotlist_item *item)
+{
+  while(item)
+  {
+    if (item->flags & HOTLIST_G_IS_SELECTED) return 0;
+    if (item->type == hl_directory)
+    {
+      if (!hotlist_no_contents_selected(item->data.directory_content)) return 0;
+    }
+    item = item->next;
+  }
+  return 1;
+}
-- 
GitLab