123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- MODULE StartMenu;
- IMPORT
- Strings, XML, KernelLog, Modules, Inputs, UTF8Strings, XMLObjects,
- MainMenu, WM := WMWindowManager, WMComponents, WMStandardComponents, WMProperties, WMMessages, WMEvents,
- WMRectangles;
- CONST
- DefaultPlugin = "BlockStartMenu";
- FancyMenuDesc = "Dummy.XML";
- MaxMenus = 16;
- MaxMenuButtons = 10;
- TYPE
- String = Strings.String;
- EventListenerInfo = WMEvents.EventListenerInfo;
- Message = WMMessages.Message;
- Popup = OBJECT (WMComponents.FormWindow)
- PROCEDURE FocusLost*;
- BEGIN manager.Remove(SELF) END FocusLost;
- PROCEDURE FocusGot*;
- BEGIN manager.SetFocus(SELF) END FocusGot;
- PROCEDURE Handle*(VAR msg : Message);
- BEGIN
- Handle^(msg);
- IF (msg.msgType = WMMessages.MsgExt) & (msg.ext = closePopupMsg) THEN FocusLost END;
- END Handle;
- END Popup;
- ClosePopupMsg = OBJECT
- END ClosePopupMsg;
- PluginManager = OBJECT
- VAR
- plugin : Plugin;
- currentPluginName : Strings.String; (* { currentPluginName # NIL } *)
- factory : PluginFactory;
- startIndex : LONGINT;
- PROCEDURE & New*;
- BEGIN
- NEW(factory);
- currentPluginName := NIL;
- SetPlugin(Strings.NewString(DefaultPlugin));
- startIndex := 0;
- END New;
- PROCEDURE Refresh;
- BEGIN {EXCLUSIVE}
- IF manager = NIL THEN manager := WM.GetDefaultManager() END;
- SetPlugin(pluginName.Get());
- END Refresh;
- PROCEDURE SetPlugin(name : String);
- BEGIN
- IF plugin # NIL THEN
- plugin.Close;
- END;
- IF (name # NIL) & ((currentPluginName=NIL) OR (name^ # currentPluginName^)) THEN
- currentPluginName := name;
- plugin := factory.Get(name);
- startIndex := 0;
- END;
- IF plugin # NIL THEN
- plugin.Open
- END
- END SetPlugin;
- PROCEDURE Close;
- BEGIN
- IF plugin # NIL THEN plugin.Close END
- END Close;
- PROCEDURE ShiftMenuItems(upwards : BOOLEAN);
- BEGIN
- plugin.ReopenMenuItemsShifted(upwards)
- END ShiftMenuItems;
- END PluginManager;
- PluginFactory = OBJECT
- PROCEDURE Get(type : String) : Plugin;
- VAR a : ANY;
- BEGIN
- IF type^ = "FancyStartMenu" THEN
- a := GenFancyStartMenu(); RETURN a(Plugin)
- ELSIF type^ = "BlockStartMenu" THEN
- a := GenBlockStartMenu(); RETURN a(Plugin)
- ELSE (* return default *)
- a := GenBlockStartMenu(); RETURN a(Plugin)
- END
- END Get;
- END PluginFactory;
- Plugin = OBJECT
- PROCEDURE Open;
- BEGIN HALT(311) END Open;
- PROCEDURE Close;
- BEGIN HALT(311) END Close;
- PROCEDURE ReopenMenuItemsShifted(upwards : BOOLEAN);
- BEGIN HALT(311) END ReopenMenuItemsShifted;
- END Plugin;
- SubMenuOpener* = OBJECT(WMComponents.Component)
- VAR filename : WMProperties.StringProperty;
- eRun* : EventListenerInfo;
- PROCEDURE &Init*;
- BEGIN
- Init^;
- NEW(filename, NIL, Strings.NewString("Filename"), Strings.NewString("")); properties.Add(filename);
- NEW(eRun, Strings.NewString("Run"), Strings.NewString(""), SELF.Run); eventListeners.Add(eRun);
- END Init;
- PROCEDURE Run*(sender, par : ANY); (** Eventhandler *)
- VAR x, y : LONGINT; filename : String;
- rect : WMRectangles.Rectangle;
- BEGIN
- (* synchronize if not synchronized *)
- IF ~IsCallFromSequencer() THEN sequencer.ScheduleEvent(SELF.Run, sender, par)
- ELSE
- (* actual business logic *)
- filename := SELF.filename.Get();
- IF filename # NIL THEN
- rect := sender(WMComponents.VisualComponent).bounds.Get();
- sender(WMComponents.VisualComponent).ToWMCoordinates(0, 0, x, y);
- OpenPopup(x, y, filename^);
- END
- END
- END Run;
- END SubMenuOpener;
- MenuButtons = ARRAY MaxMenuButtons OF WMStandardComponents.Button;
- SMOArr = ARRAY MaxMenuButtons OF SubMenuOpener;
- FancyStartMenu = OBJECT(Plugin)
- VAR startMenu : WMComponents.FormWindow;
- nofLayouts, nofButtons, nofSMOs : LONGINT;
- menuButtons : MenuButtons;
- smos : SMOArr;
- PROCEDURE CountLayouts() : LONGINT;
- VAR i, n : LONGINT; done : BOOLEAN; s : Strings.String;
- BEGIN
- n := 0; done := FALSE;
- WHILE (i < LEN(layoutNames) - 1) & ~done DO
- s := layoutNames[i].Get();
- IF UTF8Strings.Compare(s^, FancyMenuDesc) # UTF8Strings.CmpEqual THEN
- INC(n)
- ELSE
- done := TRUE
- END;
- INC(i)
- END;
- RETURN n
- END CountLayouts;
- PROCEDURE FindSMO(c : XML.Content; VAR smo : SubMenuOpener);
- VAR enum : XMLObjects.Enumerator; found : BOOLEAN; ptr : ANY;
- BEGIN
- smo := NIL;
- IF c IS WMComponents.VisualComponent THEN
- enum := c(WMComponents.VisualComponent).GetContents();
- found := FALSE;
- WHILE enum.HasMoreElements() & ~found DO
- ptr := enum.GetNext();
- IF ptr IS SubMenuOpener THEN
- smo := ptr(SubMenuOpener);
- found := TRUE
- END
- END
- END;
- END FindSMO;
- PROCEDURE FindMenuButtonsSMO(c : XML.Content; VAR menuButtons : MenuButtons; VAR smos: SMOArr; VAR n, m : LONGINT);
- VAR enum : XMLObjects.Enumerator; i, j : LONGINT; ptr : ANY; s : Strings.String;
- b : WMStandardComponents.Button; smo : SubMenuOpener;
- BEGIN
- IF c IS WMComponents.VisualComponent THEN
- enum := c(WMComponents.VisualComponent).GetContents();
- i := 0; j := 0;
- WHILE enum.HasMoreElements() DO
- ptr := enum.GetNext();
- IF ptr IS WMStandardComponents.Button THEN
- b := ptr(WMStandardComponents.Button);
- s := b.caption.Get();
- IF (s # NIL) & (UTF8Strings.Compare(s^, "") # UTF8Strings.CmpEqual) THEN
- menuButtons[i] := b; INC(i);
- FindSMO(b, smo);
- IF smo # NIL THEN smos[j] := smo; INC(j) END;
- END;
- END;
- END;
- n := i; m := j
- ELSE
- n := 0; m := 0;
- END;
- END FindMenuButtonsSMO;
- PROCEDURE Open;
- VAR c : XML.Content; width, height : LONGINT; view : WM.ViewPort; s : String;
- BEGIN
- nofLayouts := CountLayouts();
- s := layoutNames[pm.startIndex].Get();
- KernelLog.String("loading "); KernelLog.String(s^); KernelLog.Ln;
- c := WMComponents.Load(s^);
- IF (c # NIL) & (c IS WMComponents.VisualComponent) THEN
- FindMenuButtonsSMO(c, menuButtons, smos, nofButtons, nofSMOs);
- width := c(WMComponents.VisualComponent).bounds.GetWidth();
- height := c(WMComponents.VisualComponent).bounds.GetHeight();
- NEW(startMenu, width, height, TRUE);
- startMenu.SetTitle(Strings.NewString("StartMenu"));
- startMenu.pointerThreshold := 10;
- startMenu.DisableUpdate;
- startMenu.SetContent(c);
- startMenu.EnableUpdate;
- startMenu.Invalidate(startMenu.bounds);
- view := WM.GetDefaultView();
- manager := WM.GetDefaultManager();
- manager.Add(ENTIER(view.range.l), ENTIER(view.range.b) - height + 1, startMenu, {WM.FlagHidden});
- ELSE
- KernelLog.String("XML-file not correctly loaded"); KernelLog.Ln
- END
- END Open;
- PROCEDURE Close;
- BEGIN {EXCLUSIVE}
- IF startMenu # NIL THEN startMenu.Close END
- END Close;
- PROCEDURE ReplaceMenuButtonsSMO(CONST mb, newmb : MenuButtons; CONST smos, newsmos : SMOArr);
- VAR i : LONGINT; s : Strings.String;
- BEGIN
- FOR i := 0 TO nofButtons - 1 DO
- s := newmb[i].caption.Get();
- mb[i].caption.Set(s);
- s := newsmos[i].filename.Get();
- smos[i].filename.Set(s);
- END;
- END ReplaceMenuButtonsSMO;
- PROCEDURE ReopenMenuItemsShifted(upwards : BOOLEAN);
- VAR old, i : LONGINT; s : String; c : XML.Content;
- newMButtons : MenuButtons;
- newsmos : SMOArr;
- n, m : LONGINT;
- BEGIN
- old := pm.startIndex;
- IF upwards THEN
- pm.startIndex := (pm.startIndex + 1) MOD nofLayouts
- ELSE
- pm.startIndex := (pm.startIndex - 1) MOD nofLayouts
- END;
- IF old # pm.startIndex THEN
- s := layoutNames[pm.startIndex].Get();
- c := WMComponents.Load(s^);
- IF (c # NIL) & (c IS WMComponents.VisualComponent) THEN
- FindMenuButtonsSMO(c, newMButtons, newsmos, n, m);
- IF (nofButtons = nofSMOs) & (nofButtons = n) & (nofSMOs = m) THEN
- ReplaceMenuButtonsSMO(menuButtons, newMButtons, smos, newsmos);
- FOR i := 0 TO nofButtons - 1 DO
- menuButtons[i].Invalidate;
- END;
- ELSE
- KernelLog.String("layout "); KernelLog.String(s^); KernelLog.String(" does not match."); KernelLog.Ln
- END
- ELSE
- KernelLog.String("XML-file not correctly loaded"); KernelLog.Ln
- END
- END
- END ReopenMenuItemsShifted;
- END FancyStartMenu;
- BlockStartMenu = OBJECT(Plugin)
- VAR startMenu : MainMenu.Window;
- PROCEDURE Open;
- BEGIN
- NEW(startMenu);
- startMenu.SetOriginator(NIL); (* includes page loading *)
- END Open;
- PROCEDURE Close;
- BEGIN
- IF startMenu # NIL THEN startMenu.Close END
- END Close;
- PROCEDURE ReopenMenuItemsShifted(upwards : BOOLEAN);
- END ReopenMenuItemsShifted;
- END BlockStartMenu;
- (* the starter decouples the sensitive callback from the WindowManager. *)
- Starter = OBJECT
- VAR originator : ANY;
- PROCEDURE &Init*(o : ANY);
- BEGIN
- originator := o
- END Init;
- BEGIN {ACTIVE}
- pm.Refresh
- END Starter;
- VAR
- stringPrototype, pluginName : WMProperties.StringProperty;
- layoutNames : ARRAY MaxMenus OF WMProperties.StringProperty;
- manager : WM.WindowManager;
- pm : PluginManager;
- p : Popup;
- closePopupMsg : ClosePopupMsg;
- PROCEDURE OpenPopup*(x, y : LONGINT; CONST filename : ARRAY OF CHAR);
- VAR m : WM.WindowManager;
- c : XML.Content;
- width, height : LONGINT;
- BEGIN
- c := WMComponents.Load(filename);
- IF (c # NIL) & (c IS WMComponents.VisualComponent) THEN
- width := c(WMComponents.VisualComponent).bounds.GetWidth();
- height := c(WMComponents.VisualComponent).bounds.GetHeight();
- IF width <= 0 THEN width := 10 END; IF height <= 0 THEN height := 10 END;
- NEW(p, width, height, TRUE);
- p.SetContent(c);
- m := WM.GetDefaultManager(); m.Add(x, y-height, p, {WM.FlagHidden}); m.SetFocus(p)
- ELSE
- KernelLog.String(filename); KernelLog.String(" not correctly loaded"); KernelLog.Ln
- END
- END OpenPopup;
- PROCEDURE ClosePopup*;
- VAR msg : WMMessages.Message; manager : WM.WindowManager;
- BEGIN
- msg.msgType := WMMessages.MsgExt; msg.ext := closePopupMsg;
- manager := WM.GetDefaultManager();
- manager.Broadcast(msg);
- END ClosePopup;
- PROCEDURE GenSubMenuOpener*() : XML.Element;
- VAR smo : SubMenuOpener;
- BEGIN
- NEW(smo); RETURN smo
- END GenSubMenuOpener;
- PROCEDURE Open*;
- BEGIN
- pm.SetPlugin(pluginName.Get());
- END Open;
- (* load start menu with buttons shifted to the right *)
- PROCEDURE ShiftMenuItemsRight*;
- BEGIN
- pm.ShiftMenuItems(TRUE);
- END ShiftMenuItemsRight;
- (* load start menu with buttons shifted to the left *)
- PROCEDURE ShiftMenuItemsLeft*;
- BEGIN
- pm.ShiftMenuItems(FALSE);
- END ShiftMenuItemsLeft;
- (* This procedure is directly called by the window manager. It must be safe. *)
- PROCEDURE MessagePreview(VAR m : WMMessages.Message; VAR discard : BOOLEAN);
- VAR starter : Starter;
- BEGIN
- IF m.msgType = WMMessages.MsgKey THEN
- IF (m.y = 0FF1BH) & ((m.flags * Inputs.Ctrl # {}) OR (m.flags * Inputs.Meta # {})) THEN
- NEW(starter, m.originator); discard := TRUE
- END;
- ELSIF (m.msgType = WMMessages.MsgExt) & (m.ext = WMComponents.componentStyleMsg) THEN
- NEW(starter, m.originator);
- END
- END MessagePreview;
- PROCEDURE GenFancyStartMenu() : Plugin;
- VAR menu : FancyStartMenu;
- BEGIN NEW(menu); RETURN menu
- END GenFancyStartMenu;
- PROCEDURE GenBlockStartMenu() : Plugin;
- VAR menu : BlockStartMenu;
- BEGIN NEW(menu); RETURN menu
- END GenBlockStartMenu;
- PROCEDURE InitPrototypes;
- VAR plStartMenu : WMProperties.PropertyList;
- s0, s1 : ARRAY 128 OF CHAR;
- i : LONGINT;
- BEGIN
- NEW(plStartMenu); WMComponents.propertyListList.Add("StartMenu", plStartMenu);
- NEW(stringPrototype, NIL, Strings.NewString("Plugin"), Strings.NewString("Plug-in-object that creates start-menu and determines its properties"));
- stringPrototype.Set(Strings.NewString(DefaultPlugin));
- NEW(pluginName, stringPrototype, NIL, NIL); plStartMenu.Add(pluginName);
- FOR i := 0 TO LEN(layoutNames) - 1 DO
- Strings.IntToStr(i, s0);
- COPY("Layout", s1);
- Strings.Append(s1, s0);
- NEW(stringPrototype, NIL, Strings.NewString(s1), Strings.NewString("XML-file that determins content and layout of the fancy start-menu"));
- stringPrototype.Set(Strings.NewString(FancyMenuDesc));
- NEW(layoutNames[i], stringPrototype, NIL, NIL); plStartMenu.Add(layoutNames[i]);
- END;
- END InitPrototypes;
- PROCEDURE Cleanup;
- BEGIN
- IF pm # NIL THEN pm.Close END;
- manager.RemoveMessagePreview(MessagePreview)
- END Cleanup;
- PROCEDURE Fancy*;
- BEGIN
- pluginName.Set(Strings.NewString("FancyStartMenu"));
- END Fancy;
- PROCEDURE Block*;
- BEGIN
- pluginName.Set(Strings.NewString("BlockStartMenu"));
- END Block;
- BEGIN
- NEW(pm);
- NEW(closePopupMsg);
- InitPrototypes;
- Modules.InstallTermHandler(Cleanup);
- manager := WM.GetDefaultManager();
- manager.InstallMessagePreview(MessagePreview);
- END StartMenu.
|