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, ¤t_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