1 
2 #include "studiox_includes.h"
3 #include "undo_manager.h"
4 
5 #ifdef _DEBUG
6 #define new DEBUG_NEW
7 #endif
8 
9 
10 ///////////////////////////////////////////////////////////////////////////////
undo_manager()11 undo_manager::undo_manager()
12 {
13     current = NULL;
14 
15     tail = undo_list;
16     tail += MAX_UNDO_ENTRIES - 1;
17     entries = 0;
18 
19     is_add_entry_locked = FALSE;
20 }
21 
22 ///////////////////////////////////////////////////////////////////////////////
~undo_manager()23 undo_manager::~undo_manager()
24 {
25     Reset();
26 }
27 
28 ///////////////////////////////////////////////////////////////////////////////
AddEntry(int type,folder_info * folder,int display_index)29 void undo_manager::AddEntry(int type, folder_info *folder, int display_index)
30 {
31     if (!folder || IsAddEntryLocked())
32     {
33         return;
34     }
35 
36     if (current)
37     {
38         current++;
39         if (current > tail)
40         {
41             current = undo_list;
42         }
43         if (entries < MAX_UNDO_ENTRIES)
44         {
45             entries++;
46         }
47     }
48     else
49     {
50         current = undo_list;
51         entries = 1;
52     }
53 
54     ClearUndoRecord(current);
55     current->type = type;
56 
57     undo_widget new_entry;
58 
59     switch (type)
60     {
61     case UNDO_TYPE_DELETE_FOLDER:
62     case UNDO_TYPE_INSERT_TOP_LEVEL_WIDGETS:
63         new_entry.folder = new folder_info(*folder);
64         break;
65 
66     case UNDO_TYPE_INSERT_FOLDER:
67         new_entry.folder_name = folder->folder_name;
68         break;
69     }
70 
71     new_entry.res_index = display_index;
72     current->widget_list.Add(new_entry);
73 }
74 
75 ///////////////////////////////////////////////////////////////////////////////
AddEntry(int type,widget_info * info,int res_index,BOOL fold)76 void undo_manager::AddEntry(int type, widget_info *info, int res_index, BOOL fold)
77 {
78     if (!info || !info->widget || IsAddEntryLocked())
79     {
80         return;
81     }
82 
83     if (current)
84     {
85         // in a few cases we don't need to make another entry
86         //   repeast position/size changes can be folded into one
87         //   repeated name changes are folded into one
88         //   repeated style changes are foled into one
89         switch(type)
90         {
91         case UNDO_TYPE_SIZE:
92         case UNDO_TYPE_POSITION:
93 
94             if (current->type == type && fold)
95             {
96                 if (current->widget_list[0].project_info == info)
97                 {
98                     // no need to make a new entry
99                     return;
100                 }
101             }
102             break;
103 
104         case UNDO_TYPE_STYLE:
105         case UNDO_TYPE_NAMES:
106         case UNDO_TYPE_USER_DATA:
107             if (current->type == type &&
108                 current->widget_list[0].project_info == info)
109             {
110                 // same widget getting name or style change, don't save new record
111                 return;
112             }
113             break;
114 
115         default:
116             break;
117         }
118         current++;
119         if (current > tail)
120         {
121             current = undo_list;
122         }
123         if (entries < MAX_UNDO_ENTRIES)
124         {
125             entries++;
126         }
127     }
128     else
129     {
130         current = undo_list;
131         entries = 1;
132     }
133 
134     ClearUndoRecord(current);
135     current->type = type;
136 
137     undo_widget new_entry;
138 
139     if (type == UNDO_TYPE_DELETE_WIDGET)
140     {
141         // copy the entire info tree, including children
142         new_entry.copy_info = new widget_info(*info);
143         new_entry.copy_info->widget = NULL;
144 
145         // When a widget is deleted, the corresponding widget_info is also deleted.
146         // So if we un-delete the widget, we need to fixup any undo_manager entries
147         // that are pointing at the old widget_info structures:
148         UpdateUndoRecordInfoPointers(new_entry.copy_info, info);
149     }
150     else
151     {
152         // copy just this one record
153         new_entry.copy_info = new widget_info(info->basetype);
154         *new_entry.copy_info = *info;
155         new_entry.copy_info->widget = NULL;
156     }
157 
158     if (info)
159     {
160         // save pointer to original widget_info
161         new_entry.project_info = info;
162     }
163     else
164     {
165         ErrorMsg("Internal Error: Invalid project information.");
166     }
167 
168     studiox_project *project = GetOpenProject();
169 
170     widget_info *parent_info = project->FindParentInfo(info);
171     if (parent_info)
172     {
173         new_entry.parent_info = parent_info;
174     }
175     else
176     {
177         new_entry.parent_info = NULL;
178 
179         if (project)
180         {
181             folder_info *folder = project->FindParentFolderInfo(info);
182 
183             if (folder)
184             {
185                 //new_entry.folder = folder;
186                 new_entry.folder_name = folder->folder_name;
187             }
188         }
189     }
190     new_entry.res_index = res_index;
191     current->widget_list.Add(new_entry);
192 }
193 
194 ///////////////////////////////////////////////////////////////////////////////
AddEntry(int type,CArray<WIDGET_SELECT_ENTRY> & widget_list,BOOL fold)195 void undo_manager::AddEntry(int type, CArray<WIDGET_SELECT_ENTRY> &widget_list, BOOL fold)
196 {
197     int widget_count;
198     int widget_index;
199     BOOL same_set = TRUE;
200 
201     if (IsAddEntryLocked())
202     {
203         return;
204     }
205 
206     if (current)
207     {
208         // see if we just need to update most recent undo entry
209 
210         if (current->type == type && fold &&
211             (type == UNDO_TYPE_POSITION || type == UNDO_TYPE_SIZE))
212         {
213             widget_count = current->widget_list.GetSize();
214             if (widget_count != widget_list.GetCount())
215             {
216                 same_set = FALSE;
217             }
218             else
219             {
220                 for (widget_index = 0; widget_index < widget_count; widget_index++)
221                 {
222                     if (current->widget_list[widget_index].project_info !=
223                         widget_list[widget_index].info)
224                     {
225                         same_set = FALSE;
226                         break;
227                     }
228                 }
229             }
230 
231             if (same_set)
232             {
233                 // same set of widgets being positioned, so no need to make new copy
234                 // of the widget info
235                 return;
236             }
237         }
238 
239         current++;
240         if (current > tail)
241         {
242             current = undo_list;
243         }
244         if (entries < MAX_UNDO_ENTRIES)
245         {
246             entries++;
247         }
248     }
249     else
250     {
251         current = undo_list;
252         entries = 1;
253     }
254 
255     ClearUndoRecord(current);
256     current->type = type;
257 
258     widget_count = widget_list.GetCount();
259     current->widget_list.SetSize(widget_count);
260 
261     for (widget_index = 0; widget_index < widget_count; widget_index++)
262     {
263         widget_info *info = widget_list[widget_index].info;
264 
265         current->widget_list[widget_index].project_info = info;
266         current->widget_list[widget_index].copy_info = new widget_info(info->basetype);
267         *current->widget_list[widget_index].copy_info = *info;
268         current->widget_list[widget_index].copy_info->widget = NULL;
269         current->widget_list[widget_index].parent_info = GetOpenProject()->FindParentInfo(info);
270         current->widget_list[widget_index].res_index = 0;
271     }
272 }
273 
274 ///////////////////////////////////////////////////////////////////////////////
275 /* Count how many nodes are in a widget_info tree.
276    This is done as part of UpdateUndoEntryInfoPointers()
277 */
278 
CountInfoNodes(widget_info * start,int count)279 int undo_manager::CountInfoNodes(widget_info *start, int count)
280 {
281     while(start)
282     {
283         count++;
284         if (start->GetChildWidgetInfo())
285         {
286             count += CountInfoNodes(start->GetChildWidgetInfo(), count);
287         }
288         start = start->GetNextWidgetInfo();
289     }
290     return count;
291 }
292 
293 ///////////////////////////////////////////////////////////////////////////////
294 /* Write an array of old_info and new_info pointers.
295    This is done as part of UpdateUndoEntryInfoPointers()
296 */
BuildInfoNodeArray(widget_info ** write,widget_info * new_tree,widget_info * old_tree)297 widget_info **undo_manager::BuildInfoNodeArray(widget_info **write, widget_info *new_tree, widget_info *old_tree)
298 {
299     while(new_tree)
300     {
301         *write++ = old_tree;
302         *write++ = new_tree;
303 
304         if (new_tree->GetChildWidgetInfo())
305         {
306             write = BuildInfoNodeArray(write, new_tree->GetChildWidgetInfo(), old_tree->GetChildWidgetInfo());
307         }
308         new_tree = new_tree->GetNextWidgetInfo();
309         old_tree = old_tree->GetNextWidgetInfo();
310     }
311     return write;
312 }
313 
314 ///////////////////////////////////////////////////////////////////////////////
315 /* Called by UpdateUndoEntryInfoPointers.
316    For each undo entry, go through the list of project_info pointers. If any
317    of them are in the node_list array, replace them with the new pointers.
318 */
SearchAndReplaceInfoPointers(undo_record * search,widget_info ** node_list,int node_list_size)319 void undo_manager::SearchAndReplaceInfoPointers(undo_record *search, widget_info **node_list, int node_list_size)
320 {
321     int widget_index;
322     int list_index;
323 
324     int rows = search->widget_list.GetCount();
325     widget_info *old_pointer;
326 
327     for (widget_index = 0; widget_index < rows; widget_index++)
328     {
329         old_pointer = search->widget_list[widget_index].project_info;
330 
331         for (list_index = 0; list_index < node_list_size * 2; list_index += 2)
332         {
333             if (node_list[list_index] == old_pointer)
334             {
335                 search->widget_list[widget_index].project_info = node_list[list_index + 1];
336                 break;
337             }
338         }
339     }
340 }
341 
342 ///////////////////////////////////////////////////////////////////////////////
343 /* If we Delete a widget, then undo the Delete, it's possible that the undo
344    list will hold records pointing at the old widget_info structure tree. So if
345    we un-delete a widget (tree), we need to update the undo list records to
346    convert the old project_info pointers to the new project_info pointers.
347 */
UpdateUndoRecordInfoPointers(widget_info * new_info,widget_info * old_info)348 void undo_manager::UpdateUndoRecordInfoPointers(widget_info *new_info, widget_info *old_info)
349 {
350     undo_record *search = current;
351     int rows = entries;
352 
353     int nodes = CountInfoNodes(new_info, 0);
354     widget_info **info_list = new widget_info*[nodes * 2];
355     BuildInfoNodeArray(info_list, new_info, old_info);
356 
357     while(rows--)
358     {
359         SearchAndReplaceInfoPointers(search, info_list, nodes);
360         search--;
361         if (search < undo_list)
362         {
363             search = tail;
364         }
365     }
366     delete [] info_list;
367 }
368 
369 ///////////////////////////////////////////////////////////////////////////////
Undo()370 void undo_manager::Undo()
371 {
372     int widget_list_size;
373     int widget_list_index;
374     int resource_index;
375     int display;
376     widget_service_provider *provider;
377     widget_info *current_info;
378     widget_info *parent_info;
379     GX_WIDGET *target;
380 
381     studiox_project *pProject = GetOpenProject();
382 
383     if (entries <= 0 || pProject == NULL)
384     {
385         return;
386     }
387 
388     LockAddEntry();
389 
390     undo_record *entry = current;
391     current--;
392     if (current < undo_list)
393     {
394         current = tail;
395     }
396     entries--;
397 
398     if (!entries)
399     {
400         current = NULL;
401     }
402 
403     widget_list_size = entry->widget_list.GetSize();
404 
405     if (widget_list_size)
406     {
407         if (entry->type == UNDO_TYPE_DELETE_WIDGET)
408         {
409             parent_info = entry->widget_list[0].parent_info;
410         }
411         else
412         {
413             parent_info = entry->widget_list[0].project_info;
414         }
415     }
416 
417     if (parent_info)
418     {
419          GetTargetScreen()->MakeTopWindowVisible(parent_info);
420     }
421 
422     switch(entry->type)
423     {
424     case UNDO_TYPE_POSITION:
425     case UNDO_TYPE_SIZE:
426         for (widget_list_index = 0; widget_list_index < widget_list_size; widget_list_index++)
427         {
428             widget_factory::MoveWidget(entry->widget_list[widget_list_index].project_info,
429                                        entry->widget_list[widget_list_index].copy_info->size);
430 
431             current_info = entry->widget_list[widget_list_index].project_info;
432             if (current_info)
433             {
434                 GetTargetScreen()->WidgetWasMoved(current_info);
435             }
436         }
437         GetPropsWin()->WidgetWasMoved();
438         break;
439 
440     case UNDO_TYPE_STYLE:
441         current_info = entry->widget_list[0].project_info;
442         target = current_info->widget;
443 
444         if (current_info)
445         {
446             current_info->style = entry->widget_list[0].copy_info->style;
447             if (target)
448             {
449                 gx_widget_style_set(target, current_info->style);
450             }
451             GetPropsWin()->WidgetWasModified(current_info);
452         }
453         break;
454 
455     case UNDO_TYPE_TEMPLATE:
456         current_info = entry->widget_list[0].project_info;
457         if (current_info)
458         {
459             current_info->is_template = entry->widget_list[0].copy_info->is_template;
460             GetPropsWin()->WidgetWasModified(current_info);
461         }
462         break;
463 
464     case UNDO_TYPE_SLIDER_INFO:
465         current_info = entry->widget_list[0].project_info;
466         target = current_info->widget;
467 
468         if (current_info)
469         {
470             current_info->ewi = entry->widget_list[0].copy_info->ewi;
471             current_info->misc_value = entry->widget_list[0].copy_info->misc_value;
472 
473             if (target)
474             {
475                 GX_SLIDER *slider = (GX_SLIDER *) target;
476                 if (current_info->basetype == GX_TYPE_SLIDER)
477                 {
478                     slider->gx_slider_tick_count = current_info->misc_value;
479                 }
480                 gx_slider_info_set(slider, &current_info->ewi.slider);
481             }
482             GetPropsWin()->WidgetWasModified(current_info);
483         }
484         break;
485 
486     case UNDO_TYPE_PROGRESS_BAR_INFO:
487         current_info = entry->widget_list[0].project_info;
488         if (current_info)
489         {
490             current_info->ewi = entry->widget_list[0].copy_info->ewi;
491             properties_win::AssignProgressBarInfo(current_info);
492             GetPropsWin()->WidgetWasModified(current_info);
493         }
494         break;
495 
496     case UNDO_TYPE_LIST_ROWS:
497         current_info = entry->widget_list[0].project_info;
498         if (current_info)
499         {
500             switch(current_info->basetype)
501             {
502             case GX_TYPE_VERTICAL_LIST:
503             case GX_TYPE_HORIZONTAL_LIST:
504                 current_info->ewi.vlist.total_rows = entry->widget_list[0].copy_info->ewi.vlist.total_rows;
505                 break;
506 
507             case GX_TYPE_DROP_LIST:
508                 current_info->ewi.drop_list.total_rows = entry->widget_list[0].copy_info->ewi.drop_list.total_rows;
509                 break;
510 
511             default:
512                 break;
513             }
514             GetPropsWin()->WidgetWasModified(current_info);
515         }
516         break;
517 
518     case UNDO_TYPE_OPEN_HEIGHT:
519         current_info = entry->widget_list[0].project_info;
520         if (current_info)
521         {
522             current_info->ewi.drop_list.open_height = entry->widget_list[0].copy_info->ewi.drop_list.open_height;
523             GetPropsWin()->WidgetWasModified(current_info);
524         }
525         break;
526 
527     case UNDO_TYPE_DYNAMIC_TEXT_BUFFER:
528         current_info = entry->widget_list[0].project_info;
529         if (current_info)
530         {
531             current_info->ewi.text_info.dynamic_buffer = entry->widget_list[0].copy_info->ewi.text_info.dynamic_buffer;
532             GetPropsWin()->WidgetWasModified(current_info);
533         }
534         break;
535 
536     case UNDO_TYPE_TEXT_VIEW_WHITESPACE:
537         current_info = entry->widget_list[0].project_info;
538         if (current_info)
539         {
540             current_info->ewi.text_info.whitespace = entry->widget_list[0].copy_info->ewi.text_info.whitespace;
541             GetPropsWin()->WidgetWasModified(current_info);
542         }
543         break;
544 
545     case UNDO_TYPE_TEXT_VIEW_LINE_SPACE:
546         current_info = entry->widget_list[0].project_info;
547         if (current_info)
548         {
549             current_info->ewi.text_info.line_space = entry->widget_list[0].copy_info->ewi.text_info.line_space;
550             GetPropsWin()->WidgetWasModified(current_info);
551         }
552         break;
553 
554     case UNDO_TYPE_TEXT_BUFFER_SIZE:
555         current_info = entry->widget_list[0].project_info;
556         if (current_info)
557         {
558             current_info->ewi.text_info.buffer_size = entry->widget_list[0].copy_info->ewi.text_info.buffer_size;
559             GetPropsWin()->WidgetWasModified(current_info);
560         }
561         break;
562 
563     case UNDO_TYPE_SCROLL_APPEARANCE:
564         current_info = entry->widget_list[0].project_info;
565         if (current_info)
566         {
567             GX_SCROLLBAR_APPEARANCE appearance = entry->widget_list[0].copy_info->ewi.scroll;
568             widget_factory::ReplaceScrollbar(current_info, &appearance);
569             GetPropsWin()->WidgetWasModified(current_info);
570          }
571          break;
572 
573     case UNDO_TYPE_SCROLL_STYLE:
574         current_info = entry->widget_list[0].project_info;
575         if (current_info)
576         {
577             GX_SCROLLBAR_APPEARANCE appearance = current_info->ewi.scroll;
578             current_info->style = entry->widget_list[0].copy_info->style;
579             widget_factory::ReplaceScrollbar(current_info, &appearance);
580             GetPropsWin()->WidgetWasModified(current_info);
581         }
582         break;
583 
584     case UNDO_TYPE_INSERT_WIDGET:
585         if (widget_list_size > 1)
586         {
587             GetTargetScreen()->DeSelect();
588         }
589 
590         for (widget_list_index = 0; widget_list_index < widget_list_size; widget_list_index++)
591         {
592             current_info = entry->widget_list[widget_list_index].project_info;
593             if (current_info)
594             {
595                 GetProjectView()->DeleteWidget(current_info);
596             }
597             else
598             {
599                 ErrorMsg("Internal Error: Invalid Undo information.");
600             }
601         }
602         break;
603 
604     case UNDO_TYPE_DELETE_WIDGET:
605         {
606         // re-insert the deleted widget
607         // copy the widget info structures
608         parent_info = entry->widget_list[0].parent_info;
609 
610         // select the parent widget so that we don't get
611         // an out-of-sync verification error:
612         GetTargetScreen()->SelectWidget(parent_info, TRUE, FALSE);
613 
614         widget_info *pTemp = entry->widget_list[0].copy_info;
615         entry->widget_list[0].copy_info = NULL;
616 
617         widget_info *search_start;
618         BOOL is_top_level_widget;
619 
620         if (parent_info == NULL)
621         {
622             search_start = NULL;
623             is_top_level_widget = TRUE;
624         }
625         else
626         {
627             search_start = GetProjectView()->FindTopLevelWidget(parent_info);
628             if (!search_start)
629             {
630                 break;
631             }
632             search_start = search_start->GetChildWidgetInfo();
633             is_top_level_widget = FALSE;
634         }
635 
636         widget_factory::CreateUniqueAppNames(pTemp, pTemp, search_start, is_top_level_widget);          // handy name passed to create
637 
638         // now make the widget visible:
639         if (parent_info)
640         {
641             pProject->AddWidgetToParent(parent_info, pTemp);
642         }
643         else
644         {
645             //selected parent folder in case paste wrong place.
646             GetProjectView()->FolderSelected(entry->widget_list[0].res_index, entry->widget_list[0].folder_name);
647 
648             folder_info *parent_folder = pProject->FindFolderInfo(entry->widget_list[0].res_index, entry->widget_list[0].folder_name);
649             pProject->AddWidgetToFolder(parent_folder, pTemp);
650         }
651 
652         if (!pTemp->id_name.IsEmpty())
653         {
654             display = pProject->GetDisplayIndex(pTemp);
655             pProject->AddToIdDictionary(display, ID_TYPE_WIDGET, pTemp->id_name);
656         }
657         GetProjectView()->CheckParentRefresh(parent_info);
658         }
659         break;
660 
661     case UNDO_TYPE_DELETE_FOLDER:
662         {
663             folder_info *folder = entry->widget_list[0].folder;
664             entry->widget_list[0].folder = NULL;
665 
666             project_view *pview = GetProjectView();
667 
668             if (pview)
669             {
670                 pview->SelectDisplay(entry->widget_list[0].res_index);
671                 pProject->AddFolderToDisplay(entry->widget_list[0].res_index, folder);
672                 //widget_factory::GenerateWidgets(NULL, folder->GetFirstChildWidget());
673                 pview->SelectDisplay(entry->widget_list[0].res_index);
674 
675                 if (folder->GetFirstChildWidget())
676                 {
677                     pview->WidgetSelected(folder->GetFirstChildWidget());
678                 }
679             }
680         }
681         break;
682 
683     case UNDO_TYPE_INSERT_FOLDER:
684         {
685              project_view *pview = GetProjectView();
686              if (pview)
687              {
688                  undo_widget *test = &(entry->widget_list[0]);
689                  folder_info *folder = pProject->FindFolderInfo(entry->widget_list[0].res_index, entry->widget_list[0].folder_name);
690 
691                  if (folder)
692                  {
693                      pview->DeleteFolder(folder);
694                  }
695              }
696         }
697         break;
698 
699     case UNDO_TYPE_INSERT_TOP_LEVEL_WIDGETS:
700         {
701             project_view *pview = GetProjectView();
702 
703             if (pview)
704             {
705                 folder_info *folder = entry->widget_list[0].folder;
706                 CArray<widget_info *> widget_list;
707                 folder_info *parent_folder = pProject->FindFolderInfo(entry->widget_list[0].res_index, folder->folder_name);
708                 widget_info *info = folder->GetFirstChildWidget();
709 
710                 pview->FolderSelected(parent_folder);
711 
712                 while (info)
713                 {
714                     widget_list.Add(info);
715                     info = info->GetNextWidgetInfo();
716                 }
717 
718                 for (int count = widget_list.GetCount() - 1; count >= 0; count--)
719                 {
720                     info = widget_list.GetAt(count);
721                     info = pProject->FindWidgetInfo(parent_folder, info->app_name, FALSE);
722                     pview->DeleteWidget(info);
723                 }
724             }
725         }
726         break;
727 
728     case UNDO_TYPE_COLOR:
729         current_info = entry->widget_list[0].project_info;
730         resource_index = entry->widget_list[0].res_index;
731         provider = widget_factory::GetServiceProvider(current_info->basetype);
732 
733         if (provider && current_info)
734         {
735             provider->AssignColor(current_info,
736                 resource_index,
737                 entry->widget_list[0].copy_info->color_id[resource_index]);
738         }
739         GetPropsWin()->WidgetWasModified(current_info);
740         break;
741 
742     case UNDO_TYPE_FONT:
743         current_info = entry->widget_list[0].project_info;
744         resource_index = entry->widget_list[0].res_index;
745         provider = widget_factory::GetServiceProvider(current_info->basetype);
746 
747         if (provider && current_info)
748         {
749             provider->AssignFont(current_info,
750                 resource_index, entry->widget_list[0].copy_info->font_id[resource_index]);
751         }
752         GetPropsWin()->WidgetWasModified(current_info);
753         break;
754 
755     case UNDO_TYPE_PIXELMAP:
756         current_info = entry->widget_list[0].project_info;
757         resource_index = entry->widget_list[0].res_index;
758         provider = widget_factory::GetServiceProvider(current_info->basetype);
759 
760         if (provider && current_info)
761         {
762             provider->AssignPixelmap(current_info,
763                 resource_index,
764                 entry->widget_list[0].copy_info->pixelmap_id[resource_index]);
765         }
766         GetPropsWin()->WidgetWasModified(current_info);
767         break;
768 
769     case UNDO_TYPE_STRING:
770         current_info = entry->widget_list[0].project_info;
771         resource_index = entry->widget_list[0].res_index;
772         display = GetProjectView()->GetActiveDisplay();
773 
774         provider = widget_factory::GetServiceProvider(current_info->basetype);
775 
776         if (display >= 0 && current_info && provider)
777         {
778             provider->AssignText(current_info, 0,
779                 entry->widget_list[0].copy_info->string_id[resource_index]);
780             GetPropsWin()->WidgetWasModified(current_info);
781         }
782         break;
783 
784     case UNDO_TYPE_NAMES:
785         current_info = entry->widget_list[0].project_info;
786 
787         if (current_info)
788         {
789             current_info->app_name = entry->widget_list[0].copy_info->app_name;
790             current_info->callback_func = entry->widget_list[0].copy_info->callback_func;
791 
792             if (current_info->id_name != entry->widget_list[0].copy_info->id_name)
793             {
794                 display = pProject->GetDisplayIndex(current_info);
795 
796                 if (!current_info->id_name.IsEmpty() &&
797                     pProject->mDisplays[display].screenflow)
798                 {
799                     pProject->mDisplays[display].screenflow->UpdateIdName(current_info, current_info->id_name, entry->widget_list[0].copy_info->id_name);
800                 }
801                 current_info->id_name = entry->widget_list[0].copy_info->id_name;
802             }
803             current_info->event_func = entry->widget_list[0].copy_info->event_func;
804             current_info->draw_func = entry->widget_list[0].copy_info->draw_func;
805             GetPropsWin()->WidgetWasModified(current_info);
806         }
807         break;
808 
809     case UNDO_TYPE_USER_DATA:
810         current_info = entry->widget_list[0].project_info;
811 
812         if (current_info)
813         {
814             current_info->user_data = entry->widget_list[0].copy_info->user_data;
815             GetPropsWin()->WidgetWasModified(current_info);
816         }
817         break;
818 
819     case UNDO_TYPE_FOCUS:
820         current_info = entry->widget_list[0].project_info;
821         if (current_info)
822         {
823             current_info->accepts_focus = entry->widget_list[0].copy_info->accepts_focus;
824             GetPropsWin()->WidgetWasModified(current_info);
825         }
826         break;
827 
828     case UNDO_TYPE_CIRCULAR_GAUGE_INFO:
829         current_info = entry->widget_list[0].project_info;
830         if (current_info)
831         {
832             current_info->ewi.gauge.info = entry->widget_list[0].copy_info->ewi.gauge.info;
833             current_info->ewi.gauge.start_angle = entry->widget_list[0].copy_info->ewi.gauge.start_angle;
834 
835             if (current_info->widget)
836             {
837                 GX_CIRCULAR_GAUGE *gauge = (GX_CIRCULAR_GAUGE *) current_info->widget;
838                 gauge->gx_circular_gauge_info = current_info->ewi.gauge.info;
839             }
840             GetPropsWin()->WidgetWasModified(current_info);
841         }
842         break;
843 
844     case UNDO_TYPE_CHART_INFO:
845         current_info = entry->widget_list[0].project_info;
846 
847         if (current_info)
848         {
849             current_info->ewi.line_chart_info = entry->widget_list[0].copy_info->ewi.line_chart_info;
850 
851             if (current_info->widget)
852             {
853                 GX_LINE_CHART *chart = (GX_LINE_CHART *) current_info->widget;
854                 chart->gx_line_chart_info = current_info->ewi.line_chart_info;
855             }
856             GetPropsWin()->WidgetWasModified(current_info);
857         }
858         break;
859 
860     case UNDO_TYPE_NUMERIC_PROMPT_INFO:
861         current_info = entry->widget_list[0].project_info;
862         if (current_info)
863         {
864             provider = widget_factory::GetServiceProvider(current_info->basetype);
865 
866             ((prompt_service_provider *)provider)->AssignNumericValue(current_info,
867                 entry->widget_list[0].copy_info->ewi.numeric_prompt_value);
868 
869             current_info->ewi.numeric_prompt_value = entry->widget_list[0].copy_info->ewi.numeric_prompt_value;
870             current_info->format_func = entry->widget_list[0].copy_info->format_func;
871             GetPropsWin()->WidgetWasModified(current_info);
872         }
873         break;
874 
875     case UNDO_TYPE_SCROLL_WHEEL_INFO:
876         current_info = entry->widget_list[0].project_info;
877 
878         if (current_info)
879         {
880             scroll_wheel_service_provider *provider = (scroll_wheel_service_provider *)widget_factory::GetServiceProvider(current_info->basetype);
881             if (provider)
882             {
883                 provider->AssignScrollWheelInfo(current_info, &entry->widget_list[0].copy_info->ewi.scroll_wheel);
884             }
885             GetPropsWin()->WidgetWasModified(current_info);
886         }
887         break;
888 
889     case UNDO_TYPE_TEXT_SCROLL_WHEEL_INFO:
890         current_info = entry->widget_list[0].project_info;
891 
892         if (current_info)
893         {
894             int normal_font = entry->widget_list[0].copy_info->font_id[NORMAL_FONT_INDEX];
895             int selected_font = entry->widget_list[0].copy_info->font_id[SELECTED_FONT_INDEX];
896             current_info->font_id[NORMAL_FONT_INDEX] = normal_font;
897             current_info->font_id[SELECTED_FONT_INDEX] = selected_font;
898 
899             text_scroll_wheel_service_provider *provider = (text_scroll_wheel_service_provider *)widget_factory::GetServiceProvider(current_info->basetype);
900 
901             if (provider)
902             {
903                 provider->AssignFont(current_info, NORMAL_FONT_INDEX, normal_font);
904                 provider->AssignFont(current_info, SELECTED_FONT_INDEX, selected_font);
905             }
906 
907             GetPropsWin()->WidgetWasModified(current_info);
908         }
909         break;
910 
911     case UNDO_TYPE_STRING_SCROLL_WHEEL_INFO:
912         current_info = entry->widget_list[0].project_info;
913         if (current_info)
914         {
915             string_scroll_wheel_service_provider *provider = (string_scroll_wheel_service_provider *)widget_factory::GetServiceProvider(current_info->basetype);
916 
917             if (provider)
918             {
919                 widget_info *entry_info = entry->widget_list[0].copy_info;
920                 current_info->callback_func = entry_info->callback_func;
921 
922                 CArray<GX_RESOURCE_ID> list_array;
923                 provider->InitStringIdListArray(entry_info->ewi.string_scroll_wheel.string_id_list, entry_info->ewi.string_scroll_wheel.base.total_rows, list_array);
924                 if (current_info->ewi.string_scroll_wheel.string_id_list)
925                 {
926                     delete current_info->ewi.string_scroll_wheel.string_id_list;
927                     current_info->ewi.string_scroll_wheel.string_id_list = NULL;
928                 }
929                 provider->CreateStringIdList(current_info, list_array);
930             }
931             GetPropsWin()->WidgetWasModified(current_info);
932         }
933         break;
934 
935     case UNDO_TYPE_NUMRIC_SCROLL_WHEEL_INFO:
936         current_info = entry->widget_list[0].project_info;
937 
938         if (current_info)
939         {
940             numeric_scroll_wheel_info *wheel_info = &entry->widget_list[0].copy_info->ewi.numeric_scroll_wheel;
941             current_info->ewi.numeric_scroll_wheel = *wheel_info;
942 
943             numeric_scroll_wheel_service_provider *provider = (numeric_scroll_wheel_service_provider *)widget_factory::GetServiceProvider(current_info->basetype);
944             target = current_info->widget;
945 
946             if (provider)
947             {
948                 provider->AssignScrollWheelInfo(current_info, &wheel_info->base);
949                 provider->AssignValueRange(current_info, wheel_info->start_val, wheel_info->end_val);
950                 GetPropsWin()->WidgetWasModified(current_info);
951             }
952         }
953         break;
954 
955     case UNDO_TYPE_MENU_INFO:
956         current_info = entry->widget_list[0].project_info;
957 
958         if (current_info)
959         {
960             widget_info *copy = entry->widget_list[0].copy_info;
961             target = current_info->widget;
962             provider = widget_factory::GetServiceProvider(current_info->basetype);
963 
964             ((menu_service_provider *)provider)->AssignTextOffset(current_info,
965                 copy->ewi.menu.text_x_offset, copy->ewi.menu.text_y_offset);
966             ((menu_service_provider *)provider)->AssignStyle(current_info, copy->style);
967             current_info->ewi.menu.insert_as_menu_item = copy->ewi.menu.insert_as_menu_item;
968             GetPropsWin()->WidgetWasModified(current_info);
969         }
970         break;
971 
972     case UNDO_TYPE_TREE_VIEW_INFO:
973         current_info = entry->widget_list[0].project_info;
974         target = current_info->widget;
975 
976         if (current_info)
977         {
978             current_info->ewi.tree_view_indentation = entry->widget_list[0].copy_info->ewi.tree_view_indentation;
979             if (target)
980             {
981                 gx_tree_view_indentation_set((GX_TREE_VIEW *)target, current_info->ewi.tree_view_indentation);
982             }
983             GetPropsWin()->WidgetWasModified(current_info);
984         }
985         break;
986 
987     case UNDO_TYPE_VISIBLE_AT_STARTUP:
988         current_info = entry->widget_list[0].project_info;
989         if (current_info)
990         {
991             current_info->visible_at_startup = entry->widget_list[0].copy_info->visible_at_startup;
992             GetPropsWin()->WidgetWasModified(current_info);
993         }
994         break;
995 
996     case UNDO_TYPE_RADIAL_SLIDER_INFO:
997         current_info = entry->widget_list[0].project_info;
998 
999         if (current_info)
1000         {
1001             provider = widget_factory::GetServiceProvider(current_info->basetype);
1002             ((radial_slider_service_provider *)provider)->SetRadialSliderInfo(current_info, &entry->widget_list[0].copy_info->ewi.radial_slider);
1003             GetPropsWin()->WidgetWasModified(current_info);
1004         }
1005         break;
1006 
1007     default:
1008         break;
1009     }
1010     ClearUndoRecord(entry);
1011     FreeAddEntry();
1012 }
1013 
1014 ///////////////////////////////////////////////////////////////////////////////
ClearUndoRecord(undo_record * record)1015 void undo_manager::ClearUndoRecord(undo_record *record)
1016 {
1017     // delete the copied widget_info structures associate with this undo record:
1018     int widget_list_size = record->widget_list.GetSize();
1019     int widget_list_index;
1020 
1021     for (widget_list_index = 0; widget_list_index < widget_list_size; widget_list_index++)
1022     {
1023         switch (record->type)
1024         {
1025         case UNDO_TYPE_INSERT_FOLDER:
1026         case UNDO_TYPE_INSERT_TOP_LEVEL_WIDGETS:
1027         case UNDO_TYPE_DELETE_FOLDER:
1028             if (record->widget_list[widget_list_index].folder)
1029             {
1030                 delete record->widget_list[widget_list_index].folder;
1031                 record->widget_list[widget_list_index].folder = NULL;
1032             }
1033             break;
1034 
1035         default:
1036             if (record->widget_list[widget_list_index].copy_info)
1037             {
1038                 delete record->widget_list[widget_list_index].copy_info;
1039                 record->widget_list[widget_list_index].copy_info = NULL;
1040             }
1041             break;
1042         }
1043     }
1044 
1045     // now empty out the undo record widget list array
1046     record->widget_list.RemoveAll();
1047     record->type = 0;
1048 }
1049 
1050 ///////////////////////////////////////////////////////////////////////////////
Reset()1051 void undo_manager::Reset()
1052 {
1053     while(entries)
1054     {
1055         undo_record *entry = current;
1056         current--;
1057         if (current < undo_list)
1058         {
1059             current = tail;
1060         }
1061         ClearUndoRecord(entry);
1062         entries--;
1063     }
1064     current = NULL;
1065 }
1066 
1067